Jump to content

Integrating Zen-Cart/OSCommerce passwords with Prestashop


João Cunha

Recommended Posts

Hi there! This is my first contribution to the community. I hope it helps someone.

 

I would like to share my approach on how to integrate Zen-Cart / OSCommerce passwords with Prestashop. I have a Zen-Cart shop with 50k registered customers which I am migrating to Prestashop. The "Back Office -> Tools -> CSV Import" tool works like a charm to import your customers but they will not be able to login on Prestashop because passwords are encrypted in different ways on both store managers.

 

This solution requires no database modification (aside from creating a support table) and only one php code modification (/classes/Customer.php). It will let your legacy customers login and change passwords through admin panel or "forgot my password" if they'd like. Actually they would not notice anything different at all.

 

If you want to understand some of the inner workings of both systems, I would recommend you to learn a little about password hashing and hash salting. You can skip this part if you want to get your hands dirty fast.

 

How Zen-Cart / OSCommerce passwords work:

 

Format: 32 alphanumeric characters + colon + 2 alphanumeric characters salt

E.g: e56d64755f66a86996b54114bb4102bf:08

35 characters total

It has a salting function which generates a random salt for every password.

 

The password is hashed with MD5 and salted with 2 aditional characters. These two aditional characters are then appended to the password with a colon.

 

How Prestashop passwords work:

Format: 32 alphanumeric characters (a standard MD5 salted hash)

E.g: e56d64755f66a86996b54114bb4102bf

32 characters total

It uses a per-installation random constant called _COOKIE_KEY_ as salt.

 

As you can see, they simply don't match. After some tries, I ended up with the following solution:

 

==================================

IMPORTANT NOTES:

 

- It works for Prestashop V1.4.7X (needs to be tested for other versions);

- DO A BACKUP BEFORE ANY CHANGES IN YOUR DATABASE/CODE;

- Try it in a development environment;

- I'm obviously not responsible if you screw your shop;

- Have I already mentioned to do backups?

- English is my second language. Sorry you grammar nazis.

 

DATABASE:

 

1) Export the prefix_customers table from Zen-Cart / OSCommerce / OpenCart into a CSV file;

2) Import your users through Prestashop's CSV Import tool;

3) Create this table in your Prestashop database:

 

 

CREATE TABLE zc_legacy_passwords (
 id INT NOT NULL,
 PRIMARY KEY(id),
 email VARCHAR(100),
 password VARCHAR(35),
 updated BOOLEAN NOT NULL
);

 

4) Populate this table using the previously created .CSV file or create a .SQL file from the following query and import into the zc_legacy_passwords table:

 

SELECT customers_id, LOWER(customers_email_address), customers_password FROM PREFIX_customers ORDER BY customers_id

 

Now we have all the data needed to allow our customers log into Prestashop, but we still need to change how the login process work.

 

CODING STEPS:

 

Modify the /classes/Customer.php file with the following:

 

1) Look for the public function getByEmail($email, $passwd = NULL) <- line 203

2) Replace lines 217 and 218, turning it from...

 

 

if (!$result)
return false;

 

...to...

 

 

// == BEGIN ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
// == BY João Cunha - [email protected]
// == @ 31/03/2012
// == USE AND MODIFY AT WILL
// == TESTED ON PRESTASHOP V1.4.7X
if (!$result) { //<- INVALID PRESTASHOP LOGIN, IT MAY BE A ZEN-CART / OSCOMMERCE PASSWORD
//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `zc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN

//WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
Db::getInstance()->Execute('
		UPDATE `'._DB_PREFIX_	.'customer`
		SET `passwd` = \''.md5(pSQL(_COOKIE_KEY_.$passwd)).'\'
		WHERE `email` = \''.pSQL($email).'\'');

//...AND FLAG IT AS UPDATED, SO THE NEXT TIME HE LOGS IN, HE WON'T ENTER THIS ROUTINE.
Db::getInstance()->Execute('
		UPDATE `zc_legacy_passwords`
		SET `updated` = 1
		WHERE `email` = \''.pSQL($email).'\'');

//USER IS AUTHENTICATED, OVERWRITE THE EMPTY $result VARIABLE
$result = Db::getInstance()->getRow('
SELECT *
FROM `'._DB_PREFIX_ .'customer`
WHERE `active` = 1
AND `email` = \''.pSQL($email).'\'
AND `deleted` = 0
AND `is_guest` = 0');
}
// == END ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION

==================================

 

And you're done!

 

I don't know if there is another way of achieving the same results without modifying the Customer.php core file, but that would be great. Since I'm a Prestashop noob, I would like to hear any thoughts from you guys.

 

Cheers,

João Cunha

Brazil

Edited by João Cunha (see edit history)
  • Like 4
  • Thanks 1
Link to comment
Share on other sites

  • 2 months later...
  • 3 months later...

Thanks for posting solution to this issue, it's working fine with PS1.5 as well. I found a little typo in your manual - missing "d" in DB table creation causes problems in queries further:

 

DATABASE:

 

3) Create this table in your Prestashop database:

 

