Cross Domains Sessions - Shared Shopping Cart Cross Domains

Cross domains sessions - shared shopping cart cross domains

You can use a third domain to identify your customers over all domains.

Use for example a PHP File on http://thirdDomain.com/session.php that is included on all pages on both shops.

Sample:

<script type="text/javascript" src="http://thirdDomain.com/session.php"></script>

After your customer switches domains, you can identify him as the same customer using the third domain.

You can assign the session id on both shops to the session id on the third domain to access the cart on both shops. You only need to inform the third domain about your shop sessions (i.e. add them as parameter).

Depending on how flexible you are with your code and templates, you can even use an output from the third domain to define the session id in your shops. This way you can use the same session id on all domains.
But normally a session id assignment should be the more secure way.

Using the javascript version you can also output scripts that may add a session id to all outgoing links and forms to the other domain in the current html page. This might be interesting if you can identify your customer as having cookies blocked.
You can also use the javascript to inform the parent document about an existing session.

Multi store multi domain one checkout, single customer login into all stores?

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.

Secure and Flexible Cross-Domain Sessions

What you could do is create "cross-over" links between the sites to carry the session over.

The simplest way is to pass the session id via the query string; e.g.

http://whateverblammo.com/?sessid=XXYYZZ

Before you start thinking that anyone can trap that information, think about how your cookies are transferred; assuming you're not using SSL, there's not much difference for someone who taps the network.

That doesn't mean it's safe; for one, users could accidentally copy/paste the address bar and thus leaking out their session. To limit this exposure, you could immediately redirect to a page without the session id after receiving it.

Note that using mcrypt() on the session id won't help much, because it's not the visibility of the value that's the problem; session hijacking doesn't care about the underlying value, only its reproducibility of the url.

You have to make sure the id can be used only once; this can be done by creating a session variable that keeps track of the use count:

$_SESSION['extids'] = array();

$ext = md5(uniqid(mt_rand(), true)); // just a semi random diddy
$_SESSION['extids'][$ext] = 1;

$link = 'http://othersite/?' . http_build_query('sessid' => session_id() . '-' . $ext);

When received:

list($sid, $ext) = explode('-', $_GET['sessid']);
session_id($sid);
session_start();
if (isset($_SESSION['extids'][$ext])) {
// okay, make sure it can't be used again
unset($_SESSION['extids'][$ext]);
}

You need these links every time a boundary is crossed, because the session may have gotten regenerated since the last time.

Opencart cart across multiple stores with different subdomains

OpenCart stores all these information in you PHP session. Since your stores are located under different subdomains, the PHP session changes when you switch from one store to another.

So the first thing you need to do is to share the session between all subdomains. By default, PHP uses the 'PHPSESSID' cookie to propagate session data across multiple pages, and by default it uses the current top-level domain and subdomain in the cookie declaration.

Example: www.domain.com

The downside to this is that the session data can't travel with you to other subdomains. So if you started a session on www.domain.com, the session data would become unavailable on forums.domain.com. The solution is to change the domain PHP uses when it sets the 'PHPSESSID' cookie.

Assuming you have an init file that you include at the top of every PHP page, you can use the ini_set() function. Just add this to the top of your init page:

ini_set('session.cookie_domain',
substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],"."),100));

This line of code takes the domain and lops off the subdomain.

Example: forums.domain.com -> .domain.com

Now, every time PHP sets the 'PHPSESSID' cookie, the cookie will be available to all subdomains!

You might also need to make some little modifications to the OpenCart's core in order to make it work.

Have fun :)



Related Topics



Leave a reply



Submit