2016-01-04 12:49:26 +01:00
< ? 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 ();
2016-01-27 15:59:19 +01:00
$this -> alreadyInFraud ();
2016-01-04 12:49:26 +01:00
}
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
);
}
2016-01-27 15:59:19 +01:00
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.'
2016-02-22 15:28:33 +01:00
AND h . `id_order_state` IN ( 15 , 16 , 18 )
2016-01-27 15:59:19 +01:00
' );
$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 ;
2016-02-22 15:28:33 +01:00
$this -> fraud_report [] = 'Compte avec des commandes en suspicion de fraude, fraude non détectée ou commandes frauduleuses (+200)' ;
}
2016-02-23 17:05:11 +01:00
// Adding from 23/02/2016
2016-02-22 15:28:33 +01:00
$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`
2016-02-23 16:35:17 +01:00
WHERE cu . `firstname` = " '.pSQL( $this->customer ->firstname).' "
AND cu . `lastname` = " '.pSQL( $this->customer ->lastname).' "
2016-02-22 15:28:33 +01:00
AND c . `id_customer` != '.$this->customer->id.'
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`
2016-02-23 16:35:17 +01:00
WHERE cu . `firstname` = " '.pSQL( $this->customer ->firstname).' "
AND cu . `lastname` = " '.pSQL( $this->customer ->lastname).' "
2016-02-22 15:28:33 +01:00
AND o . `id_customer` != '.(int) $this->customer->id.'
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)' ;
2016-01-27 15:59:19 +01:00
}
}
2016-01-04 12:49:26 +01:00
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().' "
' );
}
}