CREATE TABLE zc_legacy_passwords (

`id` INT NOT NULL,

PRIMARY KEY(id),

`email` VARCHAR(100),

`password` VARCHAR(35),

`updated` BOOLEAN NOT NULL

);

 

 

I made a class override for PS1.5 based on your code - you can overwrite prestashop/override/classes/Customer.php with that code instead of editing core files.

 

<?php

class Customer extends CustomerCore
{
public function getByEmail($email, $passwd = null) {
if (!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd)))
die (Tools::displayError());

$sql = 'SELECT *
FROM `'._DB_PREFIX_.'customer`
WHERE `email` = \''.pSQL($email).'\'
'.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
'.(isset($passwd) ? 'AND `passwd` = \''.Tools::encrypt($passwd).'\'' : '').'
AND `deleted` = 0
AND `is_guest` = 0';
$result = Db::getInstance()->getRow($sql);

// == BEGIN ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
// == BY João Cunha - [email protected]
// == @ 31/03/2012
// == USE AND MODIFY AT WILL
// == TESTED ON PRESTASHOP V1.4.7X
if (!$result) { //<- INVALID PRESTASHOP LOGIN, IT MAY BE A ZEN-CART / OSCOMMERCE PASSWORD
//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `osc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN

//WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
Db::getInstance()->Execute('
UPDATE `'._DB_PREFIX_ .'customer`
SET `passwd` = \''.md5(pSQL(_COOKIE_KEY_.$passwd)).'\'
WHERE `email` = \''.pSQL($email).'\'');

//...AND FLAG IT AS UPDATED, SO THE NEXT TIME HE LOGS IN, HE WON'T ENTER THIS ROUTINE.
Db::getInstance()->Execute('
UPDATE `osc_legacy_passwords`
SET `updated` = 1
WHERE `email` = \''.pSQL($email).'\'');

//USER IS AUTHENTICATED, OVERWRITE THE EMPTY $result VARIABLE
$result = Db::getInstance()->getRow('
SELECT *
FROM `'._DB_PREFIX_ .'customer`
WHERE `active` = 1
AND `email` = \''.pSQL($email).'\'
AND `deleted` = 0
AND `is_guest` = 0');
}
// == END ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION

$this->id = $result['id_customer'];
foreach ($result as $key => $value)
if (key_exists($key, $this))
$this->{$key} = $value;

return $this;
}
}

 

EDIT: Forgot to mention - I've renamed legacy passwords table name to osc_legacy_passwords so you'll probably have to rename it (either table name in DB or hardcoded in script).

Edited by speed3r (see edit history)
  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

Thanks for posting solution to this issue, it's working fine with PS1.5 as well. I found a little typo in your manual - missing "d" in DB table creation causes problems in queries further:

 

Good catch. Post edited accordingly.

 

I made a class override for PS1.5 based on your code - you can overwrite prestashop/override/classes/Customer.php with that code instead of editing core files.

 

(...)

 

EDIT: Forgot to mention - I've renamed legacy passwords table name to osc_legacy_passwords so you'll probably have to rename it (either table name in DB or hardcoded in script).

 

Awesome, man! Didn't test it yet but it looks all good. Thanks a lot!

Link to comment
Share on other sites

Hello,

 

Excellent contribution!

 

I'm moving over from CubeCart v4 to Prestashop 1.5 and need a little help adapting this method for use.

 

CC stores the md5 password and a 6 digit salt in seperate table columns.

 

I guessed I'd have to add the salt column to the legacy table and somehow modify the two parts of code below:

 

$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `zc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

 

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

 

So far I've not had much luck.

 

Is anyone able to help please?

 

Thanks,

 

Steve

Link to comment
Share on other sites

I'm moving over from CubeCart v4 to Prestashop 1.5 and need a little help adapting this method for use.

 

CC stores the md5 password and a 6 digit salt in seperate table columns.

 

I guessed I'd have to add the salt column to the legacy table and somehow modify the two parts of code below:

 

(...)

 

So far I've not had much luck.

 

Is anyone able to help please?

 

Hi, Steve!

 

It looks pretty straightforward. All you should do is to concatenate both fields (password and salt) and then remove the substr() method from the equation. You could save the salt in a field called 'salt' on your legacy table and then retrieve both password and salt.

 

Do you know if the salt goes on the begining or the end of the string?

 

João Cunha

Edited by João Cunha (see edit history)
Link to comment
Share on other sites

Thanks for the quick reply.

 

I've searched around and I think the salt is before the password.

 

I've tried the below, am I going in the right direction?

 

$resultZC = Db::getInstance()->getRow('
SELECT `password`, `salt`
FROM `cc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

 

