429 lines
14 KiB
PHP
Executable File
429 lines
14 KiB
PHP
Executable File
<?php
|
|
|
|
class FraudCore {
|
|
|
|
public $order;
|
|
public $cart;
|
|
public $customer;
|
|
|
|
private $fraud_score = 0;
|
|
private $fraud_report = array();
|
|
private $delivery_country;
|
|
private $invoice_country;
|
|
|
|
public function __construct(Order $order) {
|
|
if( !Validate::isLoadedObject($order) ) {
|
|
return false;
|
|
} else {
|
|
$this->order = $order;
|
|
$customer = new Customer($order->id_customer);
|
|
$cart = new Cart($order->id_cart);
|
|
$this->customer = $customer;
|
|
$this->cart = $cart;
|
|
}
|
|
}
|
|
|
|
public function setFraudScore() {
|
|
if( !Validate::isLoadedObject($this->order) ) {
|
|
throw new Exception("this->order is not an object");
|
|
return false;
|
|
}
|
|
$this->fraudAccount();
|
|
$this->fraudAdresses();
|
|
$this->fraudEmail();
|
|
$this->fraudConnexion();
|
|
$this->fraudCountData();
|
|
$this->fraudInvite();
|
|
$this->alreadyInFraud();
|
|
}
|
|
|
|
public function getFraudScore() {
|
|
return $this->fraud_score;
|
|
}
|
|
public function getFraudReport() {
|
|
return $this->fraud_report;
|
|
}
|
|
|
|
/**
|
|
* Tools fraud
|
|
**/
|
|
private function fraudAccount() {
|
|
$account_today = time() - strtotime($this->customer->date_add) < 86400;
|
|
$time_warn = in_array(date('H'), array('23', '00', '01', '02', '03', '04', '05'));
|
|
$lower_warn = (mb_strtolower($this->customer->firstname) === $this->customer->firstname) && (mb_strtolower($this->customer->lastname) === $this->customer->lastname);
|
|
$name_warn = preg_match('/^(.*)(farid|rahmani|siphia|zitouni|moussa)(.*)$/i', $this->customer->lastname)
|
|
|| preg_match('/(\w)\1{2,}/', $this->customer->firstname)
|
|
|| preg_match('/(\w)\1{2,}/', $this->customer->lastname);
|
|
$account_today? $this->fraud_report[] = 'Compte créé moins de 24h avant la commande (+50)': TRUE;
|
|
$time_warn? $this->fraud_report[] = 'Commande de nuit (+20)': TRUE;
|
|
$lower_warn? $this->fraud_report[] = 'Nom en minuscules (+20)': TRUE;
|
|
$name_warn? $this->fraud_report[] = 'Nom fraudeur ou anormal (+100)': TRUE;
|
|
|
|
$this->fraud_score = $account_today * 50 + $time_warn * 20 + $lower_warn * 20 + $name_warn * 100;
|
|
}
|
|
|
|
private function fraudAdresses() {
|
|
$this->delivery_country = (int) Db::getInstance()->getValue('
|
|
SELECT `id_country`
|
|
FROM `'._DB_PREFIX_.'address`
|
|
WHERE `id_address` = '.(int) $this->cart->id_address_delivery.'
|
|
');
|
|
$this->invoice_country = (int) Db::getInstance()->getValue('
|
|
SELECT `id_country`
|
|
FROM `'._DB_PREFIX_.'address`
|
|
WHERE `id_address` = '.(int) $this->cart->id_address_invoice.'
|
|
');
|
|
|
|
// restriction or France, Espagne, Belgique
|
|
$foreign_delivery = ($this->delivery_country != 8 && $this->delivery_country != 6 && $this->delivery_country != 3);
|
|
|
|
$foreign_invoice = ($this->invoice_country != 8 && (int) $this->cart->id_address_invoice != (int) $this->cart->id_address_delivery)
|
|
|| ($this->invoice_country == 8 && $this->delivery_country != 8);
|
|
|
|
$delivery_warn = (bool) Db::getInstance()->getValue('
|
|
SELECT `id_cart`
|
|
FROM `'._DB_PREFIX_.'socolissimo_delivery_info`
|
|
WHERE `id_cart` = '.(int) $this->cart->id.'
|
|
AND `delivery_mode` != "DOM"
|
|
');
|
|
|
|
$livraison_relai_idf = Db::getInstance()->getRow('
|
|
SELECT SUBSTRING(`przipcode`, 1, 2) as zipcode, `delivery_mode`
|
|
FROM `'._DB_PREFIX_.'socolissimo_delivery_info`
|
|
WHERE `id_cart` = '.(int) $this->cart->id.'
|
|
AND `delivery_mode` != "DOM"
|
|
');
|
|
|
|
$delivery_dpt_risk = FALSE;
|
|
if(!empty($livraison_relai_idf)) {
|
|
if($livraison_relai_idf['zipcode'] == 75
|
|
|| $livraison_relai_idf['zipcode'] == 92
|
|
|| $livraison_relai_idf['zipcode'] == 93) {
|
|
$delivery_dpt_risk = TRUE;
|
|
}
|
|
}
|
|
|
|
$delivery_dpt_risk ? $this->fraud_report[] = 'Livraison département à risque (75,92,93) (+30)': TRUE;
|
|
$foreign_delivery? $this->fraud_report[] = 'Livraison à l\'étranger (+50)': TRUE;
|
|
$foreign_invoice? $this->fraud_report[] = 'Facturation à l\'étranger (+50)': TRUE;
|
|
$delivery_warn? $this->fraud_report[] = 'Livraison hors domicile (+20)': TRUE;
|
|
|
|
$this->fraud_score += $foreign_delivery * 50 + $foreign_invoice * 50 + $delivery_warn * 20;
|
|
}
|
|
|
|
private function fraudEmail() {
|
|
$freemail_warn = preg_match('/^(.*)@(yahoo|hotmail|gmail|yopmail|mail|mail2web|fastmail|mailinator|jetable|msn)\.(.*)$/i', $this->customer->email);
|
|
$cctldmail_warn = preg_match('/^(.*)@(.*)\.(cn|cc|in|tw|ru|pl|ua|bg|bj|br|by|ci|dj|dz|eg|et|fj|hk|it|ma|si|tn|zw)$/i', $this->customer->email);
|
|
|
|
$freemail_warn? $this->fraud_report[] = 'Utilisation d\'un compte mail ouvert (+20)': TRUE;
|
|
$cctldmail_warn? $this->fraud_report[] = 'CCTLD de l\'email à risque (+100)': TRUE;
|
|
|
|
$this->fraud_score += $freemail_warn * 20 + $cctldmail_warn * 100;
|
|
}
|
|
|
|
private function fraudConnexion() {
|
|
|
|
$data = Db::getInstance()->getRow('
|
|
SELECT *
|
|
FROM `ps_cart_fraud`
|
|
WHERE `id_cart` = '. (int)$this->cart->id);
|
|
|
|
if ($data) {
|
|
$proxy = (bool)$data['proxy'];
|
|
$ip_foreign = (bool)$data['ip_foreign'];
|
|
$ip_alert = (bool)$data['ip_alert'];
|
|
$freewifi = (bool)$data['freewifi'];
|
|
|
|
$proxy? $this->fraud_report[] = 'Utilisation d\'un proxy (+20)': TRUE;
|
|
$ip_foreign? $this->fraud_report[] = 'IP étrangère (+50)': TRUE;
|
|
$ip_alert? $this->fraud_report[] = 'IP étrangère dans un pays en liste grise (+200)': TRUE;
|
|
$freewifi? $this->fraud_report[] = 'Utilisation de Free Wifi (+50)': TRUE;
|
|
|
|
$this->fraud_score += $proxy * 20 + $ip_foreign * 200 + $ip_alert * 50 + $freewifi * 50;
|
|
}
|
|
|
|
}
|
|
|
|
private function fraudCountData() {
|
|
$count_addresses = Db::getInstance()->getValue('
|
|
SELECT COUNT(*)
|
|
FROM `'._DB_PREFIX_.'address`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
AND `alias` NOT LIKE "So Colissimo %"
|
|
');
|
|
if((int) $count_addresses > 2) {
|
|
$this->fraud_score += 5 * ((int) $count_addresses - 2);
|
|
$this->fraud_report[] = 'Compte à plus de 2 adresses (+'.(5 * ((int) $count_addresses - 2)).')';
|
|
}
|
|
|
|
$count_orders = Db::getInstance()->getRow('
|
|
SELECT COUNT(*) AS `total`
|
|
FROM `ps_orders`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
AND `date_add` >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
|
');
|
|
if($count_orders['total'] + 1 > 3) {
|
|
$this->fraud_score += 100;
|
|
$this->fraud_report[] = 'Compte origine de plus de 3 commandes ces 7 derniers jours (+100)';
|
|
}
|
|
|
|
$count_products = Db::getInstance()->getRow('
|
|
SELECT COUNT(*) AS `total`
|
|
FROM `ps_cart_product`
|
|
WHERE `id_cart` = '.(int) $this->cart->id.'
|
|
');
|
|
$count_total_paid = $this->cart->getOrderTotal();
|
|
|
|
if($count_products['total'] > 7 && $count_total_paid > 250) {
|
|
$this->fraud_score += 100;
|
|
$this->fraud_report[] = 'Plus de 7 produits dans le panier et total de plus de 250€ (+100)';
|
|
}
|
|
$count_oldorders = Db::getInstance()->getValue('
|
|
SELECT COUNT(*)
|
|
FROM `'._DB_PREFIX_.'orders`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
AND `valid` = 1
|
|
AND `date_add` < DATE_SUB(NOW(), INTERVAL 30 DAY)
|
|
');
|
|
if($count_oldorders > 3) {
|
|
$this->fraud_score -= 50;
|
|
$this->fraud_report[] = 'Compte avec plus de 3 commandes valides de plus de 30 jours (-50)';
|
|
}
|
|
}
|
|
|
|
private function fraudInvite() {
|
|
$has_order = (bool) (int) Db::getInstance()->getValue('
|
|
SELECT `id_order`
|
|
FROM `'._DB_PREFIX_.'orders`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
AND `valid` = 1
|
|
');
|
|
|
|
$has_invite = (bool) (int) Db::getInstance()->getValue('
|
|
SELECT `id_invite`
|
|
FROM `'._DB_PREFIX_.'invite`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
');
|
|
$has_landingpage = (bool) (int) Db::getInstance()->getValue('
|
|
SELECT `id_landing_page`
|
|
FROM `'._DB_PREFIX_.'landing_page_customer`
|
|
WHERE `id_customer` = '.(int) $this->customer->id.'
|
|
');
|
|
$has_invite
|
|
? ($has_landingpage
|
|
? $this->fraud_report[] = 'En provenance d\'une landing page avec parrain (-100)'
|
|
: ((strtotime($this->customer->date_add) < time() - 7776000) && $has_order
|
|
? $this->fraud_report[] = 'Parrain et compte de plus de 3 mois avec commande (-100)'
|
|
: TRUE
|
|
)
|
|
)
|
|
: TRUE
|
|
;
|
|
|
|
$this->fraud_score += ($has_invite
|
|
? ($has_landingpage || ((strtotime($this->customer->date_add) < time() - 7776000) && $has_order)
|
|
? -100
|
|
: 0
|
|
)
|
|
: 0
|
|
);
|
|
}
|
|
|
|
public function alreadyInFraud()
|
|
{
|
|
$already_fraud = Db::getInstance()->getValue('
|
|
SELECT COUNT(h.`id_order`)
|
|
FROM `'._DB_PREFIX_.'order_history` h
|
|
LEFT JOIN `'._DB_PREFIX_.'orders` o on h.`id_order` = o.`id_order`
|
|
WHERE o.`id_customer` = '.(int) $this->customer->id.'
|
|
AND h.`id_order_state` IN (15,16,18)
|
|
');
|
|
|
|
$already_suspect = Db::getInstance()->getValue('
|
|
SELECT COUNT(rep.`id_cart`)
|
|
FROM `'._DB_PREFIX_.'order_reputation` rep
|
|
LEFT JOIN `'._DB_PREFIX_.'cart` c ON c.`id_cart` = rep.`id_cart`
|
|
WHERE c.`id_customer` = '.(int) $this->customer->id.'
|
|
AND rep.`score` > 100
|
|
');
|
|
|
|
if ($already_suspect || $already_fraud) {
|
|
$this->fraud_score += 200;
|
|
$this->fraud_report[] = 'Compte avec des commandes en suspicion de fraude, fraude non détectée ou commandes frauduleuses (+200)';
|
|
}
|
|
|
|
// Adding from 15/02/2016
|
|
$already_suspect_by_names = Db::getInstance()->getValue('
|
|
SELECT COUNT(rep.`id_cart`)
|
|
FROM `'._DB_PREFIX_.'order_reputation` rep
|
|
LEFT JOIN `'._DB_PREFIX_.'cart` c ON c.`id_cart` = rep.`id_cart`
|
|
LEFT JOIN `'._DB_PREFIX_.'customer` cu ON cu.`id_customer` = c.`id_customer`
|
|
WHERE cu.`firstname` = "'.pSQL($this->customer->firstname).'"
|
|
AND cu.`lastname` = "'.pSQL($this->customer->lastname).'"
|
|
AND c.`id_customer`!='.$this->customer->id.'
|
|
AND c.`id_cart` IS NOT NULL
|
|
AND rep.`score` > 100
|
|
');
|
|
|
|
$already_fraud_by_names = Db::getInstance()->getValue('
|
|
SELECT COUNT(h.`id_order`)
|
|
FROM `'._DB_PREFIX_.'order_history` h
|
|
LEFT JOIN `'._DB_PREFIX_.'orders` o on h.`id_order` = o.`id_order`
|
|
LEFT JOIN `'._DB_PREFIX_.'customer` cu ON cu.`id_customer` = o.`id_customer`
|
|
WHERE cu.`firstname` = "'.pSQL($this->customer->firstname).'"
|
|
AND cu.`lastname` = "'.pSQL($this->customer->lastname).'"
|
|
AND o.`id_customer`!='.(int) $this->customer->id.'
|
|
AND o.`id_order` IS NOT NULL
|
|
AND h.`id_order_state` IN (15,16,18)
|
|
');
|
|
|
|
if ($already_suspect_by_names || $already_fraud_by_names) {
|
|
$this->fraud_score += 200;
|
|
$this->fraud_report[] = 'Existance d\'autres comptes de mêmes noms avec des commandes en suspicion de fraude, fraude non détectée ou commandes frauduleuses (+200)';
|
|
}
|
|
}
|
|
|
|
|
|
public static function getReputationOrder($id_order) {
|
|
$id_cart = Order::getCartIdStatic($id_order);
|
|
return Db::getInstance()->getRow('
|
|
SELECT *
|
|
FROM `'._DB_PREFIX_.'order_reputation`
|
|
WHERE `id_cart` = '. (int)$id_cart
|
|
);
|
|
}
|
|
|
|
|
|
public static function validOrder($id_order) {
|
|
$id_cart = Order::getCartIdStatic($id_order);
|
|
$order = new Order($id_order);
|
|
|
|
$sql = 'UPDATE `'._DB_PREFIX_.'order_reputation`
|
|
SET pass = 1
|
|
WHERE id_cart = '. (int)$id_cart;
|
|
|
|
if (Db::getInstance()->execute($sql)) {
|
|
Db::getInstance()->execute('
|
|
UPDATE
|
|
`'._DB_PREFIX_.'reputation`
|
|
SET `score` = 0
|
|
WHERE `id_customer` = '.(int)$order->id_customer
|
|
);
|
|
Db::getInstance()->execute('
|
|
DELETE FROM
|
|
`'._DB_PREFIX_.'order_history`
|
|
WHERE `id_order` = '. (int)$id_order
|
|
.' AND `id_order_state` = 18'
|
|
);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
public static function cidr_match($ip, $range) {
|
|
list ($subnet, $bits) = explode('/', $range);
|
|
$ip = ip2long($ip);
|
|
$subnet = ip2long($subnet);
|
|
$mask = -1 << (32 - $bits);
|
|
$subnet &= $mask;
|
|
return ($ip & $mask) == $subnet;
|
|
}
|
|
|
|
|
|
|
|
public static function CartFraudConnexion(Cart $cart) {
|
|
if (!Validate::isLoadedObject($cart)) {
|
|
return false;
|
|
}
|
|
|
|
$proxy_warn = FALSE;
|
|
foreach(array(
|
|
'HTTP_VIA',
|
|
'HTTP_X_FORWARDED_FOR',
|
|
'HTTP_FORWARDED_FOR',
|
|
'HTTP_X_FORWARDED',
|
|
'HTTP_FORWARDED',
|
|
'HTTP_CLIENT_IP',
|
|
'HTTP_FORWARDED_FOR_IP',
|
|
'VIA',
|
|
'X_FORWARDED_FOR',
|
|
'FORWARDED_FOR',
|
|
'X_FORWARDED',
|
|
'FORWARDED',
|
|
'CLIENT_IP',
|
|
'FORWARDED_FOR_IP',
|
|
'HTTP_PROXY_CONNECTION',
|
|
) as $x){
|
|
if(isset($_SERVER[$x])) {
|
|
$proxy_warn = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(self::cidr_match(Tools::getRemoteAddr(), '78.250.0.0/15')) {
|
|
$freewifi = TRUE;
|
|
} else {
|
|
$freewifi = FALSE;
|
|
}
|
|
|
|
include_once(_PS_GEOIP_DIR_.'geoipcity.inc');
|
|
include_once(_PS_GEOIP_DIR_.'geoipregionvars.php');
|
|
$gi = geoip_open(realpath(_PS_GEOIP_DIR_.'GeoLiteCity.dat'), GEOIP_STANDARD);
|
|
$record = geoip_record_by_addr($gi, Tools::getRemoteAddr());
|
|
|
|
$delivery_country = new Address($cart->id_address_delivery);
|
|
if($delivery_country InstanceOf Address) {
|
|
$foreignip_warn = is_object($record)
|
|
? (
|
|
$record->country_code == 'FR'
|
|
? FALSE
|
|
: (
|
|
strtolower($record->country_code) == Db::getInstance()->getValue('
|
|
SELECT LOWER(`iso_code`)
|
|
FROM `'._DB_PREFIX_.'country`
|
|
WHERE `id_country` = '.(int) $delivery_country->id_country.'
|
|
')
|
|
? FALSE
|
|
: TRUE
|
|
)
|
|
)
|
|
: FALSE;
|
|
// error_log('BBB - IP ETRANGERE');
|
|
} else{
|
|
$foreignip_warn = false;
|
|
}
|
|
|
|
$foreignip_alert = is_object($record)
|
|
? (
|
|
in_array($record->country_code, array(
|
|
'DE', 'AD', 'AT', 'BE', 'BG', 'CA', 'DK', 'ES', 'US', 'FI', 'FR', 'GI', 'GR', 'GP', 'GY', 'GF', 'HU', 'IE', 'IT', 'RE', 'LU', 'MQ', 'MC', 'NC', 'NL', 'PL', 'PT', 'CZ', 'GB', 'UK', 'SM', 'MF', 'SX', 'CH', 'TD', 'TF', 'VA', 'WF',
|
|
))
|
|
? FALSE
|
|
: TRUE
|
|
)
|
|
: FALSE;
|
|
|
|
|
|
Db::getInstance()->ExecuteS('
|
|
INSERT INTO `'._DB_PREFIX_.'cart_fraud`
|
|
VALUES (
|
|
'.(int)$cart->id.',
|
|
'.(int)$proxy_warn.',
|
|
'.(int)$foreignip_alert.',
|
|
'.(int)$foreignip_warn.',
|
|
'.(int)$freewifi.',
|
|
"'.Tools::getRemoteAddr().'"
|
|
)
|
|
ON DUPLICATE KEY
|
|
UPDATE
|
|
`proxy` = '.(int)$proxy_warn.',
|
|
`ip_foreign` = '.(int)$foreignip_alert.',
|
|
`ip_alert` = '.(int)$foreignip_warn.',
|
|
`freewifi` = '.(int)$freewifi.',
|
|
`ip_cart` = "'.Tools::getRemoteAddr().'"
|
|
');
|
|
}
|
|
|
|
}
|