Персональный разработчик Вашего сайта.
Модули. Скрипты. Плагины.

ExcelImportGoods

Импорт товаров из Excel в бд Mysql Modx Revo.

Часто бывает так, что  необходимо заполнить интернет-магазин товарами из Excel через CMS Modx Revo. Вручную это делать долго и нудно. Особенно если каждый товар представляет собой обычную страницу в данной "админке" с кучей дополнительных полей, содержащих характеристики, цену товара и прочее. А если таких товаров тысячи?

Тогда будет разумнее поставить скрипт - модуль, который сгенерирует кнопки для загрузки Excel, да ещё было бы неплохо видеть - какие именно вкладки таблицы можно загрузить. Не стоит забывать и о частых конфликтах кириллицы, расширений (библиотек) PHP и БД.

Ниже выкладываю готовое решение. Плагин импорта товаров из Excel в БД Mysql.

<?php
// Create by Lu Smith
// for Modx Revolution 2.4.0-pl
// My mail - pl.web-master@yandex.ru
// plagin excel_onload_goods inside modx cms
// Загрузка товаров из иксель

//include ('/core/config/config.inc.php');
//$db = mysql_connect('localhost','root','');

date_default_timezone_set('Europe/Moscow');

$db = mysql_connect('localhost','login','password') or die('Не могу соединиться с базой, проверьте пароль, логин, название базы!');
mysql_select_db('name_db', $db);


	set_time_limit(60);
	$uploaddir = 'temp/'; // papka vremennogo hraneniya
	
	// функция транслитерации
	function translit($str, $bool=0) {
	   $mess = Array ( 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'jo', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e-', 'ю' => 'yu', 'я' => 'ya', 'А' => 'a', 'Б' => 'b', 'В' => 'v', 'Г' => 'g', 'Д' => 'd', 'Е' => 'e', 'Ё' => 'jo', 'Ж' => 'zh', 'З' => 'z', 'И' => 'i', 'Й' => 'j', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n', 'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u', 'Ф' => 'f', 'Х' => 'h', 'Ц' => 'c', 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'shch', 'Ъ' => '', 'Ы' => 'y', 'Ь' => '', 'Э' => 'e-', 'Ю' => 'yu', 'Я' => 'ya', ' ' => '-');
	   $c_str = preg_split('/s+/is', $str);
	   $str = trim("$c_str[0] $c_str[1]");   
	   if($bool) {
			$mess = array_flip($mess);
			return $mess[$str]; 
		}
	   $str = preg_replace('/[^a-zА-Яа-яёЁ0-9s-]/is', ' ', strtolower($str));
	   $str = preg_replace('/s+/', ' ', $str);   
	   foreach($mess as $key => $val) {
			$str = preg_replace("/$key/is", $val, $str);
			//$str = preg_replace('/'.ucfirst($key).'/s', ucfirst($val), $str);
	   }
	   return $str;	
	}

// объявляем объект(файл) и работаем с ним 
	
function numsheets($fn){
	if(isset($fn)) {
		include_once 'Classes/PHPExcel/IOFactory.php';
		$objPHPExcel = PHPExcel_IOFactory::load($fn);
		return $objPHPExcel;
	}
}

// превращаем данные из Excel в массив
  function getXLS($obj, $numsheet){
	$objPHPExcel = $obj;
    $objPHPExcel->setActiveSheetIndex($numsheet);
    $aSheet = $objPHPExcel->getActiveSheet();
 
    //этот массив будет содержать массивы содержащие в себе значения ячеек каждой строки
    $array = array();
    //получим итератор строки и пройдемся по нему циклом
    foreach($aSheet->getRowIterator() as $row){
      //получим итератор ячеек текущей строки
      $cellIterator = $row->getCellIterator();
      //пройдемся циклом по ячейкам строки
      //этот массив будет содержать значения каждой отдельной строки
      $item = array();
      foreach($cellIterator as $cell){
        //заносим значения ячеек одной строки в отдельный массив
		
        //array_push($item, iconv('utf-8', 'cp1251', $cell->getCalculatedValue()));
		array_push($item, mb_convert_encoding($cell->getCalculatedValue(), "UTF-8", "auto"));
      }
      //заносим массив со значениями ячеек отдельной строки в "общий массив строк"
      array_push($array, $item);
    }
    return $array;
  }

// удалить файл

if($_POST['delete_file']) {
	unlink($_POST['delete_file']);
	print('<p style="font-weight: bold; color: #0000ff;">Файл '.$_POST['delete_file'].' удалён, перезагрузите страницу.</p>');
}