and

 

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = $resultZC['salt'];
$ZCpassword = md5($salt . $passwd);

 

Edit: meant to say I added a 'salt' column to the cc_legacy_passwords table.

Edited by SWS19 (see edit history)
Link to comment
Share on other sites

Still struggling concatenate both fields.

 

There's a snippet of CubeCart code below on how it puts the salt and pass together:

 

$pass_hash = md5(md5($salt).md5($pass));

 

Not sure if that helps anyone help me.

 

Thanks,

 

Steve

Link to comment
Share on other sites

  • 2 months later...

Did you get to move the password database from cubecart to prestashop?

 

I'm having the same trouble.

 

 

Still struggling concatenate both fields.

 

There's a snippet of CubeCart code below on how it puts the salt and pass together:

 

$pass_hash = md5(md5($salt).md5($pass));

 

Not sure if that helps anyone help me.

 

Thanks,

 

Steve

Link to comment
Share on other sites

  • 2 months later...

Thanks for posting solution to this issue, it's working fine with PS1.5 as well. I found a little typo in your manual - missing "d" in DB table creation causes problems in queries further:

 

 

 

I made a class override for PS1.5 based on your code - you can overwrite prestashop/override/classes/Customer.php with that code instead of editing core files.

 

<?php

Snipped to save space

}

 

EDIT: Forgot to mention - I've renamed legacy passwords table name to osc_legacy_passwords so you'll probably have to rename it (either table name in DB or hardcoded in script).

 

 

Thanks for that. I was beginning to think we would have to get our existing clients to generate new accounts. Although it would be nice to be able to import their addresses and previous order data as well.

Link to comment
Share on other sites

  • 4 weeks later...

For CubeCart follow Joao's original (and great!) instructions with the below modifications:

 

We need to add an additional salt column into our legacy database table as below:

 

CREATE TABLE cc_legacy_passwords (
 id INT NOT NULL,
 PRIMARY KEY(id),
 email VARCHAR(100),
 password VARCHAR(32),
 salt VARCHAR(6),
 updated BOOLEAN NOT NULL
);

 

Next I've modified the code so that encrypts in the CubeCart format (it will concatenate the password and salt before checking if it's valid).

I've also added a snippet of code to generate a random secure key for the customer upon their return and login.

 

<?php
class Customer extends CustomerCore
{
public function getByEmail($email, $passwd = null)
{
 if (!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd)))
  die (Tools::displayError());
 $sql = 'SELECT *
FROM `'._DB_PREFIX_.'customer`
WHERE `email` = \''.pSQL($email).'\'
 '.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
 '.(isset($passwd) ? 'AND `passwd` = \''.Tools::encrypt($passwd).'\'' : '').'
 AND `deleted` = 0
 AND `is_guest` = 0';
 $result = Db::getInstance()->getRow($sql);
