Opencart 2 sets two HTTPOnly cookies PHPSESSID and default to identify the customer. Therefore, I decided to share/sync them over the stores.
1. Get the list of stores for Javascript
Maybe not best, but in /catalog/controller/common/header.php I assigned a variable:
$this->load->language('setting/store');
$this->load->model('setting/store');
$this->load->model('setting/setting');
$data['multi_stores'] = array();
$data['multi_stores'][] = array(
'store_id' => 0,
'name' => 'Main Site',
'url' => 'https://mysite.co.uk/',
'is_current' => stripos('https://mysite.co.uk/', $_SERVER['SERVER_NAME']) !== false
);
$results = $this->model_setting_store->getStores();
foreach ($results as $result) {
$data['multi_stores'][] = array(
'store_id' => $result['store_id'],
'name' => $result['name'],
'url' => $result['url'],
'is_current' => stripos($result['url'], $_SERVER['SERVER_NAME']) !== false
);
}
2. Than in template I used it:
<script type="text/javascript">
var multiStores = <?php echo json_encode($multi_stores); ?>;
</script>
3. Created two PHP scripts to set and get cookies:
- Please note, to set PHP HTTPOnly cookie, the 7th parameter must be true.
- Another note, to get HTTPOnly cookie we have to request it from server, it is not accessible via Javascript (which is its purpose in first place).
getCookies.php:
$cookies = array(
'PHPSESSID' => $_COOKIE['PHPSESSID'],
'default' => $_COOKIE['default'],
'currency' => $_COOKIE['currency'],
'language' => $_COOKIE['language']
);
header('Content-Type: application/json');
echo json_encode( $cookies );
setCookies.php:
$response = array(
'status' => 'ok'
);
/* Format: [cookie name] => [expire days] */
$cookies_to_sync = array(
'PHPSESSID' => '',
'default' => '',
'currency' => 30,
'language'=> 30
);
/* If no expire was set, than set session HTTPOnly cookie (last, 7th parameter 'true') */
foreach( $cookies_to_sync as $cname=>$cexpire ) {
if( $_POST[$cname] ) {
if( $cexpire ) {
/* 86400 seconds per day */
setcookie($cname, $_POST[$cname], time() + (86400 * $cexpire), '/', null, null, false);
} else {
setcookie($cname, $_POST[$cname], null, '/', null, null, true);
};
};
};
/* Browser requests a JSON, cross-origin enabled, with OPTIONS enabled to set cookies */
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Content-Type: application/json');
echo json_encode( $response );
4. The Javascript part:
- Please note, in order to send/set cookies cross-domain, we set OPTIONS in PHP header and for jQuery we add $.ajax xhrFields option withCredentials: true. Having that in mind, I created my method to sync website cookies:
this.syncWebsites = function() {
if( typeof multiStores!='undefined' ) {
that.stores = multiStores;
that.synced = that.readCookie('synced');
if( !that.synced ) {
/* First get cookies */
$.getJSON( "catalog/view/theme/mytheme/javascript/getCookies.php", function( data ) {
/* Send to other sites */
$.each(that.stores, function(i, store) {
if( !store.is_current ) {
/* Send to other sites, MUST use xhrFields->withCredentials: true, to set cookies */
$.ajax({
url: store.url.replace('http://', '//') + "catalog/view/theme/mytheme/javascript/setCookies.php",
xhrFields: {
withCredentials: true
},
type: "post",
crossDomain: true,
data: data,
dataType: "json",
success:function(result){
that.echo(JSON.stringify(result));
},
error:function(xhr, status, error){
that.echo(status);
}
});
};
});
that.createCookie('synced', 'Yes', '');
});
};
};
};
Please note: I created the synced cookie, so this requests happen only once during the session.
Final result:
We have all the Opencart 2 customers synced on all websites.
Security considerations:
All websites are using SSL encription. The danger of stealing the info is same as one would visit all of those websites.