* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision: 6594 $
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registred Trademark & Property of PrestaShop SA
*/
if (!defined('_CAN_LOAD_FILES_'))
exit;
class PrestaFraud extends Module
{
private $_html;
public $_errors;
private $_trustUrl;
private $_activities;
private $_payment_types;
public function __construct()
{
$this->name = 'prestafraud';
$this->tab = 'payment_security';
$this->version = '0.99';
$this->author = 'PrestaShop';
$this->need_instance = 0;
parent::__construct();
$this->displayName = $this->l('PrestaShop Security');
$this->description = $this->l('Protect your store from fraudulent payments');
$this->_activities = array(0 => $this->l('-- Please choose your main activity --'),
1 => $this->l('Adult'),
2 => $this->l('Animals and Pets'),
3 => $this->l('Art and Culture'),
4 => $this->l('Babies'),
5 => $this->l('Beauty and Personal Care'),
6 => $this->l('Cars'),
7 => $this->l('Computer Hardware and Software'),
8 => $this->l('Download'),
9 => $this->l('Fashion and accessories'),
10 => $this->l('Flowers, Gifts and Crafts'),
11 => $this->l('Food and beverage'),
12 => $this->l('HiFi, Photo and Video'),
13 => $this->l('Home and Garden'),
14 => $this->l('Home Appliances'),
15 => $this->l('Jewelry'),
16 => $this->l('Mobile and Telecom'),
17 => $this->l('Services'),
18 => $this->l('Shoes and accessories'),
19 => $this->l('Sport and Entertainment'),
20 => $this->l('Travel'));
$this->_payment_types = array(0 => $this->l('Cheque'),
1 => $this->l('Bankwire'),
2 => $this->l('Credit card'),
3 => $this->l('Credit card multiple'),
4 => $this->l('Prepaid account (MoneyBookers, PayPal...)'));
$this->_trustUrl = 'http'.(extension_loaded('openssl') ? 's' : '').'://trust.prestashop.com/';
}
public function install()
{
if (!parent::install() OR
!$this->registerHook('updatecarrier') OR
!$this->registerHook('newOrder') OR
!$this->registerHook('adminOrder') OR
!$this->registerHook('cart'))
return false;
if (!$sql = file_get_contents(dirname(__FILE__).'/install.sql'))
die(Tools::displayError('File install.sql is not readable'));
$sql = str_replace(array('PREFIX_', 'ENGINE_TYPE'), array(_DB_PREFIX_, _MYSQL_ENGINE_), $sql);
$sql = preg_split("/;\s*[\r\n]+/", $sql);
foreach ($sql as $query)
if ($query AND sizeof($query) AND !Db::getInstance()->Execute(trim($query)))
return false;
return true;
}
public function uninstall()
{
parent::uninstall();
}
public function getContent()
{
$this->postProcess();
$this->_displayConfiguration();
return $this->_html;
}
private function _displayConfiguration()
{
global $cookie;
$this->_html .= '
';
return $this->_html;
}
public function postProcess()
{
if (Tools::isSubmit('submitSettings'))
{
if (isset($_POST['login']))
Configuration::updateValue('PS_TRUST_EMAIL', $_POST['email']);
if (isset($_POST['passwd']))
Configuration::updateValue('PS_TRUST_PASSWD', $_POST['passwd']);
if ($activity = Tools::getValue('shop_activity'))
Configuration::updateValue('PS_SHOP_ACTIVITY', $activity);
$carriers_configuration = array();
$payments_configuration = array();
foreach($_POST AS $field => $val)
{
if (preg_match('/^carrier_([0-9]+)/Ui', $field, $res))
$carriers_configuration[$res[1]] = $val;
elseif (preg_match('/^paymentmodule_([0-9]+)/Ui', $field, $pay_res))
$payments_configuration[$pay_res[1]] = $val;
}
$this->_setCarriersConfiguration($carriers_configuration);
$this->_setPaymentsConfiguration($payments_configuration);
}
elseif (Tools::isSubmit('submitCreateAccount'))
$this->_html .= $this->_createAccount();
if (sizeof($this->_errors))
{
$err = '';
foreach ($this->_errors AS $error)
$err .= $error.'
';
$this->_html .= $this->displayError($err);
}
}
private function _createAccount()
{
if (!$email = Tools::getValue('email') OR !Validate::isEmail($email))
$this->_errors[] = $this->l('Email is invalid');
if (!$shop_url = Tools::getValue('shop_url') OR !Validate::isAbsoluteUrl($shop_url))
$this->_errors[] = $this->l('Shop URL is invalid');
if (sizeof($this->_errors))
return false;
$root = new SimpleXMLElement("");
$xml = $root->addChild('create_account');
$xml->addChild('email', $email);
$xml->addChild('shop_url', $shop_url);
$result = $this->_pushDatas($root->asXml());
$xml_result = simplexml_load_string($result);
if (!(int)$xml_result->create_account->result)
{
$this->_errors[] = (string)$xml_result->create_account->errors;
return false;
}
Configuration::updateValue('PS_TRUST_SHOP_ID', (string)$xml_result->create_account->shop_id);
Configuration::updateValue('PS_TRUST_SHOP_KEY', (string)$xml_result->create_account->shop_key);
$this->_html .= $this->displayConfirmation('Account successfull created');
}
public function hookUpdateCarrier($params)
{
$this->_updateConfiguredCarrier((int)$params['id_carrier'], (int)$params['carrier']->id);
}
public function hookNewOrder($params)
{
if (!Configuration::get('PS_SHOP_ENABLE') OR !Configuration::get('PS_TRUST_SHOP_ID') OR !Configuration::get('PS_TRUST_SHOP_KEY'))
return;
$customer = new Customer((int)$params['order']->id_customer);
$address_delivery = new Address((int)$params['order']->id_address_delivery);
$address_invoice = new Address((int)$params['order']->id_address_invoice);
$root = new SimpleXMLElement("");
$xml = $root->addChild('new_order');
$shop_configuration = $xml->addChild('shop');
$default_country = new Country((int)Configuration::get('PS_COUNTRY_DEFAULT'));
$default_currency = new Currency((int)Configuration::get('PS_CURRENCY_DEFAULT'));
$shop_configuration->addChild('default_country', $default_country->iso_code);
$shop_configuration->addChild('default_currency', $default_currency->iso_code);
$shop_configuration->addChild('shop_id', Configuration::get('PS_TRUST_SHOP_ID'));
$shop_configuration->addChild('shop_password', Configuration::get('PS_TRUST_SHOP_KEY'));
if ($activity = Configuration::get('PS_SHOP_ACTIVITY'))
$shop_configuration->addChild('shop_activity', $activity);
$customer_infos = $xml->addChild('customer');
$customer_infos->addChild('customer_id', $customer->id);
$customer_infos->addChild('lastname', $customer->lastname);
$customer_infos->addChild('firstname', $customer->firstname);
$customer_infos->addChild('email', $customer->email);
$customer_infos->addChild('is_guest', (int)$customer->is_guest);
$customer_infos->addChild('birthday', $customer->birthday);
$delivery = $xml->addChild('delivery');
$delivery->addChild('lastname', $address_delivery->lastname);
$delivery->addChild('firstname', $address_delivery->firstname);
$delivery->addChild('company', $address_delivery->company);
$delivery->addChild('dni', $address_delivery->dni);
$delivery->addChild('address1', $address_delivery->address1);
$delivery->addChild('address2', $address_delivery->address2);
$delivery->addChild('phone', $address_delivery->phone);
$delivery->addChild('phone_mobile', $address_delivery->phone_mobile);
$delivery->addChild('city', $address_delivery->city);
$delivery->addChild('postcode', $address_delivery->postcode);
if ($address_delivery->id_state !== NULL OR $address_delivery->id_state != '')
{
$State = new State((int)$address_delivery->id_state);
$delivery->addChild('state', $State->iso_code);
}
$delivery->addChild('country', Country::getIsoById((int)$address_delivery->id_country));
$invoice = $xml->addChild('invoice');
$invoice->addChild('lastname', $address_invoice->lastname);
$invoice->addChild('firstname', $address_invoice->firstname);
$invoice->addChild('company', $address_invoice->company);
$invoice->addChild('dni', $address_invoice->dni);
$invoice->addChild('address1', $address_invoice->address1);
$invoice->addChild('address2', $address_invoice->address2);
$invoice->addChild('phone', $address_invoice->phone);
$invoice->addChild('phone_mobile', $address_invoice->phone_mobile);
$invoice->addChild('city', $address_invoice->city);
$invoice->addChild('postcode', $address_invoice->postcode);
if ($address_invoice->id_state !== NULL OR $address_invoice->id_state != '')
{
$State = new State((int)$address_invoice->id_state);
$invoice->addChild('state', $State->iso_code);
}
$invoice->addChild('country', Country::getIsoById((int)$address_invoice->id_country));
$infos = $this->_getCustomerInfos($params['order']);
$history = $xml->addChild('customer_history');
$history->addChild('customer_date_last_order', $infos['customer_date_last_order']);
$history->addChild('customer_orders_valid_count', (int)$infos['customer_orders_valid_count']);
$history->addChild('customer_orders_valid_sum', (float)$infos['customer_orders_valid_sum']);
$history->addChild('customer_orders_unvalid_count', (int)$infos['customer_orders_unvalid_count']);
$history->addChild('customer_orders_unvalid_sum', (float)$infos['customer_orders_unvalid_sum']);
$history->addChild('customer_ip_addresses_history', $infos['customer_ip_addresses_history']);
$history->addChild('customer_date_add', $customer->date_add);
$product_list = $params['order']->getProductsDetail();
$order = $xml->addChild('order_detail');
$order->addChild('order_id', (int)$params['order']->id);
$order->addChild('order_amount', $params['order']->total_paid);
$currency = new Currency((int)$params['order']->id_currency);
$order->addChild('currency', $currency->iso_code);
$products = $order->addChild('products');
foreach ($product_list AS $p)
{
$products->addChild('name', $p['product_name']);
$products->addChild('price', $p['product_price']);
$products->addChild('quantity', $p['product_quantity']);
$products->addChild('is_virtual', (int)!empty($p['download_hash']));
}
$sources = ConnectionsSource::getOrderSources($params['order']->id);
$referers = array();
if ($sources)
foreach ($sources AS $source)
$referers[] = $source['http_referer'];
if (sizeof($referers))
$order->addChild('order_referers', serialize($referers));
$configured_payments = $this->_getConfiguredPayments();
$paymentModule = Module::getInstanceByName($params['order']->module);
$order->addChild('payment_name', $paymentModule->displayName);
$order->addChild('payment_type', (int)$configured_payments[$paymentModule->id]);
$order->addChild('order_date', $params['order']->date_add);
$order->addChild('order_ip_address', $this->_getIpByCart($id_cart));
$carrier = new Carrier((int)$params['order']->id_carrier);
$carrier_infos = $order->addChild('carrier_infos');
$carrier_infos->addChild('name', $carrier->name);
$carriers_type = $this->_getConfiguredCarriers();
$carrier_infos->addChild('type', $carriers_type[$carrier->id]);
if ($this->_pushDatas($root->asXml()) !== false)
Db::getInstance()->Execute('INSERT INTO '._DB_PREFIX_.'prestafraud_orders (id_order) VALUES('.(int)$params['order']->id.')');
return true;
}
public function hookCart($params)
{
if ($_SERVER['REMOTE_ADDR'] == '0.0.0.0' OR $_SERVER['REMOTE_ADDR'] == '' OR $_SERVER['REMOTE_ADDR'] === false OR $_SERVER['REMOTE_ADDR'] === '::1')
return;
if (!$params['cart']->id)
return;
$res = Db::getInstance()->getValue('
SELECT `id_cart`
FROM '._DB_PREFIX_.'prestafraud_carts
WHERE id_cart='.(int)($params['cart']->id));
if ($res)
Db::getInstance()->Execute('
UPDATE `'._DB_PREFIX_.'prestafraud_carts`
SET `ip_address` = '.ip2long($_SERVER['REMOTE_ADDR']).', `date` = \''.pSQL(date('Y-m-d H:i:s')).'\'
WHERE `id_cart` = '.(int)($params['cart']->id).' LIMIT 1');
else
Db::getInstance()->Execute('
INSERT INTO `'._DB_PREFIX_.'prestafraud_carts` (`id_cart`, `ip_address`, `date`)
VALUES ('.(int)($params['cart']->id).', '.ip2long($_SERVER['REMOTE_ADDR']).',\''.date('Y-m-d H:i:s').'\')');
return true;
}
private function _getCustomerInfos($order)
{
$last_order = Db::getInstance()->getValue('SELECT date_add
FROM '._DB_PREFIX_.'orders
WHERE id_customer='.(int)$order->id_customer.' AND id_order != '.(int)$order->id.'
ORDER BY date_add DESC');
$orders_valid = Db::getInstance()->getRow('
SELECT COUNT(*) nb_valid, SUM(total_paid) sum_valid
FROM '._DB_PREFIX_.'orders
WHERE valid=1 AND id_order!='.(int)$order->id.' AND id_customer = '.(int)$order->id_customer);
$orders_unvalid = Db::getInstance()->getRow('
SELECT COUNT(*) nb_unvalid, SUM(total_paid) sum_unvalid
FROM '._DB_PREFIX_.'orders
WHERE valid=0 AND id_order!='.(int)$order->id.' AND id_customer = '.(int)$order->id_customer);
$ip_addresses = Db::getInstance()->ExecuteS('
SELECT c.ip_address
FROM '._DB_PREFIX_.'guest g
LEFT JOIN '._DB_PREFIX_.'connections c ON (c.id_guest = g.id_guest)
WHERE g.id_customer='.(int)$order->id_customer.'
ORDER BY c.id_connections DESC');
$address_list = array();
foreach ($ip_addresses AS $ip)
$address_list[] = $ip['ip_address'];
return array(
'customer_date_last_order' => $last_order,
'customer_orders_valid_count' => $orders_valid['nb_valid'],
'customer_orders_valid_sum' => $orders_valid['sum_valid'],
'customer_orders_unvalid_count' => $orders_unvalid['nb_unvalid'],
'customer_orders_unvalid_sum' => $orders_unvalid['sum_unvalid'],
'customer_ip_addresses_history' => serialize($address_list)
);
}
private static function _getIpByCart($id_cart)
{
return long2ip(Db::getInstance()->getValue('
SELECT `ip_address`
FROM '._DB_PREFIX_.'prestafraud_carts
WHERE id_cart = '.(int)$id_cart));
}
public function hookAdminOrder($params)
{
global $cookie;
$id_order = Db::getInstance()->getValue('SELECT id_order FROM '._DB_PREFIX_.'prestafraud_orders WHERE id_order = '.(int)$params['id_order']);
$this->_html .= '
';
return $this->_html;
}
private function _getScoring($id_order, $id_lang)
{
if (!$scoring = Db::getInstance()->getRow('SELECT * FROM '._DB_PREFIX_.'prestafraud_orders WHERE scoring IS NOT NULL AND id_order = '.(int)$id_order))
{
$root = new SimpleXMLElement("");
$xml = $root->addChild('get_scoring');
$xml->addChild('shop_id', Configuration::get('PS_TRUST_SHOP_ID'));
$xml->addChild('shop_password', Configuration::get('PS_TRUST_SHOP_KEY'));
$xml->addChild('id_order', (int)$id_order);
$xml->addChild('lang', Language::getIsoById((int)$id_lang));
$result = $this->_pushDatas($root->asXml());
if (!$result)
return false;
$xml = simplexml_load_string($result);
if ((int)$xml->check_scoring->status != -1)
Db::getInstance()->Execute('UPDATE '._DB_PREFIX_.'prestafraud_orders SET scoring = '.(float)$xml->check_scoring->scoring.', comment = \''.pSQL($xml->check_scoring->comment).'\' WHERE id_order='.(int)$id_order);
$scoring = array('scoring' => (float)$xml->check_scoring->scoring, 'comment' => (string)$xml->check_scoring->comment);
}
return $scoring;
}
private function _getPrestaTrustCarriersType()
{
return array(
'1' => $this->l('Pick up in-store'),
'2' => $this->l('Withdrawal point'),
'3' => $this->l('Slow shipping more than 3 days'),
'4' => $this->l('Shipping express'));
}
private function _getConfiguredCarriers()
{
$res = Db::getInstance()->ExecuteS('SELECT * FROM '._DB_PREFIX_.'prestafraud_carrier');
$carriers = array();
foreach ($res AS $row)
$carriers[$row['id_carrier']] = $row['id_prestafraud_carrier_type'];
return $carriers;
}
private function _getConfiguredPayments()
{
$res = Db::getInstance()->ExecuteS('SELECT * FROM '._DB_PREFIX_.'prestafraud_payment');
$payments = array();
foreach ($res AS $row)
$payments[$row['id_module']] = $row['id_prestafraud_payment_type'];
return $payments;
}
private function _setCarriersConfiguration($carriers)
{
Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'prestafraud_carrier');
foreach ($carriers AS $id_carrier => $id_carrier_type)
Db::getInstance()->Execute('INSERT INTO '._DB_PREFIX_.'prestafraud_carrier (id_carrier, id_prestafraud_carrier_type) VALUES ('.(int)$id_carrier.', '.(int)$id_carrier_type.')');
}
private function _setPaymentsConfiguration($payments)
{
Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'prestafraud_payment');
foreach ($payments AS $id_module => $id_payment_type)
Db::getInstance()->Execute('INSERT INTO '._DB_PREFIX_.'prestafraud_payment (id_module, id_prestafraud_payment_type) VALUES ('.(int)$id_module.', '.(int)$id_payment_type.')');
}
private function _updateConfiguredCarrier($old, $new)
{
return Db::getInstance()->Execute('UPDATE '._DB_PREFIX_.'prestafraud_carrier SET id_carrier='.(int)$new.' WHERE id_carrier='.(int)$old);
}
private function _pushDatas($datas)
{
if (function_exists('curl_init'))
{
$ch = curl_init($this->_trustUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('xml' => $datas));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
elseif (function_exists('file_get_contents'))
{
$context = stream_context_create(array('http' => array('timeout' => 5)));
return file_get_contents($this->_trustUrl.'?xml='.urlencode(str_replace("\r", "\n", '', $datas)), $context);
}
else
return false;
}
}