// загрузка выбранного листа из файла
if(isset($_POST['numsheet'])) {

	$fn = $_POST['objPHPExcel1'];
	$objPHPExcel1 = numsheets($fn);
	$numsheet = $_POST['numsheet'];
	$countsheet = $_POST['alls'];
	$xlsData = getXLS($objPHPExcel1, $numsheet); //извлекаем данные из XLS
	//print_r($xlsData);

	foreach($xlsData as $xlsD_item) {
		if($xlsD_item[0] != '' || $xlsD_item[0] != false) {

			$imya = $xlsD_item[0];
			$imya = $imya;
			$opisanie = $xlsD_item[15];
			$opisanie = iconv('cp1251', 'UTF-8', $opisanie);
			$parentID = $_POST['parentID'];
			//$parentID = '100';
			
			$contentid = mysql_fetch_assoc(mysql_query("SELECT `id` FROM `modx_site_content` WHERE `pagetitle` LIKE '%$imya%' AND `parent` = '$parentID' ORDER BY `id` DESC LIMIT 1"));
			$pagetitleparent = mysql_fetch_assoc(mysql_query("SELECT `pagetitle` FROM `modx_site_content` WHERE `id` = '$parentID'"));
			$pagetitleparent = $pagetitleparent['pagetitle'];
			$pagetitleparentUPCASE = mb_strtoupper($pagetitleparent, "utf-8");
				
			//массив ID дополнительных полей характеристик
			$arrNameTV = array('86', '9', '105', '14', '11', '104', '12', '106', '18', '19', '16', '15', '13', '87');
			
			//подготовка исходного массива к слиянию с  $arrNameTV в ассоциативный массив - обрезаем первые два элемента и последний элемент, добавляем пустой элемент в конец массива $arr_val
			$arr_val = $xlsD_item;
			
			// если необходимо добавление налога на лету, раскомментируйте строки ниже
			/*if($_POST['check_nalog'] == 'yes') {
				$sum = $arr_val[1];
				$nalog = $sum * (0.18);
				$nalog_sum = $sum + $nalog;
				array_shift($arr_val);array_shift($arr_val); array_unshift($arr_val, $nalog_sum); array_pop($arr_val);
			} else {*/
				array_shift($arr_val);array_shift($arr_val); array_pop($arr_val);
			//}
			
			//array_shift($arr_val);array_shift($arr_val); array_pop($arr_val);
			
			if($parentID == '362' || $parentID == '363') {
				array_push($arr_val, $pagetitleparentUPCASE);
			} else {
				array_push($arr_val, '');
			}

			// слияние массивов
			$arr_val_h = array_combine ($arrNameTV, $arr_val);
			
			if ( $contentid['id'] > 0) {
				$ct = 0;
				// обновление описания, мета, ссылки товара
				mysql_query ("UPDATE `modx_site_content` SET `content` = '$opisanie' WHERE `pagetitle` LIKE '%$imya%' AND `parent` = '$parentID'");

				// обновление характеристик товара

				//вписываем характеристики из икселя в соответствующие тв поля
				
				foreach($arr_val_h as $ant_item => $ant_val) {
					if($ant_val != '') {
						mysql_query ("UPDATE `modx_site_tmplvar_contentvalues` SET `value` = '".$ant_val."' WHERE `tmplvarid` = '".$ant_item."' AND `contentid` = '".$contentid['id']."'");
					}
				}	
				$c1++;				
				
			} else {
				$c2 = 0;
				$imya_f = $pagetitleparent.' '.$imya;
				$parentURL = mysql_fetch_assoc(mysql_query("SELECT `uri`, `pagetitle` FROM `modx_site_content` WHERE `id` = '$parentID'"));
				$parentURL = $parentURL['uri'];
				$aliasurl = translit(trim($imya));
				$allurl = $parentURL."/".$aliasurl;
			
				// описание, мета, ссылка нового товара
				mysql_query ("INSERT INTO `modx_site_content` (`id`, `type`, `contentType`, `pagetitle`, `longtitle`, `description`, `alias`, `link_attributes`, `published`, `pub_date`, `unpub_date`, `parent`, `isfolder`, `introtext`, `content`, `richtext`, `template`, `menuindex`, `searchable`, `cacheable`, `createdby`, `createdon`, `editedby`, `editedon`, `deleted`, `deletedon`, `deletedby`, `publishedon`, `publishedby`, `menutitle`, `donthit`, `privateweb`, `privatemgr`, `content_dispo`, `hidemenu`, `class_key`, `context_key`, `content_type`, `uri`, `uri_override`, `hide_children_in_tree`, `show_in_tree`, `properties`) VALUES ('', 'document', 'text/html', '$imya_f', '', '', '$aliasurl', '', 1, 0, 0, '$parentID', 0, '', '$opisanie', 1, 7, '', 1, 1, 1, 1446643476, '', 1463556765, 0, 0, 0, 1446643440, 1, '', 0, 0, 0, 0, 0, 'modDocument', 'web', 1, '$allurl', 1, 0, 1, '{"ms2gallery":{"media_source":"4"}}')");
				
				$contentid_new = mysql_fetch_assoc(mysql_query("SELECT `id` FROM `modx_site_content` WHERE `pagetitle` LIKE '%$imya%' ORDER BY `id` DESC LIMIT 1"));

				// вписываем характеристики нового товара
				
				//вписываем характеристики из икселя в соответствующие тв поля
				$contentid_new = $contentid_new['id'];
				if($contentid_new != '' || $contentid_new != 0) {
					foreach($arr_val_h as $ant_item_new => $ant_val_new) {
						if($ant_val_new != '') {
							$ant_val_new = trim($ant_val_new);
							$ant_val_new = $ant_val_new;
							mysql_query ("INSERT INTO `modx_site_tmplvar_contentvalues` (`id`, `tmplvarid`, `contentid`, `value`) VALUES
							('', '$ant_item_new', '$contentid_new', '$ant_val_new')");
							$ct++;
						}
					}
				} else { $mess = '<p style="font-weight: bold; color: #ff0000;">Error underfined. Try again or another sheet.</p>'; }
				$c2++;
			}

		}
		$mess1 = ($c1 > 0) ? '<p style="font-weight: bold; color: #9dcb53;">Обновление '.$c1.' карточек товара прошло успешно! Можете обновить следующий лист!</p>' : '';
	}
	$mess = $mess1;
	print($mess);
}

//сканируем папку с excel файлами

function exl_dir_f($uploaddir) {
	$name_dir = scandir($uploaddir);
	if(sizeof($name_dir) > 0) {
	$exl_dir_file = '';
		for($i=2; $i<=(sizeof($name_dir)-1); $i++) {
			$url_f = $uploaddir.$name_dir[$i];
			$num_sh = numsheets($url_f);
			$count_sh = $num_sh->getSheetCount();
			$inpt_1 = '';
			$c = 0;
			foreach ($num_sh->getWorksheetIterator() as $worksheet) {
				$worksheetTitle = $worksheet->getTitle();
					$inpt_1 .= '<button class="shh" name="numsheet" value="'.$c.'" type="button" id="numsheet'.$c.'">'.$worksheetTitle.'</button>';
				$c++;
			}
				$exl_dir_file .= '<div class="excelshtl" id="exl-'.($i-1).'" style="margin: 7px 0 9px;"><input name="objPHPExcel1" value="'.$url_f.'" type="hidden" class="objPHPExcel1" /><input name="alls" value="'.$count_sh.'" type="hidden" class="alls" /><p>'.($i-1).'. <a href="/'.$url_f.'">'.$name_dir[$i].'</a></p><p>'.$inpt_1.'<button class="delete_file" name="delete_file" value="'.$url_f.'">Удалить файл</button></p></div>';
		}
		
		$exl_dir_file1 = '<div class="excelshtload">'.$mess.'<p style="margin: 9px 0 6px;">Или выберите название/номер листа Excel (кнопки ниже), товары с которого необходимо залить на сайт. Нумерация листов начинается с «1». Товары будут залиты в текущую папку (категория).</p><p>Номер кнопки соответствует порядковому номеру листа в Excel. Пожалуйста, будьте внимательны при загрузке, значения полей и расположение столбцов должно соответствовать примеру. От этого зависит как и куда загрузятся значения из икселя в базу. Если вышла ошибка, возможно, загружаемый лист пуст.</p>'.strval($exl_dir_file).strval($exl_dir_file_maz).'</div>';
		
	} else {
		 $exl_dir_file1 = '<p>В папке пока нет excel файлов для загрузки</p>';
	}	
		return $exl_dir_file1;
}

$exl_dir_l = exl_dir_f($uploaddir);


//загружаем файл excel
if($_FILES['userfile']) {

	$fnt = $uploaddir.$_FILES['userfile']['name'];
	if (move_uploaded_file($_FILES['userfile']['tmp_name'], $fnt)) {
		$countsheet_q = '1';
		$exl_dir_l = exl_dir_f($uploaddir);
		print "<p style='font-weight: bold; color: #9dcb53;' id='scsc'>Файл успешно загружен в папку ".$fnt."!</p><div id='excelload'>Выберите файл и подождите пока он загрузится: <input name='userfile' id='upload_f' type='file' value='' />".$mess.$exl_dir_l."</div>";
	} else {
		$exl_dir_l = exl_dir_f($uploaddir);
		print "<p style='font-weight: bold; color: #ff0000;' id='err'>Не удалось загрузить файл! Проверьте, существует ли папка для загрузки, размер файла не должен превышать 500КБ, расширение должно быть .xls или .xlsx</p><div id='excelload'>Выберите файл и подождите пока он загрузится: <input name='userfile' id='upload_f' type='file' value='' />".$mess.$exl_dir_l."</div>";
	}
}

$mess = $mess ? '<p>'.$mess.' Можете загрузить следующий лист!</p>' : '';
$html = $mess.'<div class="m"></div><div id="excelload"><div id="n"> Выберите файл и подождите пока он загрузится: <input name="userfile" id="upload_f" type="file" value="" />'.$exl_dir_l.'</div></div>';


$urlcur = $_SERVER['REQUEST_URI'];
$parentID_res = $resource->get('id');

$modx->controller->addHtml("<script type="text/javascript">Ext.onReady(function() {MODx.addTab("modx-resource-tabs",{title:"Загрузить новые товары в данную категорию из  Excel",id:"modx-resource-excel-onload-goods"}); MODx.hideRegion("modx-resource-tabs","modx-resource-access-permissions"); MODx.moveTV(["tv107"],"modx-resource-excel-onload-goods");});</script> <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'></script><script type='text/javascript'>
window.onload = function() {
    var exlloadplace = document.getElementById('ext-gen348');
    exlloadplace.innerHTML = '".$html."';

    $('#upload_f').change(function() {
    
        var userfile = new FormData();
        userfile.append(this.name, this.files[0])
        $.ajax({
            type: 'POST',
            url: '/loadexl.php',
            data: userfile,
            contentType: false,
            processData: false,
            success: function(msg) {
                $('.m').html(msg);
				$('#n').hide();
            },
            error: function() {
                $('.m').html('Error js script!');
            }
        });
    });

}
$(document).on('click','.excelshtl button.shh', function() {

	$('#scsc').hide();
	$('#err').hide();
	
	var sheetload = new FormData();
	var objPHPExcel1 = $(this).parent().parent().find('.objPHPExcel1');
	var alls = $(this).parent().parent().find('.alls');
	var check_nalog = $(this).parent().parent().find('.check_nalog');
	
	if (check_nalog.is(':checked')) {
        sheetload.append('check_nalog', check_nalog.val());
    }

	sheetload.append('numsheet', $(this).val());
	sheetload.append('objPHPExcel1', objPHPExcel1.val());
	sheetload.append('alls', alls.val());
	sheetload.append('parentID', '".$parentID_res."');
	$.ajax({
		type: 'POST',
		url: '/loadexl.php',
		data: sheetload,
		contentType: false,
		processData: false,
		success: function(msg) {
			$('.m').html('<div class="blk">'+ msg + '</div>');
			$('#n').show();
		},
		error: function() {
			$('.m').html('Error js script!');
		}
	});
});

$(document).on('click','.excelshtl button.delete_file', function() {

	var id_prnt = $(this).parent().parent().attr('id');
	var idp = document.getElementById(id_prnt);
	
	var deleteExcel = new FormData();

	deleteExcel.append('delete_file', $(this).val());
	$.ajax({
		type: 'POST',
		url: '/loadexl.php',
		data: deleteExcel,
		contentType: false,
		processData: false,
		success: function(msg) {
			$(idp).html(msg);
		},
		error: function() {
		    $(this).parent()[1].html('Error js script!');
		}
	});
});

</script>");
?>

А вот пример использования.

Открыть вкладку

Загрузить Excel

Нажать на кнопку

Сам плагин

Работает с применением Ajax-технологии. Генерирует дополнительную вкладку в редактор каталога в "админке". Выводит поле для загрузки прайса, после того, как excel-файл загружен - на экран выведутся кнопки с названиями вкладок в Excel. Нажимая на одну из кнопок, Вы загружаете в текущий раздел (открытый для редактирования) все товары из данной вкладки.

Загрузив файл один раз в любой папке/разделе он становится доступен для всех разделов. Названия товаров, написанные кириллицей(русскими буквами) будут корректно перенесены в БД. Без нарушения кодировки и "кракозябр".  Нужно будет только поменять в коде id tv-полей товара на актуальные. Которые будут соответствовать ячейкам икселя, в которых хранятся параметры/характеристики/стоимость товара.

Установка и настройка требует некоторых познаний в программировании и особенностях CMS MODX, код вставлять как плагин, в разделе открытого кода и редактирования. Комментарии внутри кода я добавила, если будут вопросы, пишите pl.web-master@yandex.ru.

Разработанные мной скрипты, модули и CMS
Портфолио

Смотреть все статьи