// == BEGIN CubeCart TO PRESTASHOP PASSWORD INTEGRATION ==
// == BY João Cunha - [email protected]
// == @ 31/03/2012
// == Updated for CubeCart by tinyDev
// == @ 12/01/2013
// == USE AND MODIFY AT WILL
// == TESTED ON PRESTASHOP V1.5.3.X
if (!$result) { //<- INVALID PRESTASHOP LOGIN, IT MAY BE A CubeCart PASSWORD
//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`, `salt`
FROM `cc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');
if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN
//ENCRYPTS THE GIVEN PASSWORD IN CubeCart FORMAT
$salt = $resultZC['salt'];
$ZCpassword = md5(md5($salt).md5($passwd));
if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG CubeCart PASSWORD GIVEN
//WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD
Db::getInstance()->Execute('
					UPDATE `'._DB_PREFIX_   .'customer`
					SET `passwd` = \''.md5(pSQL(_COOKIE_KEY_.$passwd)).'\'
					WHERE `email` = \''.pSQL($email).'\'');

//SET RANDOM SECURE_KEY [ADDED BY tinyDev]
Db::getInstance()->Execute('
					UPDATE `'._DB_PREFIX_   .'customer`
					SET `secure_key` = \''.md5(uniqid(rand(), true)).'\'
					WHERE `email` = \''.pSQL($email).'\' AND `secure_key` = \''.pSQL($secure_key['']).'\'');
//...AND FLAG IT AS UPDATED, SO THE NEXT TIME HE LOGS IN, HE WON'T ENTER THIS ROUTINE.
Db::getInstance()->Execute('
					UPDATE `cc_legacy_passwords`
					SET `updated` = 1
					WHERE `email` = \''.pSQL($email).'\'');
//USER IS AUTHENTICATED, OVERWRITE THE EMPTY $result VARIABLE
$result = Db::getInstance()->getRow('
SELECT *
FROM `'._DB_PREFIX_ .'customer`
WHERE `active` = 1
AND `email` = \''.pSQL($email).'\'
AND `deleted` = 0
AND `is_guest` = 0');
}
// == END CubeCart TO PRESTASHOP PASSWORD INTEGRATION


 $this->id = $result['id_customer'];
 foreach ($result as $key => $value)
  if (key_exists($key, $this))
$this->{$key} = $value;
 return $this;
}
}

 

Hope that helps others.

 

tinyDev

Edited by tinyDev (see edit history)
Link to comment
Share on other sites

  • 1 month later...

This modification also works on older versions of Prestashop. There's just one small part of code to be removed, because this column (is_guest) doesn't exist in older versions.

 

Just change the following code:

 

AND `deleted` = 0
AND `is_guest` = 0');

 

Into:

AND `deleted` = 0');

 

That's all.

Edited by timonia (see edit history)
Link to comment
Share on other sites

  • 8 months later...

Thanks for posting solution to this issue, it's working fine with PS1.5 as well. I found a little typo in your manual - missing "d" in DB table creation causes problems in queries further:

 

 

 

I made a class override for PS1.5 based on your code - you can overwrite prestashop/override/classes/Customer.php with that code instead of editing core files.

 

<?php

class Customer extends CustomerCore
{
public function getByEmail($email, $passwd = null) {
if (!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd)))
die (Tools::displayError());

$sql = 'SELECT *
FROM `'._DB_PREFIX_.'customer`
WHERE `email` = \''.pSQL($email).'\'
'.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
'.(isset($passwd) ? 'AND `passwd` = \''.Tools::encrypt($passwd).'\'' : '').'
AND `deleted` = 0
AND `is_guest` = 0';
$result = Db::getInstance()->getRow($sql);

// == BEGIN ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
// == BY João Cunha - [email protected]
// == @ 31/03/2012
// == USE AND MODIFY AT WILL
// == TESTED ON PRESTASHOP V1.4.7X
if (!$result) { //<- INVALID PRESTASHOP LOGIN, IT MAY BE A ZEN-CART / OSCOMMERCE PASSWORD
//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `osc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN

//WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
Db::getInstance()->Execute('
UPDATE `'._DB_PREFIX_ .'customer`
SET `passwd` = \''.md5(pSQL(_COOKIE_KEY_.$passwd)).'\'
WHERE `email` = \''.pSQL($email).'\'');

//...AND FLAG IT AS UPDATED, SO THE NEXT TIME HE LOGS IN, HE WON'T ENTER THIS ROUTINE.
Db::getInstance()->Execute('
UPDATE `osc_legacy_passwords`
SET `updated` = 1
WHERE `email` = \''.pSQL($email).'\'');

//USER IS AUTHENTICATED, OVERWRITE THE EMPTY $result VARIABLE
$result = Db::getInstance()->getRow('
SELECT *
FROM `'._DB_PREFIX_ .'customer`
WHERE `active` = 1
AND `email` = \''.pSQL($email).'\'
AND `deleted` = 0
AND `is_guest` = 0');
}
// == END ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION

$this->id = $result['id_customer'];
foreach ($result as $key => $value)
if (key_exists($key, $this))
$this->{$key} = $value;

return $this;
}
}
EDIT: Forgot to mention - I've renamed legacy passwords table name to osc_legacy_passwords so you'll probably have to rename it (either table name in DB or hardcoded in script).

 

 

