Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gautamkeshri/5a5cfbab74f9ff66a5cfe8c2e436f7d5 to your computer and use it in GitHub Desktop.
Save gautamkeshri/5a5cfbab74f9ff66a5cfe8c2e436f7d5 to your computer and use it in GitHub Desktop.
Import customers into Magento from command line using a CSV file
<?php
define('BUNCH_SIZE_TO_INSERT', 20);
$magentoRootPath = './public';
require_once $magentoRootPath . '/shell/abstract.php';
class CustomerImportFromCsv extends Mage_Shell_Abstract
{
protected $_headerArray = array();
protected $_attributes = array();
protected $_attributeRows = array();
protected $_customFieldNamesEqualsTo;
protected $_nextEntityId;
protected $_entityTypeId;
protected $_passId;
protected $_passTable;
protected $_connection;
protected $_resource;
protected $_table;
protected $_indexValueAttributes = array('group_id');
protected $_defaultValuesForBuiltInImport = array(
'_website' => 'uk',
'group_id' => 1,
'firstname' => ' ',
'middlename' => ' ',
'lastname' => ' ',
'email' => 'default@email.com',
'reward_update_notification' => '1',
'reward_warning_notification' => '1',
);
protected $_defaultValuesForCustomImport = array(
'group_id' => '1',
'store_id' => '1',
'entity_type_id' => '1',
'attribute_set_id' => '0',
'website_id' => '1',
'is_active' => '1',
'email' => 'default@email.com',
);
public function __construct()
{
parent::__construct();
Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);
echo "\n";
$entityType = Mage::getSingleton('eav/config')->getEntityType('customer');
$this->_entityTypeId = $entityType->getEntityTypeId();
$this->_connection = Mage::getSingleton('core/resource')->getConnection('write');
$this->_resource = Mage::getModel('customer/customer');
$this->_table = $this->_resource->getResource()->getEntityTable();
$this->_initAttributes();
if ($this->getArg('h') || $this->getArg('help') || count($this->_args) == 0) {
echo $this->usageHelp();
return 1;
}
$this->behavior = ($this->getArg('b') ? $this->getArg('b') : ($this->getArg('behavior') ? $this->getArg('behavior') : 'replace'));
$this->behavior === true ? $this->behavior = 'replace': '';
$this->_customFieldNamesEqualsTo = $this->getFieldMappings();
}
public function run()
{
if ($filename = $this->getCustomersSourceFile()) {
$files = $this->splitFile($filename, ($this->getArg('l') ? $this->getArg('l') : ($this->getArg('linecount') ? $this->getArg('linecount') : true)));
echo "Start customers '$this->behavior' action from $filename\n";
Mage::log("Start customers '$this->behavior' action from $filename", Zend_Log::DEBUG);
$count = 0;
$files_ = array();
foreach ($files as $file) {
if (empty($this->_customFieldNamesEqualsTo)) {
$count += $this->_importWithBuiltInFunctionality($file);
} else {
$count += $this->_importFromCustomFormattedCsv($file);
}
}
$this->unlinkFiles($files);
$this->unlinkFiles($files_);
echo "\nDone (processed rows count: " . $count . ")\n";
}
}
protected function _initAttributes()
{
$collection = Mage::getResourceModel('customer/attribute_collection')->addSystemHiddenFilterWithPasswordHash();
foreach ($collection as $attribute) {
$this->_attributes[$attribute->getAttributeCode()] = array(
'id' => $attribute->getId(),
'is_required' => $attribute->getIsRequired(),
'is_static' => $attribute->isStatic(),
'rules' => $attribute->getValidateRules() ? unserialize($attribute->getValidateRules()) : null,
'type' => Mage_ImportExport_Model_Import::getAttributeType($attribute),
'options' => $this->getAttributeOptions($attribute)
);
}
return $this;
}
public function getCustomersSourceFile()
{
$option1 = $this->getArg('f');
$option2 = $this->getArg('filename');
if ($option1 || $option2) {
if ($option1 && $option1 != 1) {
if (file_exists($option1)) {
return $option1;
} else {
echo "Skipping customers source file $option1\n";
}
}
if ($option2 && $option2 != 1) {
if (file_exists($option2)) {
return $option2;
} else {
echo "Skipping customers source file $option2\n";
}
}
if ($default = 'customers.csv') {
if (file_exists($default)) {
return $default;
} else {
echo "Skipping default customers source file $default\n";
}
} else {
echo "No default customers source file found in config.xml\n";
}
}
}
public function getFieldMappings()
{
$mappings = array();
$option1 = $this->getArg('m');
$option2 = $this->getArg('map');
if ($option1 || $option2) {
if ($option1 && $option1 != 1) {
parse_str(str_replace(array(',', ' '), array('&', ''), trim($option1)), $mappings);
}
if ($option2 && $option2 != 1) {
parse_str(str_replace(array(',', ' '), array('&', ''), trim($option2)), $mappings);
}
}
return $mappings;
}
public function initCustomersImportModel()
{
$customersimport = Mage::getModel('importexport/import');
$customersimport->setEntity('customer');
$customersimport->setBehavior($this->behavior);
return $customersimport;
}
public function usageHelp()
{
$tmpFolder = substr(
Mage::getConfig()->getOptions()->getTmpDir(),
strlen(Mage::getConfig()->getOptions()->getBaseDir()) + 1
);
return <<<HELP
SYNOPSIS
php -f customerImportFromCsv.php
php -f customerImportFromCsv.php [-- [OPTIONS...]]
DESCRIPTION
This can import customers from CSV file.
Imports:
file.csv: multiple-row csv files, supports multiselect fields
Multiselect fields:
Use commas to separate values, but make sure not to put asterisks in column header, ie:
sku ,*_category ,color
TEST,"CAT1/CAT2,CAT3","red,yellow"
OPTIONS
-h
-help
print this usage and exit
-b
-behavior
set import behavior for csv file: append|delete|replace (default)
-f [file]
-filename [file]
import customers from csv file, if source file not specified or not found uses defined in config.xml
-l <n>
-linecount <n>
split import file into pieces of n lines length ($tmpFolder must be writable)
-m
-map
set custom fields' mapping when you use custom formatted CSV file
EXAMPLES
php -f customerImportFromCsv.php -- -f customers.csv
php -f customerImportFromCsv.php -- -f customers.csv -m "u_email_address=email, u_first_name=firstname, u_last_name=lastname"
HELP;
}
public function splitFile($filename, $linecount)
{
$extension = pathinfo($filename, PATHINFO_EXTENSION);
$count = 0;
$i = 0;
$j = 0;
$files = array();
$h = fopen($filename, 'r');
$header = fgets($h);
$defaultValueIndex = array();
$this->_headerArray = explode(',', trim($header));
foreach (array_keys($this->_defaultValuesForBuiltInImport) as $requiredField) {
if (FALSE !== $indexInHeader = array_search($requiredField, $this->_headerArray)) {
$defaultValueIndex[$requiredField] = $indexInHeader;
} else {
$defaultValueIndex[$requiredField] = count($this->_headerArray);
$this->_headerArray[] = $requiredField;
}
}
$header = implode(',', $this->_headerArray) . "\n";
while ($line = fgets($h)) {
// first iteration / no "attr-only" line / line count has been reached
if ($i == 0 || (substr($line, 0 ,1) != ',' && substr($line, 0 ,2) != '""' && substr($line, 0 ,2) != "''" && $i >= $linecount && !($linecount === true))) {
if (defined('t')) {
fclose($t);
}
$files[] = Mage::getConfig()->getOptions()->getTmpDir() . DS . pathinfo($filename, PATHINFO_FILENAME) . '.tmp.' . $j . '.' . $extension;
$t = fopen($files[$j++], 'w');
fwrite($t, $header);
$i = 0;
}
$line = $this->_convertCsvLineToValid($line, $this->_headerArray) . "\n";
fwrite($t, $line);
$count++;
$i++;
}
fclose($h);
if (defined('t')) {
fclose($t);
}
return $files;
}
public function unlinkFiles($files)
{
foreach ($files as $file) {
unlink($file);
}
}
private function _convertCsvLineToValid($line, $headerArray)
{
$lineArray = explode(',', trim($line));
foreach ($this->_defaultValuesForBuiltInImport as $requiredField => $defaultValue) {
$requiredFieldIndex = array_search($requiredField, $headerArray);
if (empty($lineArray[$requiredFieldIndex])) {
$lineArray[$requiredFieldIndex] = $defaultValue;
}
}
return implode(',', $lineArray);
}
private function _importWithBuiltInFunctionality($file)
{
$count = 0;
$customersimport = $this->initCustomersImportModel();
$validationResult = $customersimport->validateSource($file);
$processedRowsCount = $customersimport->getProcessedRowsCount();
if ($processedRowsCount > 0) {
// get only one field each time to prevent disruption because some line errors
while (!$validationResult) {
echo "\n";
$errorLines = array();
foreach ($customersimport->getErrors() as $type => $lines) {
echo ":::: " . $type . " in line(s) " . implode(", ", $lines) . " ::::\n";
$errorLines = array_merge($errorLines, $lines);
}
echo "\n";
$file_ = str_replace('tmp.', 'tmp._', $file);
$files_[] = $file_;
$h = fopen($file, 'r');
$t = fopen($file_, 'w');
$i = 0;
$error = false;
while ($line = fgets($h)) {
if ((substr($line, 0 ,1) != ',' && substr($line, 0 ,2) != '""' && substr($line, 0 ,2) != "''")) {
$error = false;
}
if (!$error) {
if (!in_array($i, $errorLines)) {
fwrite($t, $line);
} else {
echo ":: Line " . $i . " :: " . $line;
$error = true;
}
}
$i++;
}
fclose($h);
fclose($t);
$customersimport = $this->initCustomersImportModel();
$validationResult = $customersimport->validateSource($file_);
$processedRowsCount = $customersimport->getProcessedRowsCount();
$file = $file_;
}
$count += $processedRowsCount;
$customersimport->importSource();
}
return $count;
}
private function _importFromCustomFormattedCsv($filePath)
{
$count = 0;
$entityRows = $this->_attributeRows = array();
$this->_nextEntityId = Mage::getResourceHelper('importexport')->getNextAutoincrement($this->_table);
$this->_passId = $this->_resource->getAttribute('password_hash')->getId();
$this->_passTable = $this->_resource->getAttribute('password_hash')->getBackend()->getTable();
$file = fopen($filePath, 'r');
$header = fgets($file);
$error = false;
while ($line = fgets($file)) {
if ((substr($line, 0 ,1) != ',' && substr($line, 0 ,2) != '""' && substr($line, 0 ,2) != "''")) {
$error = false;
}
if (!$error) {
$count++;
$entityRows[] = $this->_createEntityArrayFromKnownFields($line);
$this->_loadAttributesFromKnownFields($line);
}
if ($count > 0 && $count % BUNCH_SIZE_TO_INSERT == 0) {
$this->_connection->insertMultiple($this->_table, $entityRows);
$this->_saveCustomerAttributes($this->_attributeRows);
$entityRows = array();
$this->_attributeRows = array();
}
}
fclose($file);
if ($count > 0 && ! empty($entityRows)) {
$this->_connection->insertMultiple($this->_table, $entityRows);
$this->_saveCustomerAttributes($this->_attributeRows);
}
return $count;
}
protected function _saveCustomerAttributes(array $attributesData)
{
foreach ($attributesData as $tableName => $data) {
$tableData = array();
foreach ($data as $customerId => $attrData) {
foreach ($attrData as $attributeId => $value) {
$tableData[] = array(
'entity_id' => $customerId,
'entity_type_id' => $this->_entityTypeId,
'attribute_id' => $attributeId,
'value' => $value
);
}
}
$this->_connection->insertOnDuplicate($tableName, $tableData, array('value'));
}
return $this;
}
private function _createEntityArrayFromKnownFields($line)
{
$row = $tmpRow = array();
$lineArray = explode(',', trim($line));
foreach ($this->_customFieldNamesEqualsTo as $customFieldName => $correspondingFieldName) {
$customFieldIndex = array_search($customFieldName, $this->_headerArray);
$tmpRow[$correspondingFieldName] = $lineArray[$customFieldIndex];
}
foreach ($this->_defaultValuesForCustomImport as $fieldName => $defaultValue) {
$row[$fieldName] = (empty($tmpRow[$fieldName]) || $tmpRow[$fieldName] === "NULL")
? $defaultValue
: $tmpRow[$fieldName];
}
return $row;
}
private function _loadAttributesFromKnownFields($line)
{
$row = $tmpRow = array();
$entityId = $this->_nextEntityId++;
$lineArray = explode(',', trim($line));
foreach ($this->_customFieldNamesEqualsTo as $customFieldName => $correspondingFieldName) {
$customFieldIndex = array_search($customFieldName, $this->_headerArray);
$tmpRow[$correspondingFieldName] = $lineArray[$customFieldIndex];
}
foreach (array_merge($this->_headerArray, array_keys($tmpRow)) as $index => $fieldName) {
if (empty($lineArray[$index])) {
$lineArray[$index] = '';
}
$row[$fieldName] = empty($tmpRow[$fieldName]) ? $lineArray[$index] : $tmpRow[$fieldName];
if ($row[$fieldName] == 'NULL' && array_key_exists($fieldName, $this->_defaultValuesForBuiltInImport)) {
$row[$fieldName] = $this->_defaultValuesForBuiltInImport[$fieldName];
}
}
// attribute values
foreach (array_intersect_key($row, $this->_attributes) as $attrCode => $value) {
if (!$this->_attributes[$attrCode]['is_static'] && strlen($value)) {
/** @var $attribute Mage_Customer_Model_Attribute */
$attribute = $this->_resource->getAttribute($attrCode);
$backModel = $attribute->getBackendModel();
$attrParams = $this->_attributes[$attrCode];
if ('select' == $attrParams['type']) {
$value = $attrParams['options'][strtolower($value)];
} elseif ('datetime' == $attrParams['type']) {
$value = gmstrftime($strftimeFormat, strtotime($value));
} elseif ($backModel) {
$attribute->getBackend()->beforeSave($this->_resource->setData($attrCode, $value));
$value = $this->_resource->getData($attrCode);
}
$this->_attributeRows[$attribute->getBackend()->getTable()][$entityId][$attrParams['id']] = $value;
// restore 'backend_model' to avoid default setting
$attribute->setBackendModel($backModel);
}
}
// password change/set
if (isset($row['password']) && strlen($row['password'])) {
$this->_attributeRows[$this->_passTable][$entityId][$this->_passId] = $this->_resource->hashPassword($row['password']);
}
}
public function getAttributeOptions(Mage_Eav_Model_Entity_Attribute_Abstract $attribute, $indexValAttrs = array())
{
$options = array();
if ($attribute->usesSource()) {
// merge global entity index value attributes
$indexValAttrs = array_merge($indexValAttrs, $this->_indexValueAttributes);
// should attribute has index (option value) instead of a label?
$index = in_array($attribute->getAttributeCode(), $indexValAttrs) ? 'value' : 'label';
// only default (admin) store values used
$attribute->setStoreId(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID);
try {
foreach ($attribute->getSource()->getAllOptions(false) as $option) {
$value = is_array($option['value']) ? $option['value'] : array($option);
foreach ($value as $innerOption) {
if (strlen($innerOption['value'])) { // skip ' -- Please Select -- ' option
$options[strtolower($innerOption[$index])] = $innerOption['value'];
}
}
}
} catch (Exception $e) {
// ignore exceptions connected with source models
}
}
return $options;
}
}
$main = new CustomerImportFromCsv();
$main->run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment