bebeboutik/modules/fraud/models/FraudCore.php
2016-02-23 16:35:17 +01:00

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().'"
');
}
}