First of all thanks for this code, I thought that I have found a solution to my passwords problem (I'm migrating from Oscommerce to Prestashop) BUT I'm afraid that something is wrong, I have followed your instructions but it doesn't work for me, I get this error:

"There is 1 error - Authentication failed" Seems like it's not checking the new osc_legacy_passwords table ...

 

I'm using PrestaShop 1.5.6.2 version

 

I created the new table using:

CREATE TABLE osc_legacy_passwords (

id INT NOT NULL,

PRIMARY KEY(id),

email VARCHAR(100),

password VARCHAR(35),

updated BOOLEAN NOT NULL

);

 

And a new customer class (Customer.php) in override folder with speed3r code

 

I have to say that I don't have a clue of Php, so any help is welcome.

 

Thanks in advance.

 

Link to comment
Share on other sites

  • 3 weeks later...

Hello guys,

 

I have the same problem as Jota. When I install the override Customer.php it seems like the store is ignoring the new table with the old oscommerce passwords. Btw. My Prestashopversion is 1.5.6.1

 

When I change the corefile /classes/Customer.php like Joao Cunha described it, it is working. But of course it would be better to use a overridefile. So what could be the reason? What do we have to change?

 

Matt

Edited by Afriluka (see edit history)
Link to comment
Share on other sites

Hello guys,

 

I have the same problem as Jota. When I install the override Customer.php it seems like the store is ignoring the new table with the old oscommerce passwords. Btw. My Prestashopversion is 1.5.6.1

 

When I change the corefile /classes/Customer.php like Joao Cunha described it, it is working. But of course it would be better to use a overridefile. So what could be the reason? What do we have to change?

 

Matt

Hi Matt, after going crazy with this, and many hours of time lost, I finally discovered that  the solution was extremely easy (http://www.prestashop.com/forums/topic/238197-solved-overrides-not-working-anymore-in-154/)... when you place something in override folder you have to delete the file "class_index.php" in cache folder. After doing that it works like a charm. (I did a security back up before deleting just in case)

 

Hope this helps.

 

Kind regards.

 

Jon.

Link to comment
Share on other sites

  • 2 months later...
  • 5 months later...

Thanks fo all,

 

This solution work fine for me with Oscommerce 2.x and prestashop 1.5.x  (solution João) and work fine too with overide classe other solution.

I test it with success

 

For an other projetc, i must migrate Oscommerce 2.x to prestashop 1.6.0.9

Any idea too help me for coding solution ?

 

  Best regard,

       Eric

Link to comment
Share on other sites

  • 3 months later...
  • 1 month later...

Hello, I took an inspiration from the code here. I tried it with osCommerce 2.3.4 and it didn't work. Passwords in osC 2.3.4 are stored in newer format $P$md5hash without :salt.

So I took the code from here, code from osC for password manipulation and combined them to one. Copy the code and store it to prestashop/override/classes/Customer.php. Don't forget to remove prestashop/cache/class_index.php, otherwise this new Customer class won't be found and used.

 

I don't use support table for legacy osC account. I have osC passwords in PrestaShop customers table. When PrestaShop password fails, I try to authenticate with osC password. If it succeed then I update the password to PrestaShop and reauthenticate with PrestaShop password to proceed.

<?php

class Customer extends CustomerCore {

	public function getByEmail($email, $passwd = null) {
		
		if(!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd)))
			die(Tools::displayError());
		
		$db = Db::getInstance();
		
		$sql = 'SELECT *
				FROM `' . _DB_PREFIX_ . 'customer`
				WHERE `email` = \'' . pSQL($email) . '\'
				' . Shop::addSqlRestriction(Shop::SHARE_CUSTOMER) . '
				' . (isset($passwd) ? 'AND `passwd` = \'' . Tools::encrypt($passwd) . '\'' : '') . '
				AND `deleted` = 0
				'.($ignore_guest ? ' AND `is_guest` = 0' : '');
		$result = $db->getRow($sql);
		
		// == BEGIN OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
		// == BY Martin Edlman - [email protected]
		// == @ 27/2/2014
		// == USE AND MODIFY AT WILL
		// == TESTED ON PRESTASHOP V1.6.X
		if(! $result) { // <- INVALID PRESTASHOP LOGIN, IT MAY BE AN OSCOMMERCE PASSWORD
			$resultOSC = $db->getRow('
				SELECT `passwd`
				FROM `' . _DB_PREFIX_ . 'customer`
				WHERE `email` = \'' . pSQL($email) . '\'
				' . Shop::addSqlRestriction(Shop::SHARE_CUSTOMER) . '
				AND `deleted` = 0
				'.($ignore_guest ? ' AND `is_guest` = 0' : ''));
			
			if(! $resultOSC)
				return false; // <- EMAIL NOT FOUND, SO IT IS AN INVALID LOGIN

			if(! OSCPassword::check($passwd, $resultOSC['passwd']))
				return false; // <- WRONG OSCOMMERCE PASSWORD GIVEN
			
			// WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
			$db->Execute('
			 UPDATE `' . _DB_PREFIX_ . 'customer`
				SET `passwd` = \'' . md5(pSQL(_COOKIE_KEY_ . $passwd)) . '\'
				WHERE `email` = \'' . pSQL($email) . '\'');
			
			// REUSE ORIGINAL SQL TO AUTHENTICATE WITH UPDATED PRESTASHOP PASSWORD
			$result = $db->getRow($sql);
		}
		// == END OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION
		
		$this->id = $result['id_customer'];
		foreach($result as $key => $value)
			if(key_exists($key, $this))
				$this->{$key} = $value;
		
		return $this;
	}
	
}


