/** * Converts non Magento import file into currect Magento import file. * Show warnings if file cant be converted due to incorrect import data. * Use output buffering if you would like to catch all messages in this method * * @param int $attribute_set_id Magento's attribute set id * @param array $file_path An information array of uploaded file, receved * directly from $_FILES array * @param int $rows_per_file Split import result file into several ones, * which should contain not more than $rows_per_file products * @param string $category_ids Magento's identifiers of categories, to which * imported products should belong * @param string $import_action The type of import action: add or update * product information * @param bool $out_of_stock Add "out of stock" status for products * @param bool $add_images Auto generate pathes to product images * @param array $exclude_sku_list The list of products that should not be * involved into convertion even if they mentioned in $file_path file. * It is an element of $_FILES array. * @param string $import_language The language of product information * @param bool $attribytes_by_groups Magento's attributes are splited into groups. * If you would like to use this feature then use **Attribute_group_name * column name in the importing file to specify group name * @param array $name_manuf_fix Add manufacturer name to the resulting SKU * * @throws Exception Throws an exception if something critical happens, * should be catched for informative purposes only. * * @return string Path to the zip compressed csv file */ public static function convertForImport($attribute_set_id, $file_path, $rows_per_file = 50, $category_ids = '', $import_action = self::UPDATE_ACTION, $out_of_stock = false, $add_images = false, $exclude_sku_list = null, $import_language = 'EN', $attribytes_by_groups = true, $name_manuf_fix = array()) { global $STOCKS; $db =& DB::singleton(); $tmp_file_name = ''; if (is_array($file_path)) { if ($file_path['type'] == 'text/csv') { //use csv file as is $file_path = $file_path['tmp_name']; } else { if ($file_path['type'] == 'application/vnd.ms-excel' || $file_path['type'] == 'application/msexcel') { //convert xls file to csv if (filesize($file_path['tmp_name'])) { $tmp_file_name = tempnam('/tmp', 'xls2csv_prodict_import_'); $additional_conf = ''; $res = shell_exec('export LANG=en_US.UTF-8 && xls2csv -dUTF-8 -q3 -c, -x ' . $additional_conf . $file_path['tmp_name'] . ' > ' . $tmp_file_name); $file_path = $tmp_file_name; } else { throw new Exception('Empty file.'); } } else { throw new Exception('Incorrect file.'); } } } if (filesize($file_path)) { $fp = fopen($file_path, 'r'); if ($fp) { $exclude_skus = array(); if (!is_null($exclude_sku_list)) { // get excluding SKUs to array $exclude_skus = file($exclude_sku_list['tmp_name'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES | FILE_TEXT); } //get all magento attribute sets $attribute_sets = Product::getAttributeSets(); $dir_name = PROJECT_HOME . '/dl/' . self::trans(mb_strtolower($attribute_sets[$attribute_set_id])) . '_' . date('d.m.y-H.i.s'); if (@mkdir($dir_name)) { // main conversion logic starts here try { $column_names = array(); // relation between the magento attributes and columns in importing file $column_names_from_file = fgetcsv($fp, 0, ',', '"'); // column names that present in importing file $column_names_from_file_count = count($column_names_from_file); $cur_column_name = ''; $not_found_columns = array(); require_once MAGE_DIR . '/app/Mage.php'; $storeId = 0; // get attributes for specified attribute set $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); $attrs = Mage::getResourceModel('catalog/product_attribute_collection')->setAttributeSetFilter($attribute_set_id)->addVisibleFilter()->checkConfigurableProducts(); $attrs->getSelect()->joinLeft('eav_attribute_group', 'entity_attribute.attribute_group_id = eav_attribute_group.attribute_group_id', 'eav_attribute_group.attribute_group_name'); $attrs = $attrs->load(); $attrs_group = array(); $attributes = array(); $attributes_types = array(); $select_values = array(); foreach ($attrs as $attr) { if (!isset($attrs_group[$attr->getAttributeGroupName()])) { $attrs_group[$attr->getAttributeGroupName()] = array(); } $code = $attr->getAttributeCode(); $label = $attr->getFrontendLabel(); $attrs_group[$attr->getAttributeGroupName()][$label] = $code; $attributes[$label] = $code; $attr_type = $attr->getFrontendInput(); $attributes_types[$code] = $attr_type; if ($attr_type == 'select' || $attr_type == 'multiselect') { $select_values[$code] = array(); $optionCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')->setAttributeFilter($attr->getAttributeId())->setPositionOrder('desc', true)->load(); foreach ($optionCollection as $option) { $select_values[$code][] = $option->getValue(); } } } //unset $attrs, because it can be heavy weight unset($attrs); // fill the $column_names array if ($attribytes_by_groups) { $cur_group = ''; for ($i = 0; $i < $column_names_from_file_count; $i++) { if (substr($column_names_from_file[$i], 0, 2) == '**' && substr($column_names_from_file[$i], 0, -2)) { $cur_group = substr($column_names_from_file[$i], 2, strlen($column_names_from_file[$i]) - 4); continue; } if ($cur_group) { $cur_column_name = ''; if (isset($attrs_group[$cur_group]) && isset($attrs_group[$cur_group][$column_names_from_file[$i]])) { //column name found by attribute code $column_names[$attrs_group[$cur_group][$column_names_from_file[$i]]] = $i; } else { if (isset($attrs_group[$cur_group]) && in_array($column_names_from_file[$i], $attrs_group[$cur_group])) { //column name found by attribute label $column_names[$column_names_from_file[$i]] = $i; } else { $not_found_columns[] = $column_names_from_file[$i]; } } } } } else { for ($i = 0; $i < $column_names_from_file_count; $i++) { $cur_column_name = ''; $cur_column_name = $attributes[$column_names_from_file[$i]]; if (strlen($cur_column_name)) { //column name found by attribute code $column_names[$cur_column_name] = $i; } else { if (in_array($column_names_from_file[$i], $attributes)) { //column name found by attribute label $column_names[$column_names_from_file[$i]] = $i; } else { $not_found_columns[] = $column_names_from_file[$i]; } } } } if (count($not_found_columns)) { echo '<h2>Notfound attributes:</h2><p>' . implode('<br>', $not_found_columns) . '</p>'; } // if 'sku' is not specified, then try to use 'name' if (!isset($column_names['sku']) && isset($column_names['name'])) { $column_names['sku'] = $column_names['name']; if ($import_action == self::UPDATE_ACTION) { unset($column_names['name']); } } if (!isset($column_names['sku'])) { throw new Exception('SKU is important.'); } if (count($name_manuf_fix) && !isset($column_names['manufacturer'])) { throw new Exception('Manufacturer is important.'); } if (count($column_names)) { // $additional_columns - additional attributes with static values for all products $additional_columns = array(); // $dyn_additional_columns - additional attributes with dynamic values, i.e. // calculated while processing each line $dyn_additional_columns = array(); if ($category_ids != 'dummy') { $additional_columns['category_ids'] = $category_ids; } $low_stock_date = gmdate('Y-m-d H:i:s'); if ($out_of_stock) { $additional_columns['qty'] = '0'; $additional_columns['low_stock_date'] = $low_stock_date; $additional_columns['is_in_stock'] = '0'; } else { if (isset($column_names['availability_status'])) { $dyn_additional_columns[] = 'qty'; $dyn_additional_columns[] = 'low_stock_date'; $dyn_additional_columns[] = 'is_in_stock'; } } if ($add_images) { $dyn_additional_columns[] = 'image'; $dyn_additional_columns[] = 'small_image'; $dyn_additional_columns[] = 'thumbnail'; } if ($import_action == self::ADD_ACTION) { $additional_columns['store'] = 'admin'; $additional_columns['websites'] = 'base'; $additional_columns['visibility'] = $GLOBALS['_'][$import_language]['conv4imp']['Каталог, поиск']; $additional_columns['tax_class_id'] = $GLOBALS['_'][$import_language]['conv4imp']['Нет']; $additional_columns['status'] = $GLOBALS['_'][$import_language]['conv4imp']['Включено']; // weight is important, add 1 if nothing specified if (!isset($column_names['weight'])) { $additional_columns['weight'] = '1'; } $additional_columns['type'] = 'simple'; // price is important if (!isset($column_names['price'])) { $additional_columns['price'] = '0'; } $additional_columns['attribute_set'] = $attribute_sets[$attribute_set_id]; $dyn_additional_columns[] = 'url_key'; $dyn_additional_columns[] = 'meta_keyword'; } $short_desc_id = -1; if (isset($column_names['description']) && !isset($column_names['short_description'])) { $desc_id = array_search('description', array_keys($column_names)); $dyn_additional_columns[] = 'short_description'; } $all_column_names = array_merge(array_keys($column_names), array_keys($additional_columns), $dyn_additional_columns); $file_to_write = fopen($dir_name . '/' . basename($dir_name) . '_1.csv', 'w'); fputcsv($file_to_write, $all_column_names, ',', '"'); $row = 0; $cur_row = array(); $sku_id = array_search('sku', array_keys($column_names)); $name_prefx_id = array_search('name_prefix', array_keys($column_names)); $availability_status_id = array_search('availability_status', array_keys($column_names)); $name_id = array_search('name', array_keys($column_names)); $add_update_products_error_skus = array(); // the main loop, which goes through the convertion file while (($data = fgetcsv($fp, 0, ',', '"')) !== false) { $cur_row = array(); // get current row values foreach ($column_names as $column_name => $id) { // check if attribute is 'select' or 'multiselect' // then check the specified value, if it exist in magento if (($attributes_types[$column_name] == 'select' || $attributes_types[$column_name] == 'multiselect') && strlen($data[$id])) { $found = false; for ($i = 0; $i < count($select_values[$column_name]); $i++) { if (mb_strtolower($select_values[$column_name][$i]) == mb_strtolower($data[$id])) { $found = true; $cur_row[] = $select_values[$column_name][$i]; break; } } if (!$found) { printf(INCORRECT_VALUE_FOR_SELECT, $data[$id], $column_name, $row + 1); $cur_row[] = ''; } } else { $cur_row[] = $data[$id]; } switch ($column_name) { // add default description if description is empty, // or remove tags if description is specified case 'description': if (!strlen($cur_row[count($cur_row) - 1])) { $cur_row[count($cur_row) - 1] = NO_DESCRIPTION; } else { $cur_row[count($cur_row) - 1] = strip_tags($cur_row[count($cur_row) - 1]); } break; } } // fix SKU if it is necessary to add manufactirer if (count($name_manuf_fix)) { if ($import_action == self::ADD_ACTION) { if (isset($name_manuf_fix['name']) && $name_id !== false) { $cur_row[$name_id] = strtoupper($data[$column_names['manufacturer']]) . ' ' . $cur_row[$name_id]; } if (isset($name_manuf_fix['sku'])) { $cur_row[$sku_id] = strtoupper($data[$column_names['manufacturer']]) . ' ' . $cur_row[$sku_id]; } } else { if (isset($name_manuf_fix['name'])) { $cur_row[$name_id] = $cur_row[$name_id] . ' ' . $data[$column_names['manufacturer']]; } } } // skip import for this line if SKU is not specified // in most cases it is just empty line if (!strlen($cur_row[$sku_id]) || in_array($cur_row[$sku_id], $exclude_skus)) { echo "cant fine sku in: " . print_r($data, true); continue; } $is_product_exist = Product::isProductExistInShop($cur_row[$sku_id]); // skip this data line if product exist and we trying to add it, // and if product does not exist and we trying to update it. if ($is_product_exist && $import_action == self::ADD_ACTION || !$is_product_exist && $import_action == self::UPDATE_ACTION) { $add_update_products_error_skus[] = $cur_row[$sku_id]; continue; } // add static values for some attributes foreach ($additional_columns as $col_val) { $cur_row[] = $col_val; } // add dynamically generated values for some attributes for ($i = 0; $i < count($dyn_additional_columns); $i++) { switch ($dyn_additional_columns[$i]) { case 'url_key': $cur_row[] = self::trans(mb_strtolower($cur_row[$sku_id]), '-'); break; case 'meta_keyword': $cur_row[] = ($name_prefx_id !== false ? $cur_row[$name_prefx_id] : $attribute_sets[$attribute_set_id]) . ' ' . $cur_row[$sku_id] . META_KEYWORDS; break; case 'image': case 'small_image': case 'thumbnail': $cur_row[] = '/' . self::trans(mb_strtolower($cur_row[$sku_id]), '-') . '.jpg'; break; case 'short_description': $cur_row[] = mb_substr($cur_row[$desc_id], 0, 100); break; case 'qty': if ($cur_row[$availability_status_id] == $STOCKS['in_stock']) { $cur_row[] = DEFAULT_QTY; } else { $cur_row[] = '0'; } break; case 'low_stock_date': if ($cur_row[$availability_status_id] == $STOCKS['in_stock']) { $cur_row[] = ''; } else { $cur_row[] = $low_stock_date; } break; case 'is_in_stock': if ($cur_row[$availability_status_id] == $STOCKS['in_stock']) { $cur_row[] = '1'; } else { $cur_row[] = '0'; } break; } } // write converted data fputcsv($file_to_write, $cur_row, ',', '"'); $row++; // import file splitting is here: if ($row % $rows_per_file == 0) { fclose($file_to_write); $file_to_write = fopen($dir_name . '/' . basename($dir_name) . '_' . ($row / $rows_per_file + 1) . '.csv', 'w'); fputcsv($file_to_write, $all_column_names, ',', '"'); } } // show messages about errors in cenvertion file if (count($add_update_products_error_skus)) { if ($import_action == self::UPDATE_ACTION) { echo NO_GOODS_MESSAGE; } else { if ($import_action == self::ADD_ACTION) { echo GOODS_ARE_IN_DB; } } echo implode('<br/>', $add_update_products_error_skus); } fclose($file_to_write); self::removeTempFiles(); // create the resulting zip archive exec('cd ' . dirname($dir_name) . " && zip -r {$dir_name}.zip " . basename($dir_name) . " && rm -rf {$dir_name}"); $archive_name = basename($dir_name) . '.zip'; } else { throw new Exception("There are no any relations between columns in file and attributes"); } } catch (Exception $e) { exec("rm -rf {$dir_name}"); fclose($fp); //rethrow exception, because it has issue specific message throw $e; } } else { throw new Exception('Cant create temporary dir.'); } fclose($fp); } else { throw new Exception('Cant get access to ' . $file_path); } } else { throw new Exception('Empty file.'); } // remove some trash if (strlen($tmp_file_name)) { unlink($tmp_file_name); } return $archive_name; }
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <?php require_once dirname(__FILE__) . '/menu.php'; require_once dirname(__FILE__) . "/lib/Product.php"; require_once dirname(__FILE__) . "/lib/Converter.php"; try { if (isset($_POST['convert_the_the_file']) && (int) $_POST['attribute_set_id'] > 0 && $_FILES["file_to_convert"]["error"] == UPLOAD_ERR_OK) { $archive_name = Converter::convertForImport((int) $_POST['attribute_set_id'], $_FILES["file_to_convert"], (int) $_POST['rows_per_file'], implode(",", $_POST['category_ids']), $_POST['add_update_products'], isset($_POST['out_of_stock']), isset($_POST['add_images']), strlen($_FILES["exclude_sku_list"]['tmp_name']) ? $_FILES["exclude_sku_list"] : null, $_POST['import_language'], isset($_POST['attribytes_by_groups']), (array) $_POST['manuf_fix']); echo '<h2><a href="/dl/' . $archive_name . '">Готово.</a></h2>'; } } catch (Exception $e) { die($e->getMessage()); } $attribute_sets = Product::getAttributeSets(); $categories = Product::getCategories(); ?> <form action="" method="post" enctype="multipart/form-data"> <table border="0" style="margin: 0 auto;"> <tbody> <tr> <td> <label for="attribute_set_id">Тип: </label> </td> <td> <select name="attribute_set_id" id="attribute_set_id"> <option selected="selected" value="dummy"></option> <?php foreach ($attribute_sets as $attribute_set_id => $attribute_set_name) { echo '<option value="' . $attribute_set_id . '">' . $attribute_set_name . '</option>';