How to export customers from Magento 1 and import them in Magento 2

Vallar Margulis !

Before doing next operations please create files and database backup for Magento 1 and Magento 2.

I would like to tell how i exported customers from magento 1.9.3.2 (next M1) and imported them in magento 2.1.0 (next M2). Actually it’s might be done via native magento tools in both versions.

  1. log in M1 admin panel and go to System->import/export->export->select Customers and press continue button. After it magento will give you CSV file with all your users data.
  2. log in M2 admin panel and go to System->Import->choose Customers and Addresses (single file) and press Check Data button and if evrething is ok then press Import button. If M2 says that your customers don’t have some required fields like “Zip/Postal Code” or “City” – you can delete this rows via Excell and come back later to this customers or you can do this fieds as not required(find this attributes in database in ‘eav_attribute’ table and change 1 to 0 in column ‘is_required’.

When customers were imported there might be an issue like when customers simple can’t login. M2 just refresh login page with no error(actually the error is: ‘Invalid login or password’).  As you might know magento 2 has changed password hashing. In magento 1 password hash looks like this: ’55e9aa7ff7e4b3c81c3e8bbd1acdce8b:yt’ in other words A:B (pay atention for : symbol). In magento 2 password hash has next format: ’55e9aa7ff7e4b3c81c3e8bbd1acdce8b:yt:0′ in other words A:B:C – as you can  see M2 password hash combined from 3 parts. So to fix login issue just need to add third part to password hash. In my case it was adding ‘:0’ to the end of M1 password hash.

To fix that in M2 will help CLI command:

customer:hash:upgrade

The code for this command locating in: vendor/magento/module-customer/Console/Command/UpgradeHashAlgorithmCommand.php function execute line 58.

so i canged this:

if (!$this->encryptor->validateHashVersion($customer->getPasswordHash())) {
    list($hash, $salt, $version) = explode(Encryptor::DELIMITER, $customer->getPasswordHash(), 3);
    $version .= Encryptor::DELIMITER . Encryptor::HASH_VERSION_LATEST;
    $customer->setPasswordHash($this->encryptor->getHash($hash, $salt, $version));
    $customer->save();
    $output->write(".");
}

to this:

if (!$this->encryptor->validateHashVersion($customer->getPasswordHash())) {
    $customer->setPasswordHash($customer->getPasswordHash() . ':0');
    $customer->save();
    $output->write(".");
}

then open terminl and run: customer:hash:upgrade. If this command will tell you something like:

Area code not set: Area code must be set before starting a session.

solution is next:

find vendor/magento/framework/Encryption/Encryptor.php line 109 and change this:

public function __construct(
Random $random,
DeploymentConfig $deploymentConfig
) {
$this->random = $random;

// load all possible keys
$this->keys = preg_split('/\s+/s', trim($deploymentConfig->get(self::PARAM_CRYPT_KEY)));
$this->keyVersion = count($this->keys) - 1;
}

to this:

public function __construct(\Magento\Framework\App\State $state,
Random $random,
DeploymentConfig $deploymentConfig
) {
$state->setAreaCode('frontend');
$this->random = $random;

// load all possible keys
$this->keys = preg_split('/\s+/s', trim($deploymentConfig->get(self::PARAM_CRYPT_KEY)));
$this->keyVersion = count($this->keys) - 1;
}

After that M2 will run encryptor and will change M1 password hashes in M2 password hashes format and you can login in M2 via M1 customer password.

Don’t forget to put evrething back after finish.

Yes, i know about Ubdatamigration tool but their code for converting M1 pass hash in M2 password hash simple didnt nothing with M1 pass hash(it might be too week passwords in M1 which not supporting in M2…for example pass length is 6).

Here is Ubdatamigration  code (maybe someone will make it better):

/**
 * Upgrade customer hash according M2 algorithm versions
 *
 * @param array $recordAttributesData
 * @return array
 */
private function upgradeCustomerHash($recordAttributesData)
{
    if (isset($recordAttributesData['password_hash'])) {
        $hash = $this->explodePasswordHash($recordAttributesData['password_hash']);

        if (strlen($hash[self::PASSWORD_HASH]) == 32) {
            $recordAttributesData['password_hash'] = implode(
                ':',
                [$hash[self::PASSWORD_HASH], $hash[self::PASSWORD_SALT], '0']
            );
        } elseif (strlen($hash[self::PASSWORD_HASH]) == 64) {
            $recordAttributesData['password_hash'] = implode(
                ':',
                [$hash[self::PASSWORD_HASH], $hash[self::PASSWORD_SALT], '1']
            );
        }
    }

    return $recordAttributesData;
}

/**
 * @param string $passwordHash
 * @return array
 */
private function explodePasswordHash($passwordHash)
{
    $explodedPassword = explode(':', $passwordHash, 2);
    $explodedPassword[self::PASSWORD_SALT] = isset($explodedPassword[self::PASSWORD_SALT])
        ? $explodedPassword[self::PASSWORD_SALT]
        : ''
    ;
    return $explodedPassword;
}

my M1 password hashes were not changes because their length was 31…which is not accapteble for any condition in Ubdatamigration code.

Sorry for my english. Ask your questions in comments. Here is my freelancer.com profile to hire me: https://www.freelancer.com/u/rockforweb

Thank’s for reading !