class OSCPassword {

	private static $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

	private static function encode64($input, $count) {
		$output = '';
		$i = 0;
		do {
			$value = ord($input[$i++]);
			$output .= self::$itoa64[$value & 0x3f];
			if($i < $count)
				$value |= ord($input[$i]) << 8;
			$output .= self::$itoa64[($value >> 6) & 0x3f];
			if($i++ >= $count)
				break;
			if($i < $count)
				$value |= ord($input[$i]) << 16;
			$output .= self::$itoa64[($value >> 12) & 0x3f];
			if($i++ >= $count)
				break;
			$output .= self::$itoa64[($value >> 18) & 0x3f];
		} while($i < $count);
		
		return $output;
	}

	private static function crypt($password, $setting) {
		$output = '*0';
		if(substr($setting, 0, 2) == $output)
			$output = '*1';
		
		$id = substr($setting, 0, 3);
		// We use "$P$", phpBB3 uses "$H$" for the same thing
		if($id != '$P$' && $id != '$H$')
			return $output;
		
		$count_log2 = strpos(self::$itoa64, $setting[3]);
		if($count_log2 < 7 || $count_log2 > 30)
			return $output;
		
		$count = 1 << $count_log2;
		
		$salt = substr($setting, 4, 8);
		if(strlen($salt) != 8)
			return $output;
			
			// We're kind of forced to use MD5 here since it's the only
			// cryptographic primitive available in all versions of PHP
			// currently in use. To implement our own low-level crypto
			// in PHP would result in much worse performance and
			// consequently in lower iteration counts and hashes that are
			// quicker to crack (by non-PHP code).
		if(PHP_VERSION >= '5') {
			$hash = md5($salt . $password, TRUE);
			do {
				$hash = md5($hash . $password, TRUE);
			} while(--$count);
		} else {
			$hash = pack('H*', md5($salt . $password));
			do {
				$hash = pack('H*', md5($hash . $password));
			} while(--$count);
		}
		
		$output = substr($setting, 0, 12);
		$output .= self::encode64($hash, 16);
		
		return $output;
	}

	public static function check($password, $stored_hash) {
		$hash = self::crypt($password, $stored_hash);
		if($hash[0] == '*')
			$hash = crypt($password, $stored_hash);

		// PrestaShop has varchar(32) for password
		return substr($hash, 0, 32) == $stored_hash;
	}

}

?>

I hope this will help someone.

 

Regards Martin

  • Like 1
Link to comment
Share on other sites

  • 1 month later...
  • 1 month later...

Hi there! This is my first contribution to the community. I hope it helps someone.

 

I would like to share my approach on how to integrate Zen-Cart / OSCommerce passwords with Prestashop. I have a Zen-Cart shop with 50k registered customers which I am migrating to Prestashop. The "Back Office -> Tools -> CSV Import" tool works like a charm to import your customers but they will not be able to login on Prestashop because passwords are encrypted in different ways on both store managers.

 

 

Thank you!

It worked well in PS 1.6.14

Link to comment
Share on other sites

Hi. I've tried this with a Prestashop 1.6.14 and the original solution by Joao Cunha works fine. I don't understand why, but the override solution doesn't work. It seems prestashop is not accessing the override file Customer.php. File permissions are -rw-r--rw-, shouldn't it work?

 

Thanks Joao and speed3r

Link to comment
Share on other sites

Hi again. I found out why the override solution didn't work for me in my Prestashop 1.6.14. In order to make the override solution to work you must delete:

 

./prestashop/cache/class_index.php

 

And since getByEmail headers have changed from 1.5 till 1.6.14, the override file for 1.6.14 should contain this:

<?php

class Customer extends CustomerCore
{

