Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/esol.redirector/lib/ |
Upload File : |
<?php namespace Bitrix\EsolRedirector; use Bitrix\Main\Loader; use Bitrix\Main\Localization\Loc; Loc::loadMessages(__FILE__); require_once(dirname(__FILE__).'/PHPExcel/PHPExcel.php'); class Importer { protected static $moduleId = 'esol.redirector'; protected static $moduleSubDir = ''; protected static $cpSpecCharLetters = null; protected static $instances = array(); var $notHaveTimeSetWorksheet = false; public static function getInstance($entity=0) { if (!isset(static::$instances[$entity])) static::$instances[$entity] = new static($entity); return static::$instances[$entity]; } public function __construct($entity) { //$this->fl = \Bitrix\EsolRedirector\RedirectTable::GetImportedFields(); } function setParams($filename, $params, $fparams, $stepparams, $pid = false) { $this->filename = $_SERVER['DOCUMENT_ROOT'].$filename; $this->params = $params; $this->fparams = $fparams; $this->maxReadRows = 500; $this->skipRows = 0; $this->errors = array(); $this->breakWorksheet = false; $this->stepparams = $stepparams; $this->stepparams['total_read_line'] = intval($this->stepparams['total_read_line']); $this->stepparams['total_line'] = intval($this->stepparams['total_line']); $this->stepparams['correct_line'] = intval($this->stepparams['correct_line']); $this->stepparams['error_line'] = intval($this->stepparams['error_line']); $this->stepparams['element_added_line'] = intval($this->stepparams['element_added_line']); $this->stepparams['element_updated_line'] = intval($this->stepparams['element_updated_line']); $this->stepparams['element_removed_line'] = intval($this->stepparams['element_removed_line']); $this->stepparams['worksheetCurrentRow'] = intval($this->stepparams['worksheetCurrentRow']); if(!isset($this->stepparams['total_line_by_list'])) $this->stepparams['total_line_by_list'] = array(); $this->stepparams['total_file_line'] = 0; if(is_array($this->params['LIST_LINES'])) { foreach($this->params['LIST_ACTIVE'] as $k=>$v) { if($v=='Y') { $this->stepparams['total_file_line'] += $this->params['LIST_LINES'][$k]; } } } $this->SetZipClass(); /*Temp folders*/ $this->filecnt = 0; $dir = $_SERVER["DOCUMENT_ROOT"].'/upload/tmp/'.static::$moduleId.'/'.static::$moduleSubDir; CheckDirPath($dir); if(!$this->stepparams['tmpdir']) { $i = 0; while(($tmpdir = $dir.$i.'/') && file_exists($tmpdir)){$i++;} $this->stepparams['tmpdir'] = $tmpdir; CheckDirPath($tmpdir); } $this->tmpdir = $this->stepparams['tmpdir']; $this->archivedir = $this->stepparams['tmpdir'].'archives/'; CheckDirPath($this->archivedir); $this->tmpfile = $this->tmpdir.'params.txt'; /*/Temp folders*/ if(file_exists($this->tmpfile) && filesize($this->tmpfile) > 0) { $this->stepparams = array_merge($this->stepparams, unserialize(file_get_contents($this->tmpfile))); } if(!isset($this->stepparams['curstep'])) $this->stepparams['curstep'] = 'import'; if(!isset($this->params['MAX_EXECUTION_TIME']) || $this->params['MAX_EXECUTION_TIME']!==0) { if(\Bitrix\Main\Config\Option::get(static::$moduleId, 'SET_MAX_EXECUTION_TIME')=='Y' && is_numeric(\Bitrix\Main\Config\Option::get(static::$moduleId, 'MAX_EXECUTION_TIME'))) { $this->params['MAX_EXECUTION_TIME'] = intval(\Bitrix\Main\Config\Option::get(static::$moduleId, 'MAX_EXECUTION_TIME')); if(ini_get('max_execution_time') && $this->params['MAX_EXECUTION_TIME'] > ini_get('max_execution_time') - 5) $this->params['MAX_EXECUTION_TIME'] = ini_get('max_execution_time') - 5; if($this->params['MAX_EXECUTION_TIME'] < 5) $this->params['MAX_EXECUTION_TIME'] = 5; if($this->params['MAX_EXECUTION_TIME'] > 300) $this->params['MAX_EXECUTION_TIME'] = 300; } else { $this->params['MAX_EXECUTION_TIME'] = intval(ini_get('max_execution_time')) - 10; if($this->params['MAX_EXECUTION_TIME'] < 10) $this->params['MAX_EXECUTION_TIME'] = 15; if($this->params['MAX_EXECUTION_TIME'] > 50) $this->params['MAX_EXECUTION_TIME'] = 50; } } if($pid!==false) { $this->procfile = $dir.$pid.'.txt'; $this->errorfile = $dir.$pid.'_error.txt'; if((int)$this->stepparams['import_started'] < 1) { if(file_exists($this->procfile)) unlink($this->procfile); if(file_exists($this->errorfile)) unlink($this->errorfile); } $this->pid = $pid; } } public function SetZipClass() { if($this->params['OPTIMIZE_RAM']!='Y' && !isset($this->stepparams['optimizeRam'])) { $this->stepparams['optimizeRam'] = 'N'; $origFileSize = filesize($this->filename); if((class_exists('\XMLReader') && $origFileSize > 2*1024*1024) && ToLower(GetFileExtension($this->filename))=='xlsx') { $timeBegin = microtime(true); $needSize = $origFileSize*10; $tempPath = \CFile::GetTempName('', 'test_size.txt'); CheckDirPath($tempPath); $fileSize = 0; $handle = fopen($tempPath, 'a'); while($fileSize < $needSize && microtime(true) - $timeBegin < 3) { $partSize = min(5*1024*1024, $needSize - $fileSize); fwrite($handle, str_repeat('0', $partSize)); $fileSize += $partSize; } fclose($handle); if($fileSize <= filesize($tempPath)) { $this->stepparams['optimizeRam'] = 'Y'; } unlink($tempPath); $dir = dirname($tempPath); if(count(array_diff(scandir($dir), array('.', '..')))==0) { rmdir($dir); } } } if($this->params['OPTIMIZE_RAM']=='Y' || $this->stepparams['optimizeRam']=='Y') { \KDAPHPExcel_Settings::setZipClass(KDAPHPExcel_Settings::KDAIEZIPARCHIVE); } } public function CheckTimeEnding($time = 0) { if($time==0) $time = $this->timeBeginImport; return ($this->params['MAX_EXECUTION_TIME'] && (time()-$time >= $this->params['MAX_EXECUTION_TIME'])); } public function GetRemainingTime() { if(!$this->params['MAX_EXECUTION_TIME']) return 600; else return ($this->params['MAX_EXECUTION_TIME'] - (time() - $this->timeBeginImport)); } public function HaveTimeSetWorksheet($time) { $this->notHaveTimeSetWorksheet = ($this->params['MAX_EXECUTION_TIME'] && $this->params['TIME_READ_FILE'] && (time()-$time+$this->params['TIME_READ_FILE'] >= $this->params['MAX_EXECUTION_TIME'])); return !$this->notHaveTimeSetWorksheet; } public function Import() { register_shutdown_function(array($this, 'OnShutdown')); set_error_handler(array($this, "HandleError")); set_exception_handler(array($this, "HandleException")); $this->stepparams['import_started'] = 1; $this->SaveStatusImport(); $time = $this->timeBeginImport = time(); if($this->stepparams['curstep'] == 'import') { $this->InitImport(); while($arItem = $this->GetNextRecord($time)) { if(is_array($arItem)) $this->SaveRecord($arItem); if($this->CheckTimeEnding($time)) { return $this->GetBreakParams(); } } if($this->CheckTimeEnding($time) || $this->notHaveTimeSetWorksheet) return $this->GetBreakParams(); $this->stepparams['curstep'] = 'import_end'; } return $this->EndOfLoading($time); } public function EndOfLoading($time) { $this->SaveStatusImport(true); foreach(GetModuleEvents(static::$moduleId, "OnEndImport", true) as $arEvent) { $bEventRes = ExecuteModuleEventEx($arEvent, array($this->pid, $arEventData)); } ZipArchive::RemoveFileDir($this->filename); return $this->GetBreakParams('finish'); } public function InitImport() { $this->objReader = \KDAPHPExcel_IOFactory::createReaderForFile($this->filename); $this->worksheetNames = array(); if(is_callable(array($this->objReader, 'listWorksheetNames'))) { $this->worksheetNames = $this->objReader->listWorksheetNames($this->filename); } if($this->params['ELEMENT_NOT_LOAD_STYLES']=='Y' && $this->params['ELEMENT_NOT_LOAD_FORMATTING']=='Y') { $this->objReader->setReadDataOnly(true); } if(isset($this->params['CSV_PARAMS'])) { $this->objReader->setCsvParams($this->params['CSV_PARAMS']); } $this->chunkFilter = new ImporterChunkReadFilter(); $this->objReader->setReadFilter($this->chunkFilter); $this->worksheetNum = (isset($this->stepparams['worksheetNum']) ? intval($this->stepparams['worksheetNum']) : 0); $this->worksheetCurrentRow = intval($this->stepparams['worksheetCurrentRow']); $this->GetNextWorksheetNum(); } public function GetBreakParams($action = 'continue') { $arStepParams = array( 'params' => $this->GetStepParams(), 'action' => $action, 'errors' => $this->errors, 'sessid' => bitrix_sessid() ); if($action == 'continue') { file_put_contents($this->tmpfile, serialize($arStepParams['params'])); } else { if(file_exists($this->procfile)) unlink($this->procfile); if(file_exists($this->tmpdir)) DeleteDirFilesEx(substr($this->tmpdir, strlen($_SERVER['DOCUMENT_ROOT']))); } unset($arStepParams['params']['currentelement']); unset($arStepParams['params']['currentelementitem']); return $arStepParams; } public function GetStepParams() { return array_merge($this->stepparams, array( 'worksheetNum' => intval($this->worksheetNum), 'worksheetCurrentRow' => $this->worksheetCurrentRow )); } public function SetWorksheet($worksheetNum, $worksheetCurrentRow) { $this->skipRows = 0; $timeBegin = microtime(true); $this->chunkFilter->setRows($worksheetCurrentRow, $this->maxReadRows); if($this->efile) $this->efile->__destruct(); if($this->worksheetNames[$worksheetNum]) $this->objReader->setLoadSheetsOnly($this->worksheetNames[$worksheetNum]); if($this->stepparams['csv_position'] && is_callable(array($this->objReader, 'setStartFilePosRow'))) { $this->objReader->setStartFilePosRow($this->stepparams['csv_position']); } $this->efile = $this->objReader->load($this->filename); $this->worksheetIterator = $this->efile->getWorksheetIterator(); $this->worksheet = $this->worksheetIterator->current(); $timeEnd = microtime(true); $this->params['TIME_READ_FILE'] = ceil($timeEnd - $timeBegin); $this->params['CURRENT_ELEMENT_UID'] = array('OLD_URL'); if($this->params['CHANGE_ELEMENT_UID'][$this->worksheetNum]=='Y') { $this->params['CURRENT_ELEMENT_UID'] = $this->params['LIST_ELEMENT_UID'][$this->worksheetNum]; } $filedList = $this->params['FIELDS_LIST'][$this->worksheetNum]; $arEntityFields = \Bitrix\EsolRedirector\RedirectTable::GetImportedFields(); $notSetUid = (bool)((is_array($this->params['CURRENT_ELEMENT_UID']) && count(array_diff($this->params['CURRENT_ELEMENT_UID'], $filedList)) > 0) || (!is_array($this->params['CURRENT_ELEMENT_UID']) && !in_array($this->params['CURRENT_ELEMENT_UID'], $filedList))); /*$arRequiredFields = $this->fl->GetRequiredField(); $notSetRequired = (bool)(count(array_diff(array_keys($arRequiredFields), $filedList)) > 0);*/ if($notSetUid) { if($this->worksheet->getHighestDataRow() > 0) { if($notSetUid) { $nofields = (is_array($this->params['CURRENT_ELEMENT_UID']) ? array_diff($this->params['CURRENT_ELEMENT_UID'], $filedList) : array($this->params['CURRENT_ELEMENT_UID'])); foreach($nofields as $k=>$field) { $nofields[$k] = '"'.$arEntityFields[$field].'"'; } $nofields = implode(', ', $nofields); //$this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_UID"), $this->worksheetNum+1, $nofields); $this->errors[] = Loc::getMessage("ESOL_RDR_NOT_SET_UID"); } /*elseif($notSetRequired) { $nofields = (array_diff(array_keys($arRequiredFields), $filedList)); foreach($nofields as $k=>$field) { $nofields[$k] = '"'.$arEntityFields[$field].'"'; } $nofields = implode(', ', $nofields); $this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_REQUIRED"), $this->worksheetNum+1, $nofields); }*/ } if(!$this->GetNextWorksheetNum(true)) { $this->worksheet = false; return false; } $pos = $this->GetNextLoadRow(1, $this->worksheetNum); $this->SetWorksheet($this->worksheetNum, $pos); return; } $this->fieldSettings = array(); $this->fieldSettingsExtra = array(); $this->fieldOnlyNew = array(); foreach($filedList as $k=>$field) { $fieldParams = $this->fparams[$this->worksheetNum][$k]; $this->fieldSettings[$field] = $fieldParams; if(strpos($field, '|')!==false) $this->fieldSettings[substr($field, 0, strpos($field, '|'))] = $fieldParams; $this->fieldSettingsExtra[$k] = $fieldParams; if($this->fieldSettings[$field]['SET_NEW_ONLY']=='Y') { $this->fieldOnlyNew[] = $field; } } if(!isset($this->stepparams['ELEMENT_NOT_LOAD_STYLES_ORIG'])) { $this->stepparams['ELEMENT_NOT_LOAD_STYLES_ORIG'] = ($this->params['ELEMENT_NOT_LOAD_STYLES']=='Y' ? 'Y' : 'N'); } else { $this->params['ELEMENT_NOT_LOAD_STYLES'] = $this->stepparams['ELEMENT_NOT_LOAD_STYLES_ORIG']; } $listSettings = $this->params['LIST_SETTINGS'][$this->worksheetNum]; $this->titlesRow = (isset($listSettings['SET_TITLES']) ? $listSettings['SET_TITLES'] : false); $this->worksheetColumns = \KDAPHPExcel_Cell::columnIndexFromString($this->worksheet->getHighestDataColumn()); $this->worksheetRows = min($this->maxReadRows, $this->worksheet->getHighestDataRow()); $this->worksheetCurrentRow = $worksheetCurrentRow; if($this->worksheet) { $this->worksheetRows = min($worksheetCurrentRow+$this->maxReadRows, $this->worksheet->getHighestDataRow()); } } public function SetFilePosition($pos, $time) { if($this->breakWorksheet) { $this->breakWorksheet = false; if(!$this->GetNextWorksheetNum(true)) return; if(!$this->HaveTimeSetWorksheet($time)) return false; $pos = $this->GetNextLoadRow(1, $this->worksheetNum); $this->SetWorksheet($this->worksheetNum, $pos); } else { $pos = $this->GetNextLoadRow($pos, $this->worksheetNum); if(($pos >= $this->worksheetRows) || !$this->worksheet) { if(!$this->HaveTimeSetWorksheet($time)) return false; if(!$this->GetNextWorksheetNum()) return; $this->SetWorksheet($this->worksheetNum, $pos); if($this->worksheetCurrentRow > $this->worksheetRows) { if(!$this->GetNextWorksheetNum(true)) return; if(!$this->HaveTimeSetWorksheet($time)) return false; $pos = $this->GetNextLoadRow(1, $this->worksheetNum); $this->SetWorksheet($this->worksheetNum, $pos); } $this->SaveStatusImport(); } else { $this->worksheetCurrentRow = $pos; } } $this->stepparams['csv_position'] = $this->chunkFilter->getFilePosRow($this->worksheetCurrentRow); } public function GetNextWorksheetNum($inc = false) { if($inc) $this->worksheetNum++; //$arLists = $this->params['LIST_ACTIVE']; $arLists = array('Y'); while(isset($arLists[$this->worksheetNum]) && $arLists[$this->worksheetNum]!='Y') { $this->worksheetNum++; } if(!isset($arLists[$this->worksheetNum])) { $this->worksheet = false; return false; } return true; } public function CheckSkipLine($currentRow, $worksheetNum, $checkValue = true) { $load = true; if($this->breakWorksheet || (!$this->params['CHECK_ALL'][$worksheetNum] && !isset($this->params['IMPORT_LINE'][$worksheetNum][$currentRow - 1])) || (isset($this->params['IMPORT_LINE'][$worksheetNum][$currentRow - 1]) && !$this->params['IMPORT_LINE'][$worksheetNum][$currentRow - 1])) { $load = false; } return !$load; } public function SaveStatusImport($end = false) { if($this->procfile) { $writeParams = $this->GetStepParams(); $writeParams['action'] = ($end ? 'finish' : 'continue'); file_put_contents($this->procfile, \CUtil::PhpToJSObject($writeParams)); } } public function GetNextLoadRow($row, $worksheetNum) { $nextRow = $row; if(isset($this->params['LIST_ACTIVE'][$worksheetNum])) { while($this->CheckSkipLine($nextRow, $worksheetNum, false)) { $nextRow++; if($nextRow - $row > 30000) { return $nextRow; } } } return $nextRow; } public function GetNextRecord($time) { if($this->SetFilePosition($this->worksheetCurrentRow + 1, $time)===false) return false; while($this->worksheet && $this->CheckSkipLine($this->worksheetCurrentRow, $this->worksheetNum)) { if($this->CheckTimeEnding($time)) return false; if($this->SetFilePosition($this->worksheetCurrentRow + 1, $time)===false) return false; } if(!$this->worksheet) { return false; } $arItem = array(); $this->hyperlinks = array(); $this->notes = array(); for($column = 0; $column < $this->worksheetColumns; $column++) { $val = $this->worksheet->getCellByColumnAndRow($column, $this->worksheetCurrentRow); $valText = $this->GetCalculatedValue($val); $arItem[$column] = trim($valText); $arItem['~'.$column] = $valText; if($this->params['ELEMENT_NOT_LOAD_STYLES']!='Y' && !isset($arItem['STYLE']) && strlen(trim($valText))>0) { $arItem['STYLE'] = md5(\CUtil::PhpToJSObject(self::GetCellStyle($val))); } } $this->worksheetNumForSave = $this->worksheetNum; return $arItem; } public function SaveRecord($arItem) { $saveReadRecord = (bool)(!isset($this->stepparams['lastoffergenkey'])); if($saveReadRecord) $this->stepparams['total_read_line']++; if(count(array_diff(array_map('trim', $arItem), array('')))==0) { $this->skipRows++; if($this->params['ADDITIONAL_SETTINGS'][$this->worksheetNum]['BREAK_LOADING']=='Y' || ($this->skipRows>=$this->maxReadRows - 1)) { $this->breakWorksheet = true; } return false; } if($saveReadRecord) { $this->stepparams['total_line']++; $this->stepparams['total_line_by_list'][$this->worksheetNum]++; } $filedList = $this->params['FIELDS_LIST'][$this->worksheetNumForSave]; $arEntityFields = \Bitrix\EsolRedirector\RedirectTable::GetImportedFields(); $entityDataClass = '\Bitrix\EsolRedirector\RedirectTable'; $primaryField = 'ID'; $this->currentItemValues = $arItem; $arFieldsElement = array(); $arFieldsElementOrig = array(); foreach($filedList as $key=>$field) { if(!array_key_exists($field, $arEntityFields)) continue; $k = $key; if(strpos($k, '_')!==false) $k = substr($k, 0, strpos($k, '_')); $value = $arItem[$k]; if($this->fieldSettings[$field]['NOT_TRIM']=='Y') $value = $arItem['~'.$k]; $origValue = $arItem['~'.$k]; /*$conversions = (isset($this->fieldSettingsExtra[$key]) ? $this->fieldSettingsExtra[$key]['CONVERSION'] : $this->fieldSettings[$field]['CONVERSION']); if(!empty($conversions)) { $value = $this->ApplyConversions($value, $conversions, $arItem, array('KEY'=>$k, 'NAME'=>$field), $iblockFields); $origValue = $this->ApplyConversions($origValue, $conversions, $arItem, array('KEY'=>$k, 'NAME'=>$field), $iblockFields); if($value===false) continue; }*/ $arFieldsElement[$field] = $value; $arFieldsElementOrig[$field] = $origValue; } $arUid = array(); if(!is_array($this->params['CURRENT_ELEMENT_UID'])) $this->params['CURRENT_ELEMENT_UID'] = array($this->params['CURRENT_ELEMENT_UID']); foreach($this->params['CURRENT_ELEMENT_UID'] as $uid) { $nameUid = $arEntityFields[$tuid]['title']; $valUid = $arFieldsElementOrig[$uid]; $valUid2 = $arFieldsElement[$uid]; $arUid[] = array( 'uid' => $uid, 'nameUid' => $nameUid, 'valUid' => $valUid, 'valUid2' => $valUid2 ); } $emptyFields = array(); foreach($arUid as $k=>$v) { if((is_array($v['valUid']) && count(array_diff($v['valUid'], array('')))==0) || (!is_array($v['valUid']) && strlen(trim($v['valUid']))==0)) $emptyFields[] = $v['nameUid']; } if(!empty($emptyFields) || empty($arUid)) { //$this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_FIELD"), implode(', ', $emptyFields), $this->worksheetNumForSave+1, $this->worksheetCurrentRow); $this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_FIELD"), implode(', ', $emptyFields), $this->worksheetCurrentRow); $this->stepparams['error_line']++; return false; } $arFilter = array(); foreach($arUid as $v) { if(is_array($v['valUid'])) $arSubfilter = array_map(array($this, 'Trim'), $v['valUid']); else { $arSubfilter = array($this->Trim($v['valUid'])); if($this->Trim($v['valUid']) != $v['valUid2']) { $arSubfilter[] = $this->Trim($v['valUid2']); if(strlen($v['valUid2']) != strlen($this->Trim($v['valUid2']))) { $arSubfilter[] = $v['valUid2']; } } if(strlen($v['valUid']) != strlen($this->Trim($v['valUid']))) { $arSubfilter[] = $v['valUid']; } } if(count($arSubfilter) == 1) { $arSubfilter = $arSubfilter[0]; } $arFilter['='.$v['uid']] = $arSubfilter; } $isError = false; $arKeys = array_diff(array_keys($arFieldsElement), array('SITE_ID')); //if($primaryField && !in_array($primaryField, $arKeys)) $arKeys[] = $primaryField; if($primaryField) { $arPrimaryFields = $primaryField; if(!is_array($arPrimaryFields)) $arPrimaryFields = array($arPrimaryFields); foreach($arPrimaryFields as $pfKey) { if(!in_array($pfKey, $arKeys)) $arKeys[] = $pfKey; } } $dbRes = $entityDataClass::getList(array('filter'=>$arFilter, 'select'=>$arKeys)); while($arElement = $dbRes->Fetch()) { if(is_array($primaryField)) { $ID = array(); foreach($primaryField as $pfKey) { $ID[$pfKey] = $arElement[$pfKey]; } } else { $ID = $arElement[$primaryField]; } /*if($this->params['ONLY_DELETE_MODE']=='Y') { if(!empty($ID)) { $entityDataClass::delete($ID); $this->stepparams['element_removed_line']++; } continue; }*/ $arFieldsElement2 = $arFieldsElement; if($this->params['ONLY_CREATE_MODE_ELEMENT']!='Y') { /*$this->UnsetUidFields($arFieldsElement2, $this->params['CURRENT_ELEMENT_UID']); if(!empty($this->fieldOnlyNew)) { $this->UnsetExcessFields($this->fieldOnlyNew, $arFieldsElement2); }*/ $this->PrepareFields($arFieldsElement2); if(empty($arFieldsElement2)) { $this->stepparams['element_updated_line']++; continue; } $dbRes2 = $entityDataClass::update($ID, $arFieldsElement2); if($dbRes2->isSuccess()) { $this->stepparams['element_updated_line']++; } else { $isError = true; $this->stepparams['error_line']++; //$this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_UPDATE_ELEMENT_ERROR"), implode(', ',$dbRes2->GetErrorMessages()), $this->worksheetNumForSave+1, $this->worksheetCurrentRow, (is_array($ID) ? print_r($ID, true) : $ID)); $this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_UPDATE_ELEMENT_ERROR"), implode(', ',$dbRes2->GetErrorMessages()), $this->worksheetCurrentRow, (is_array($ID) ? print_r($ID, true) : $ID)); } } } $allowCreate = (bool)($dbRes->getSelectedRowsCount()==0 && $this->params['ONLY_DELETE_MODE']!='Y' && $this->params['ONLY_UPDATE_MODE_ELEMENT']!='Y'); /*if($allowCreate) { if(is_callable(array($entityDataClass, 'PrepareFieldsForAddImport'))) { $entityDataClass::PrepareFieldsForAddImport($arFieldsElement); } $arRequiredFields = $this->fl->GetRequiredField(); $arRequiredKeys = array_diff(array_keys($arRequiredFields), array_keys($arFieldsElement)); if(count($arRequiredKeys) > 0) { foreach($arRequiredKeys as $k=>$field) { $arRequiredKeys[$k] = '"'.$arEntityFields[$field]['title'].'"'; } $arRequiredKeys = implode(', ', $arRequiredKeys); //$this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_REQUIRED_ADD"), $arRequiredKeys, $this->worksheetNum+1, $this->worksheetCurrentRow); $this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_NOT_SET_REQUIRED_ADD"), $arRequiredKeys, $this->worksheetCurrentRow); $isError = true; $allowCreate = false; } }*/ if($allowCreate) { if($this->params['ONLY_UPDATE_MODE_ELEMENT']!='Y') { /*$this->UnsetUidFields($arFieldsElement, $this->params['CURRENT_ELEMENT_UID'], true);*/ $this->PrepareFields($arFieldsElement, true); $dbRes2 = $entityDataClass::add($arFieldsElement); if($dbRes2->isSuccess()) { $ID = $dbRes2->getId(); $this->stepparams['element_added_line']++; } else { $this->stepparams['error_line']++; //$this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_ADD_ELEMENT_ERROR"), implode(', ',$dbRes2->GetErrorMessages()), $this->worksheetNumForSave+1, $this->worksheetCurrentRow); $this->errors[] = sprintf(Loc::getMessage("ESOL_RDR_ADD_ELEMENT_ERROR"), implode(', ',$dbRes2->GetErrorMessages()), $this->worksheetCurrentRow); $isError = true; } } } if(!$isError) $this->stepparams['correct_line']++; $this->SaveStatusImport(); } public function PrepareFields(&$arFieldsElement, $bAdd=false) { if(isset($arFieldsElement['ACTIVE'])) { $arFieldsElement['ACTIVE'] = $this->GetBoolValue($arFieldsElement['ACTIVE'], false, false); if($arFieldsElement['ACTIVE']===false) unset($arFieldsElement['ACTIVE']); } if(isset($arFieldsElement['WSUBSECTIONS'])) { $arFieldsElement['WSUBSECTIONS'] = $this->GetBoolValue($arFieldsElement['WSUBSECTIONS'], false, false); if($arFieldsElement['WSUBSECTIONS']===false) unset($arFieldsElement['WSUBSECTIONS']); } if(isset($arFieldsElement['WGETPARAMS'])) { $arFieldsElement['WGETPARAMS'] = $this->GetBoolValue($arFieldsElement['WGETPARAMS'], false, false); if($arFieldsElement['WGETPARAMS']===false) unset($arFieldsElement['WGETPARAMS']); } if(isset($arFieldsElement['REGEXP'])) { $arFieldsElement['REGEXP'] = $this->GetBoolValue($arFieldsElement['REGEXP'], false, false); if($arFieldsElement['REGEXP']===false) unset($arFieldsElement['REGEXP']); } if(isset($arFieldsElement['FOR404'])) { $arFieldsElement['FOR404'] = $this->GetBoolValue($arFieldsElement['FOR404'], false, false); if($arFieldsElement['FOR404']===false) unset($arFieldsElement['FOR404']); } if(isset($arFieldsElement['STATUS'])) { $arFieldsElement['STATUS'] = (int)$arFieldsElement['STATUS']; } if(isset($arFieldsElement['SITE_ID'])) { if(strpos($arFieldsElement['SITE_ID'], '/')!==false) $arSites = explode('/', $arFieldsElement['SITE_ID']); elseif(strpos($arFieldsElement['SITE_ID'], ',')!==false) $arSites = explode(',', $arFieldsElement['SITE_ID']); elseif(strpos($arFieldsElement['SITE_ID'], ';')!==false) $arSites = explode(';', $arFieldsElement['SITE_ID']); else $arSites = array($arFieldsElement['SITE_ID']); foreach($arSites as $k=>$v) { $arSites[$k] = $this->GetSiteByName($v); } $arSites = array_diff($arSites, array('')); if(!empty($arSites)) $arFieldsElement['SITE_ID'] = $arSites; else unset($arFieldsElement['SITE_ID']); } if(!isset($arFieldsElement['SITE_ID']) && $bAdd) { $arFieldsElement['SITE_ID'] = array($this->GetDefaultSiteId()); } } public function GetSiteByName($val) { if(!isset($this->siteList)) { $this->siteList = array( 'names' => array(), 'ids' => array() ); $dbRes = \CSite::GetList(($by='sort'), ($order='asc'), array()); while($arr = $dbRes->Fetch()) { $this->siteList['names'][ToLower($arr['NAME'])] = $arr['ID']; $this->siteList['ids'][ToLower($arr['ID'])] = $arr['ID']; } } $val = ToLower(trim($val)); if(isset($this->siteList['ids'][$val])) return $this->siteList['ids'][$val]; elseif(isset($this->siteList['names'][$val])) return $this->siteList['names'][$val]; else return ''; } public function GetDefaultSiteId() { if(!isset($this->defultSiteId)) { if(!($arSite = \CSite::GetList(($by='sort'), ($order='asc'), array('DEFAULT'=>'Y'))->Fetch())) $arSite = \CSite::GetList(($by='sort'), ($order='asc'), array())->Fetch(); $this->defultSiteId = $arSite['ID']; } return $this->defultSiteId; } public function GetBoolValue($val, $numReturn = false, $defaultValue = false) { $trueVals = array_map('trim', explode(',', Loc::getMessage("ESOL_RDR_FIELD_VAL_Y"))); $falseVals = array_map('trim', explode(',', Loc::getMessage("ESOL_RDR_FIELD_VAL_N"))); if(in_array(ToLower($val), $trueVals)) { return ($numReturn ? 1 : 'Y'); } elseif(in_array(ToLower($val), $falseVals)) { return ($numReturn ? 0 : 'N'); } else { return $defaultValue; } } public static function GetPreviewData($file, $showLines, $arParams = array(), $colsCount = false) { $selfobj = new ImporterStatic($arParams, $file); $file = $_SERVER['DOCUMENT_ROOT'].$file; $objReader = \KDAPHPExcel_IOFactory::createReaderForFile($file); if($arParams['ELEMENT_NOT_LOAD_STYLES']=='Y' && $arParams['ELEMENT_NOT_LOAD_FORMATTING']=='Y') { $objReader->setReadDataOnly(true); } if(isset($arParams['CSV_PARAMS'])) { $objReader->setCsvParams($arParams['CSV_PARAMS']); } $chunkFilter = new ImporterChunkReadFilter(); $objReader->setReadFilter($chunkFilter); $maxLine = 1000; if(!$colsCount) $maxLine = max($showLines + 50, 50); $chunkFilter->setRows(1, $maxLine); $efile = $objReader->load($file); $arWorksheets = array(); foreach($efile->getWorksheetIterator() as $worksheet) { $maxDrawCol = 0; $columns_count = max(\KDAPHPExcel_Cell::columnIndexFromString($worksheet->getHighestDataColumn()), $maxDrawCol); $columns_count = min($columns_count, 5000); $rows_count = $worksheet->getHighestDataRow(); $arLines = array(); $cntLines = $emptyLines = 0; for ($row = 0; ($row < $rows_count && count($arLines) < min($showLines+$emptyLines, $maxLine)); $row++) { $arLine = array(); $bEmpty = true; for ($column = 0; $column < $columns_count; $column++) { $val = $worksheet->getCellByColumnAndRow($column, $row+1); $valText = $selfobj->GetCalculatedValue($val); if(strlen(trim($valText)) > 0) $bEmpty = false; $curLine = array('VALUE' => $valText); if($arParams['ELEMENT_NOT_LOAD_STYLES']!='Y') { $curLine['STYLE'] = $selfobj->GetCellStyle($val, true); } $arLine[] = $curLine; } $arLines[$row] = $arLine; if($bEmpty) { $emptyLines++; } $cntLines++; } if($colsCount) { $columns_count = $colsCount; $arLines = array(); $lastEmptyLines = 0; for ($row = $cntLines; $row < $rows_count; $row++) { $arLine = array(); $bEmpty = true; for ($column = 0; $column < $columns_count; $column++) { $val = $worksheet->getCellByColumnAndRow($column, $row+1); $valText = $selfobj->GetCalculatedValue($val); if(strlen(trim($valText)) > 0) $bEmpty = false; $curLine = array('VALUE' => $valText); if($arParams['ELEMENT_NOT_LOAD_STYLES']!='Y') { $curLine['STYLE'] = $selfobj->GetCellStyle($val, true); } $arLine[] = $curLine; } if($bEmpty) $lastEmptyLines++; else $lastEmptyLines = 0; $arLines[$row] = $arLine; } if($lastEmptyLines > 0) { $arLines = array_slice($arLines, 0, -$lastEmptyLines, true); } } $arCells = explode(':', $worksheet->getSelectedCells()); $heghestRow = intval(preg_replace('/\D+/', '', end($arCells))); if(is_callable(array($worksheet, 'getRealHighestRow'))) $heghestRow = intval($worksheet->getRealHighestRow()); elseif($worksheet->getHighestDataRow() > $heghestRow) $heghestRow = intval($worksheet->getHighestDataRow()); if(stripos($file, '.csv')) { $heghestRow = self::GetFileLinesCount($file); } $arWorksheets[] = array( 'title' => self::CorrectCalculatedValue($worksheet->GetTitle()), 'show_more' => ($row < $rows_count - 1), 'lines_count' => $heghestRow, 'lines' => $arLines ); } return $arWorksheets; } public static function GetFileLinesCount($fn) { if(!file_exists($fn)) return 0; $cnt = 0; $handle = fopen($fn, 'r'); while (!feof($handle)) { $buffer = trim(fgets($handle)); if($buffer) $cnt++; } fclose($handle); return $cnt; } public function GetCellStyle($val, $modify = false) { $style = $val->getStyle(); $arStyle = array( 'COLOR' => $style->getFont()->getColor()->getRGB(), 'FONT-FAMILY' => $style->getFont()->getName(), 'FONT-SIZE' => $style->getFont()->getSize(), 'FONT-WEIGHT' => $style->getFont()->getBold(), 'FONT-STYLE' => $style->getFont()->getItalic(), 'TEXT-DECORATION' => $style->getFont()->getUnderline(), 'BACKGROUND' => ($style->getFill()->getFillType()=='solid' ? $style->getFill()->getStartColor()->getRGB() : ''), ); $outlineLevel = (int)$val->getWorksheet()->getRowDimension($val->getRow())->getOutlineLevel(); if($outlineLevel > 0) { $arStyle['TEXT-INDENT'] = $outlineLevel; } if($modify) { $arStyle['EXT'] = array( 'COLOR' => $style->getFont()->getColor()->getRealRGB(), 'BACKGROUND' => ($style->getFill()->getFillType()=='solid' ? $style->getFill()->getStartColor()->getRealRGB() : ''), ); } return $arStyle; } public function GetCalculatedValue($val) { try{ if($this->params['ELEMENT_NOT_LOAD_FORMATTING']=='Y') $val = $val->getCalculatedValue(); else $val = $val->getFormattedValue(); }catch(\Exception $ex){} return self::CorrectCalculatedValue($val); } public function Trim($str) { $str = trim($str); $str = preg_replace('/(^(\xC2\xA0|\s)+|(\xC2\xA0|\s)+$)/s', '', $str); return $str; } public static function CorrectCalculatedValue($val) { $val = str_ireplace('_x000D_', '', $val); if((!defined('BX_UTF') || !BX_UTF) && \CUtil::DetectUTF8($val)/*function_exists('mb_detect_encoding') && (mb_detect_encoding($val) == 'UTF-8')*/) { $val = self::ReplaceCpSpecChars($val); if(function_exists('iconv')) { $newVal = iconv("UTF-8", "CP1251//IGNORE", $val); if(strlen(trim($newVal))==0 && strlen(trim($val))>0) { $newVal2 = utf8win1251($val); if(strpos(trim($newVal2), '?')!==0) $newVal = $newVal2; } $val = $newVal; } else $val = utf8win1251($val); } return $val; } public static function ReplaceCpSpecChars($val) { $specChars = array('Ø'=>'Ø', '™'=>'™', '®'=>'®', '©'=>'©'); if(!isset(self::$cpSpecCharLetters)) { $cpSpecCharLetters = array(); foreach($specChars as $char=>$code) { $letter = false; $pos = 0; for($i=192; $i<255; $i++) { $tmpLetter = \Bitrix\Main\Text\Encoding::convertEncodingArray(chr($i), 'CP1251', 'UTF-8'); $tmpPos = strpos($tmpLetter, $char); if($tmpPos!==false) { $letter = $tmpLetter; $pos = $tmpPos; } } $cpSpecCharLetters[$char] = array('letter'=>$letter, 'pos'=>$pos); } self::$cpSpecCharLetters = $cpSpecCharLetters; } foreach($specChars as $char=>$code) { if(strpos($val, $char)===false) continue; $letter = self::$cpSpecCharLetters[$char]['letter']; $pos = self::$cpSpecCharLetters[$char]['pos']; if($letter!==false) { if($pos==0) $val = preg_replace('/'.substr($letter, 0, 1).'(?!'.substr($letter, 1, 1).')/', $code, $val); elseif($pos==1) $val = preg_replace('/(?<!'.substr($letter, 0, 1).')'.substr($letter, 1, 1).'/', $code, $val); } else { $val = str_replace($char, $code, $val); } } return $val; } public function OnShutdown() { $arError = error_get_last(); if(!is_array($arError) || !isset($arError['type']) || !in_array($arError['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR))) return; if($this->worksheetCurrentRow > 0) { $this->EndWithError(sprintf(Loc::getMessage("ESOL_RDR_FATAL_ERROR_IN_LINE"), $this->worksheetNumForSave+1, $this->worksheetCurrentRow, $arError['type'], $arError['message'], $arError['file'], $arError['line'])); } else { $this->EndWithError(sprintf(Loc::getMessage("ESOL_RDR_FATAL_ERROR"), $arError['type'], $arError['message'], $arError['file'], $arError['line'])); } } public function HandleError($code, $message, $file, $line) { return true; } public function HandleException($exception) { $error = ''; if($this->worksheetCurrentRow > 0) { $error .= sprintf(Loc::getMessage("ESOL_RDR_ERROR_LINE"), $this->worksheetNumForSave+1, $this->worksheetCurrentRow); } if(is_callable(array('\Bitrix\Main\Diag\ExceptionHandlerFormatter', 'format'))) { $error .= \Bitrix\Main\Diag\ExceptionHandlerFormatter::format($exception); } else { $error .= sprintf(Loc::getMessage("ESOL_RDR_FATAL_ERROR"), '', $exception->getMessage(), $exception->getFile(), $exception->getLine()); } $this->EndWithError($error); } public function EndWithError($error) { global $APPLICATION; $APPLICATION->RestartBuffer(); ob_end_clean(); $this->errors[] = $error; $this->SaveStatusImport(); echo '<!--module_return_data-->'.\CUtil::PhpToJSObject($this->GetBreakParams()); die(); } } class ImporterStatic extends Importer { function __construct($params, $file='') { $this->params = $params; $this->filename = $_SERVER['DOCUMENT_ROOT'].$file; $this->SetZipClass(); } } class ImporterChunkReadFilter implements \KDAPHPExcel_Reader_IReadFilter { private $_startRow = 0; private $_endRow = 0; private $_arFilePos = array(); private $_arMerge = array(); private $_params = array(); /** Set the list of rows that we want to read */ public function setParams($arParams=array()) { $this->_params = $arParams; } public function getParam($paramName) { return (array_key_exists($paramName, $this->_params) ? $this->_params[$paramName] : false); } public function setMergeCells($mergeRef) { if(preg_match('/^([A-Z]+)(\d+):([A-Z]+)(\d+)$/', trim($mergeRef), $m) && $m[2]!=$m[4]) { /*$this->_arMerge[$m[1]][$m[2].':'.$m[4]] = array($m[2], $m[4]); $this->_arMerge[$m[3]][$m[2].':'.$m[4]] = array($m[2], $m[4]);*/ $this->_arMerge[$m[2].':'.$m[4]] = array($m[2], $m[4]); } } public function setRows($startRow, $chunkSize) { $this->_startRow = $startRow; $this->_endRow = $startRow + $chunkSize; $this->_arMerge = array(); } public function readCell($column, $row, $worksheetName = '') { // Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)){ return true; } elseif(count($this->_arMerge) > 0){ foreach($this->_arMerge as $range){ if($row >= $range[0] && $row <= $range[1] && (($this->_startRow >= $range[0] && $this->_startRow <= $range[1]) || ($this->_endRow >= $range[0] && $this->_endRow <= $range[1]))){ return true; } } } return false; } public function getStartRow() { return $this->_startRow; } public function getEndRow() { return $this->_endRow; } public function setFilePosRow($row, $pos) { $this->_arFilePos[$row] = $pos; } public function getFilePosRow($row) { $nextRow = $row + 1; $pos = 0; if(!empty($this->_arFilePos)) { if(isset($this->_arFilePos[$nextRow])) $pos = (int)$this->_arFilePos[$nextRow]; else { $arKeys = array_keys($this->_arFilePos); if(!empty($arKeys)) { $maxKey = max($arKeys); if($nextRow > $maxKey); { $nextRow = $maxKey; $pos = (int)$this->_arFilePos[$maxKey]; } } } } return array( 'row' => $nextRow, 'pos' => $pos ); } } ?>