	public function getByEmail($email, $passwd = null, $ignore_guest = true)
	{
		if (!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd)))
			die (Tools::displayError());

		$result = Db::getInstance()->getRow('
		SELECT *
		FROM `'._DB_PREFIX_.'customer`
		WHERE `email` = \''.pSQL($email).'\'
		'.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
		'.(isset($passwd) ? 'AND `passwd` = \''.pSQL(Tools::encrypt($passwd)).'\'' : '').'
		AND `deleted` = 0
		'.($ignore_guest ? ' AND `is_guest` = 0' : ''));

		// == BEGIN ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
		// == BY João Cunha - [email protected]
		// == @ 31/03/2012
		// == USE AND MODIFY AT WILL
		// == TESTED ON PRESTASHOP V1.4.7X
		if (!$result) { //<- INVALID PRESTASHOP LOGIN, IT MAY BE A ZEN-CART / OSCOMMERCE PASSWORD
			//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
			$resultZC = Db::getInstance()->getRow('
			SELECT `password`
			FROM `zc_legacy_passwords`
			WHERE `email` = \''.pSQL($email).'\'
			AND `updated` = 0');

			if (!$resultZC)
				return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

			//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
			$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
			$ZCpassword = md5($salt . $passwd) . ':' . $salt;

			if ($ZCpassword != $resultZC['password'])
				return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN

			//WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
			Db::getInstance()->Execute('
				UPDATE `'._DB_PREFIX_	.'customer`
				SET `passwd` = \''.md5(pSQL(_COOKIE_KEY_.$passwd)).'\'
				WHERE `email` = \''.pSQL($email).'\'');

			//...AND FLAG IT AS UPDATED, SO THE NEXT TIME HE LOGS IN, HE WON'T ENTER THIS ROUTINE.
			Db::getInstance()->Execute('
				UPDATE `zc_legacy_passwords`
				SET `updated` = 1
				WHERE `email` = \''.pSQL($email).'\'');

			//USER IS AUTHENTICATED, OVERWRITE THE EMPTY $result VARIABLE
			$result = Db::getInstance()->getRow('
				SELECT *
				FROM `'._DB_PREFIX_ .'customer`
				WHERE `active` = 1
				AND `email` = \''.pSQL($email).'\'
				AND `deleted` = 0
				AND `is_guest` = 0');
		}
		// == END ZEN-CART / OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION

		$this->id = $result['id_customer'];
		foreach ($result as $key => $value)
			if (array_key_exists($key, $this))
				$this->{$key} = $value;

		return $this;
	}

}

I hope this helps.

 

Kind regards.

Edited by serpeal79 (see edit history)
  • Like 2
Link to comment
Share on other sites

  • 3 months later...
  • 1 month later...
  • 4 months later...
  • 8 months later...

Thanks for the fix and I'm glad it worked for many of you. Unfortunately it doest work with oscommerce 2.3.1 and the latest prestashop. I've tried Martins code also but no luck :(

Rob

It works, I have operated oscommerce from version 2.3 through 2.3.3.4 and all my test accounts from various versions of osc worked. I used eldman code but I had to upgrade it since his code is not for presta 1.6.1.10. Also if you use eldman solution you cant import passwords via prestashop CSV function (other data can), need to use phpmyadmin/sql query.

code for prsta v. 1.6.1.10 override/Customer.php:

<?php

class Customer extends CustomerCore
{
     public function getByEmail($email, $passwd = null, $ignore_guest = true)
    {
        if (!Validate::isEmail($email) || ($passwd && !Validate::isPasswd($passwd))) {
            die(Tools::displayError());
        }

        $result = Db::getInstance()->getRow('
		SELECT *
		FROM `'._DB_PREFIX_.'customer`
		WHERE `email` = \''.pSQL($email).'\'
		'.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
		'.(isset($passwd) ? 'AND `passwd` = \''.pSQL(Tools::encrypt($passwd)).'\'' : '').'
		AND `deleted` = 0
		'.($ignore_guest ? ' AND `is_guest` = 0' : ''));


		
		// == BEGIN OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION ==
		// == BY Martin Edlman - [email protected]
		// == @ 27/2/2014
		// == USE AND MODIFY AT WILL
		// == TESTED ON PRESTASHOP V1.6.X
		if(! $result) { // <- INVALID PRESTASHOP LOGIN, IT MAY BE AN OSCOMMERCE PASSWORD
			$resultOSC = Db::getInstance()->getRow('
				SELECT `passwd`
				FROM `' . _DB_PREFIX_ . 'customer`
				WHERE `email` = \'' . pSQL($email) . '\'
				' . Shop::addSqlRestriction(Shop::SHARE_CUSTOMER) . '
				AND `deleted` = 0
				'.($ignore_guest ? ' AND `is_guest` = 0' : ''));

			if(! $resultOSC)
			
				return false; // <- EMAIL NOT FOUND, SO IT IS AN INVALID LOGIN

			if(! OSCPassword::check($passwd, $resultOSC['passwd']))
				return false; // <- WRONG OSCOMMERCE PASSWORD GIVEN
			
			// WE'LL UPDATE THE CUSTOMER TABLE WITH ITS PRESTASHOP ENCRYPTED PASSWORD...
			Db::getInstance()->Execute('
			 UPDATE `' . _DB_PREFIX_ . 'customer`
				SET `passwd` = \'' . md5(pSQL(_COOKIE_KEY_ . $passwd)) . '\'
				WHERE `email` = \'' . pSQL($email) . '\'');
			
			// REUSE ORIGINAL SQL TO AUTHENTICATE WITH UPDATED PRESTASHOP PASSWORD
			$result = Db::getInstance()->getRow('
			SELECT *
			FROM `'._DB_PREFIX_.'customer`
			WHERE `email` = \''.pSQL($email).'\'
			'.Shop::addSqlRestriction(Shop::SHARE_CUSTOMER).'
			'.(isset($passwd) ? 'AND `passwd` = \''.pSQL(Tools::encrypt($passwd)).'\'' : '').'
			AND `deleted` = 0
			'.($ignore_guest ? ' AND `is_guest` = 0' : ''));
			if(! $result) { 
				return false; //incase our password rewrite does not match prestashop authentication
			}
		}
		// == END OSCOMMERCE TO PRESTASHOP PASSWORD INTEGRATION
		
        $this->id = $result['id_customer'];
        foreach ($result as $key => $value) {
            if (property_exists($this, $key)) {
                $this->{$key} = $value;
            }
        }
        return $this;
    }
}

class OSCPassword {

	private static $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

	private static function encode64($input, $count) {
		$output = '';
		$i = 0;
		do {
			$value = ord($input[$i++]);
			$output .= self::$itoa64[$value & 0x3f];
			if($i < $count)
				$value |= ord($input[$i]) << 8;
			$output .= self::$itoa64[($value >> 6) & 0x3f];
			if($i++ >= $count)
				break;
			if($i < $count)
				$value |= ord($input[$i]) << 16;
			$output .= self::$itoa64[($value >> 12) & 0x3f];
			if($i++ >= $count)
				break;
			$output .= self::$itoa64[($value >> 18) & 0x3f];
		} while($i < $count);
		
		return $output;
	}

	private static function crypt($password, $setting) {
				
		$output = '*0';
		if(substr($setting, 0, 2) == $output)
			$output = '*1';
		
		$id = substr($setting, 0, 3);
		// We use "$P$", phpBB3 uses "$H$" for the same thing
		if($id != '$P$' && $id != '$H$')
			return $output;
			
		$count_log2 = strpos(self::$itoa64, $setting[3]);
		if($count_log2 < 7 || $count_log2 > 30)
			return $output;
	
		$count = 1 << $count_log2;
		
		$salt = substr($setting, 4, 8);
		if(strlen($salt) != 8)
			return $output;
			
			// We're kind of forced to use MD5 here since it's the only
			// cryptographic primitive available in all versions of PHP
			// currently in use. To implement our own low-level crypto
			// in PHP would result in much worse performance and
			// consequently in lower iteration counts and hashes that are
			// quicker to crack (by non-PHP code).
		if(PHP_VERSION >= '5') {
			$hash = md5($salt . $password, TRUE);
			do {
				$hash = md5($hash . $password, TRUE);
			} while(--$count);
		} else {
			$hash = pack('H*', md5($salt . $password));
			do {
				$hash = pack('H*', md5($hash . $password));
			} while(--$count);
		}
		
		$output = substr($setting, 0, 12);
		$output .= self::encode64($hash, 16);
		
		return $output;
	}

	public static function check($password, $stored_hash) {
		$hash = self::crypt($password, $stored_hash);
		
		if($hash[0] == '*')
			$hash = crypt($password, $stored_hash);

		// PrestaShop has varchar(32) for password
		return substr($hash, 0, 32) == $stored_hash;
	}

}

?>
Link to comment
Share on other sites

Hello tarmogr, thank you for sharing your code.

I'm trying to migrate customers from magento to prestashop 1.6.1.7.

Where should I add ''class OSCPassword''? In Customer.php as well? I'm having some issues with your code :/

''old'' magento passwords still have the salt suffix.Should I create a support/legacy table?

thank you

Edited by Matte01990 (see edit history)
Link to comment
Share on other sites

Hello Matte

 

If you use the same code as I did, there is no need for separate table.

 

You should copy the whole code above to the override/Customers.php file

You then need to modify the class OSCPassword class according to magento algorithm. I used print_r($some_variable); to debug the code and see contents of variables.

Link to comment
Share on other sites

  • 1 year later...
  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...