audit = GetAuditObject( $this->tName ); $this->jsSettings["tableSettings"][ $this->tName ]["importFieldsLables"] = $this->getImportfieldsLabels(); } /** * Get import fields labels data * @return Array */ protected function getImportfieldsLabels() { $importFieldsLabels = array(); $importFields = $this->pSet->getImportFields(); foreach( $importFields as $importField ) { $importFieldsLabels[ $importField ] = GetFieldLabel( GoodFieldName($this->tName), GoodFieldName($importField) ); } return $importFieldsLabels; } /** * Process the page */ public function process() { if( !strlen($this->action) ) $this->removeOldTemporaryFiles(); // Before Process event if( $this->eventsObject->exists("BeforeProcessImport") ) $this->eventsObject->BeforeProcessImport( $this ); if( $this->action == "importPreview" ) { $this->prepareAndSentPreviewData(); return; } if( $this->action == "importData" ) { $this->runImportAndSendResultReport(); return; } if( $this->action == "downloadReport" ) { $this->downloadReport(); return; } if( $this->action == "downloadUnprocessed" ) { $this->downloadUnprocessed(); return; } $this->doCommonAssignments(); $this->addButtonHandlers(); $this->addCommonJs(); $this->displayImportPage(); } /** * Send the preview data */ protected function prepareAndSentPreviewData() { $response = array(); // prepare the temp import file name $rnrTempFileName = $this->getImportTempFileName(); if( $this->importType == "text" ) { $response["previewData"] = $this->getPreviewDataFromText( $this->importText ); // prepare the temp file path $rnrTempImportFilePath = getabspath("templates_c/".$rnrTempFileName.".csv"); // save file in a temporary directory runner_save_textfile( $rnrTempImportFilePath, $this->importText ); } else { $ext = getImportFileExtension( "importFile".$this->id ); $importTempFileName = getTempImportFileName( "importFile".$this->id ); $response["previewData"] = $this->getPreviewDataFromFile( $importTempFileName, $ext ); // save file in a temporary directory $importFileData = getImportFileData( "importFile".$this->id ); // prepare the temp file path $rnrTempImportFilePath = getabspath("templates_c/".$rnrTempFileName.".".$ext); upload_File( $importFileData, $rnrTempImportFilePath ); } // keep the temporary path in the SESSION variable $_SESSION[ $this->sessionPrefix ."_tempImportFilePath" ] = $rnrTempImportFilePath; $returnJSON = printJSON( $response, $this->useXHR ); if( $returnJSON != false ) echo $returnJSON; else echo mlang_message("IMPORT_FILE_PARSING_FAILED"); exit(); } /** * Import the data and send a report */ protected function runImportAndSendResultReport() { if( $this->eventsObject->exists("BeforeImport") ) { $message = ""; if( $this->eventsObject->BeforeImport($this, $message) === false ) { echo printJSON( array( "failed" => true, "message" => $message ) ); exit(); } } $rnrTempImportFilePath = $_SESSION[ $this->sessionPrefix ."_tempImportFilePath" ]; $resultData = $this->ImportFromFile( $rnrTempImportFilePath, $this->importData ); // remove a temporary import file runner_delete_file( $rnrTempImportFilePath ); if( $this->eventsObject->exists("AfterImport") ) $this->eventsObject->AfterImport( $resultData["totalRecordsNumber"], $resultData["unprocessedRecordsNumber"], $this); // keep all necessary data in SESSION variables $_SESSION[ $this->sessionPrefix ."_tempImportLogFilePath" ] = $resultData["logFilePath"]; if( $resultData["unprocessedRecordsNumber"] ) $_SESSION[ $this->sessionPrefix ."_tempDataFilePath" ] = $resultData["unprocessedFilePath"]; echo printJSON( $resultData ); exit(); } /** * */ protected function downloadReport() { $logFilePath = $_SESSION[ $this->sessionPrefix ."_tempImportLogFilePath" ]; if( !myfile_exists( $logFilePath ) ) { $data = array( "success" => false ); echo printJSON( $data ); exit(); } header("Content-Type: text/plain"); header("Content-Disposition: attachment;Filename=importLog.txt"); header("Cache-Control: private"); printfile( $logFilePath ); exit(); } /** * */ protected function downloadUnprocessed() { $dataFilePath = $_SESSION[ $this->sessionPrefix ."_tempDataFilePath" ]; if( !myfile_exists( $dataFilePath ) ) { $data = array( "success" => false ); echo printJSON( $data ); exit(); } header("Content-Type: application/csv"); header("Content-Disposition: attachment;Filename=unpocessedData.csv"); printfile( $dataFilePath ); exit(); } /** * Assign 'body' element */ public function doCommonAssignments() { $this->xt->assign("id", $this->id); // assign body begin $this->body["begin"] = GetBaseScriptsForPage(false); // assign body end $this->body["end"] = XTempl::create_method_assignment( "assignBodyEnd", $this); $this->xt->assignbyref("body", $this->body); } /** * Clear session kyes * @intellisense */ public function clearSessionKeys() { parent::clearSessionKeys(); if( !count($_POST) && !count($_GET) ) { unset( $_SESSION[ $this->sessionPrefix ."_tempImportFilePath" ] ); unset( $_SESSION[ $this->sessionPrefix ."_tempImportLogFilePath" ] ); unset( $_SESSION[ $this->sessionPrefix ."_tempDataFilePath" ] ); } } /** * Get preview data for an importing file * @param String filePath * @param String ext * @return Array */ public function getPreviewDataFromFile( $filePath, $ext ) { $normalizedExt = strtoupper($ext); if( $normalizedExt == "XLS" || $normalizedExt == "XLSX" ) return $this->getPreviewDataFromExcel( $filePath, $ext ); return $this->getPreviewDataFromCsv( $filePath ); } /** * A wrapper for the import function getPreviewDataFromExcel * @param String filePath * @param String ext * @return Array */ protected function getPreviewDataFromExcel( $filePath, $ext ) { $fileHandle = openImportExcelFile( $filePath, $ext ); $headerFieldsFromExcel = getImportExcelFields( $fileHandle ); $fieldsData = $this->getCorrespondingImportFieldsData( $headerFieldsFromExcel ); $previewData = getPreviewDataFromExcel( $fileHandle, $fieldsData ); $previewData["fieldsData"] = $fieldsData; return $previewData; } /** * Get preview data for an importing text * @param String importText * @return Array */ public function getPreviewDataFromText( $importText ) { $lines = $this->importExplode($importText); $lines = $this->removeEmptyLines( $lines ); if( !count($lines) ) return array(); $previewData = array(); $previewData["CSVPreview"] = true; $firstTwoLinesData = array_slice( $lines, 0, 2 ); $delimiter = $this->getCSVDelimiter( $firstTwoLinesData ); $previewData["delimiter"] = $delimiter; $fieldsNamesLine = $lines[0]; $headerFieldsFromCSV = parceCSVLine( $fieldsNamesLine, $delimiter ); $fieldsData = $this->getCorrespondingImportFieldsData( $headerFieldsFromCSV ); $previewData["fieldsData"] = $fieldsData; $hasDTFields = ImportPage::hasDateTimeFields( $fieldsData ); $linesData = array(); foreach($lines as $line) { if( count( $linesData ) >= 100 ) break; $linesData[] = $line; if( !$hasDTFields ) continue; $elems = parceCSVLine( $line, $delimiter ); foreach($elems as $idx => $elem) { if( isset($fieldsData[ $idx ]) && $fieldsData[ $idx ]["dateTimeType"] && !strlen($dateFormat) ) $dateFormat = ImportPage::extractDateFormat( $elem ); } } if( $hasDTFields ) $previewData["dateFormat"] = $this->getImportDateFormat( $dateFormat ); $previewData["tableData"] = $tableData; $previewData["CSVlinesData"] = $linesData; return $previewData; } /** * Remove elementes containing empty lines forms the lines array * @param Array lines * @return Array */ protected function removeEmptyLines( $lines ) { $resultLines = array(); foreach( $lines as $line ) { if( strlen( trim($line) ) ) $resultLines[] = $line; } return $resultLines; } /** * Get preview data for an importing CSV file * @param String filePath * @return Array */ protected function getPreviewDataFromCsv( $filePath ) { $fileHandle = OpenCSVFile($filePath, ""); if( $fileHandle === FALSE ) return array(); $previewData = array(); $previewData["CSVPreview"] = true; $firstTwoLinesData = $this->getNLinesFromFile($fileHandle, 2); $delimiter = $this->getCSVDelimiter( $firstTwoLinesData ); $previewData["delimiter"] = $delimiter; // reset the CSV file pointer $fileHandle = rewindFilePointerPosition( $fileHandle, $filePath ); $linesData = array(); $fistNotEmptyLineData = $this->getNLinesFromFile($fileHandle, 1); $fieldsNamesLine = $fistNotEmptyLineData[0]; $headerFieldsFromCSV = parceCSVLine( $fieldsNamesLine, $delimiter, true ); // add the first line with columns' names to the preview $linesData[] = $fieldsNamesLine; $fieldsData = $this->getCorrespondingImportFieldsData( $headerFieldsFromCSV ); $previewData["fieldsData"] = $fieldsData; $hasDTFields = ImportPage::hasDateTimeFields( $fieldsData ); // traversing CSV file lines starting from the second one while( ($line = getLineFromFile($fileHandle, 1000000)) !== FALSE && count( $linesData ) < 100 ) { if( !strlen( trim($line) ) ) break; $linesData[] = $line; if( !$hasDTFields ) continue; $elems = parceCSVLine( $line, $delimiter, true ); foreach($elems as $idx => $elem) { if( isset($fieldsData[ $idx ]) && $fieldsData[ $idx ]["dateTimeType"] && !strlen($dateFormat) ) $dateFormat = ImportPage::extractDateFormat( $elem ); } } if( ImportPage::hasDateTimeFields( $fieldsData ) ) $previewData["dateFormat"] = $this->getImportDateFormat( $dateFormat ); $previewData["CSVlinesData"] = $linesData; CloseCSVFile( $fileHandle ); return $previewData; } /** * Extract a date format form the dateTime string //#9684 * @param String dateString * @return String */ public static function extractDateFormat($dateString) { global $locale_info; $dateComponents = parsenumbers( $dateString ); if( count($dateComponents) < 3 ) return ""; $dateSeparator = $locale_info["LOCALE_SDATE"]; $format = ""; if( $dateComponents[0] > 31 && testMonth($dateComponents[1]) && $dateComponents[2] >= 12) { $year = $dateComponents[0]; $format = "Y".$dateSeparator."M".$dateSeparator."D"; } if( $dateComponents[0] >= 12 && testMonth($dateComponents[1]) && $dateComponents[2] > 31 ) { $year = $dateComponents[3]; $format = "D".$dateSeparator."M".$dateSeparator."Y"; } if( testMonth($dateComponents[0]) && $dateComponents[1] >= 12 && $dateComponents[2] > 31 ) { $year = $dateComponents[3]; $format = "M".$dateSeparator."D".$dateSeparator."Y"; } if( $format ) $format = str_replace("Y", $year < 100 ? "YY" : "YYYY", $format); return $format; } /** * Get no more then N not empty lines from a file * @param Mixed fileHandle CSV file hanle * @param Number * @return Array */ protected function getNLinesFromFile( $fileHandle, $N ) { $lines = array(); while( count($lines) < $N ) { $line = getLineFromFile( $fileHandle, 1000000 ); if( $line === FALSE ) break; $line = cutBOM($line); if( strlen( trim($line) ) ) $lines[] = $line; } return $lines; } /** * Detect a delimiter value by the first two not empty file (or text) lines * @param Array firstTwoLinesData An array containing no more then first two file (or text) lines * @return String */ protected function getCSVDelimiter( $firstTwoLines ) { // the most possible delimiters values $delimiters = array(",", ";", "\t", " "); $delimitersData = array(); foreach($delimiters as $delim) { $delimitersData[ $delim ] = array(); foreach($firstTwoLines as $idx => $line) { $elemsNumber = count( parceCSVLine($line, $delim) ); if( $elemsNumber <= 1 ) break; $delimitersData[ $delim ][ $idx ] = $elemsNumber; } } // the default delimiter value $delimiter = ","; $maxNumOfElems = 1; foreach($delimitersData as $delim => $data) { if( !count($data) ) continue; if( (count($firstTwoLines) == 1 || count($firstTwoLines) == 2 && $data[0] == $data[1]) && $data[0] > $maxNumOfElems ) { $maxNumOfElems = $data[0]; $delimiter = $delim; } } return $delimiter; } /** * Check if header fields correspond to any import dateTime field * @param Array * @return Boolean */ static function hasDateTimeFields($fieldsData) { // always show Date Format box. return true; foreach($fieldsData as $fieldData) { if( $fieldData["dateTimeType"] ) return true; } return false; } /** * Get the field names array for Import * @param Array headerFields * @return Array */ public function getCorrespondingImportFieldsData( $headerFields ) { $importFields = $this->pSet->getImportFields(); $tempFieldArray = array(); $tempLabelArray = array(); $tempGNamesArray = array(); foreach($headerFields as $idx => $headerField) { foreach($importFields as $importField) { $dateTimeType = IsDateFieldType( $this->pSet->getFieldType($importField) ); if( strtoupper($headerField) == strtoupper($importField) ) { $tempFieldArray[ $idx ]["fName"] = $importField; $tempFieldArray[ $idx ]["dateTimeType"] = $dateTimeType; } $gName = GoodFieldName($importField); if( strtoupper($headerField) == strtoupper(trim( $gName )) ) { $tempGNamesArray[ $idx ]["fName"] = $importField; $tempGNamesArray[ $idx ]["dateTimeType"] = $dateTimeType; } $label = GetFieldLabel(GoodFieldName($this->tName), GoodFieldName($importField)); if( strtoupper($headerField) == strtoupper(trim( $label )) ) { $tempLabelArray[ $idx ]["fName"] = $importField; $tempLabelArray[ $idx ]["dateTimeType"] = $dateTimeType; } } } if( !count($tempFieldArray) && !count($tempGNamesArray) && !count($tempLabelArray) ) return array(); if( count($tempFieldArray) >= count($tempLabelArray) && count($tempFieldArray) >= count($tempGNamesArray) ) return $tempFieldArray; if( count($tempLabelArray) >= count($tempFieldArray) && count($tempLabelArray) >= count($tempGNamesArray) ) return $tempLabelArray; return $tempGNamesArray; } /** * Import data form a file to db * @param String filePath * @param Array &importData * @return Array */ public function ImportFromFile( $filePath, &$importData ) { $fieldsData = $this->refineImportFielsData( $importData["importFieldsData"] ); $dateFormat = getRefinedDateFormat( $this->getImportDateFormat( $importData["dateFormat"] ) ); $this->currentDateFormat = $dateFormat; if( $importData["CSV"] ) $metaData = $this->importFromCSV( $filePath, $fieldsData, $importData["useHeadersLine"], $importData["delimiter"] ); else $metaData = $this->importFromExcel( $filePath, $fieldsData, $importData["useHeadersLine"] ); $resultData = array(); $resultData["reportText"] = $this->getBasicReportText( $metaData["totalRecords"], $metaData["addedRecords"], $metaData["updatedRecords"] ); $resultData["unprocessedRecordsNumber"] = count( $metaData["errorMessages"] ); $resultData["totalRecordsNumber"] = $metaData["totalRecords"] - $resultData["unprocessedRecordsNumber"]; // prepare a report file $reportFileText = $this->getBasicReportText( $metaData["totalRecords"], $metaData["addedRecords"], $metaData["updatedRecords"], false, "\r\n", $metaData["errorMessages"], $metaData["unprocessedData"] ); $logFilePath = getabspath("templates_c/".$this->getImportLogFileName().".txt"); runner_save_file( $logFilePath, $reportFileText ); $resultData["logFilePath"] = $logFilePath; if( count( $metaData["unprocessedData"] ) ) { // prepare an unprocessed data log $unprocFilePath = getabspath("templates_c/".$this->getUnprocessedDataFileName().".csv"); $unprocContent = $this->getUnprocessedDataContent( $metaData["unprocessedData"] ); runner_save_file( $unprocFilePath, $unprocContent ); $resultData["unprocessedFilePath"] = $unprocFilePath; } return $resultData; } /** * @param String * @return String dateFormat */ protected function getImportDateFormat( $dateFormat ) { global $locale_info; return !strlen($dateFormat) ? $locale_info["LOCALE_SSHORTDATE"] : $dateFormat; } /** * Refine user import fields data * @param Array importFiledsData * @return Array */ protected function refineImportFielsData( $importFiledsData ) { $fieldsData = array(); foreach($importFiledsData as $idx => $fData) { $fName = $fData["fName"]; if( $fName ) $fieldsData[ $idx ] = array( "fName" => $fName, "type" => $this->pSet->getFieldType($fName) ); } return $fieldsData; } /** * Import data form a CSV file * @param String filePath * @param Array fieldsData * @param Boolean useFirstLine * @param String delimiter * @param String dateFormat * @return Array */ protected function importFromCSV( $filePath, $fieldsData, $useFirstLine, $delimiter ) { $metaData = array(); $metaData["totalRecords"] = 0; $fileHandle = OpenCSVFile( $filePath, $delimiter ); if( $fileHandle === FALSE ) return $metaData; $keys = $this->pSet->getTableKeys(); $autoinc = $this->hasAutoincImportFields( $fieldsData ); $errorMessages = array(); $unprocessedData = array(); $addedRecords = 0; $updatedRecords = 0; if( $this->connection->dbType == nDATABASE_MSSQLServer && $autoinc ) { $sql = "SET IDENTITY_INSERT ".$this->connection->addTableWrappers($this->strOriginalTableName)." ON"; $this->connection->exec( $sql ); } $row = 0; // parse records from file while( ($elems = GetCSVLine($fileHandle, 1000000, $delimiter)) !== FALSE ) { if( $row === 0 && (!$useFirstLine || $useFirstLine === "false") ) //for asp, $useFirstLine is string type { $row++; continue; } $fieldsValuesData = array(); foreach( $elems as $idx => $elem ) { if( !isset( $fieldsData[ $idx ] ) ) continue; $importFieldName = $fieldsData[ $idx ]["fName"]; $fType = $fieldsData[ $idx ]["type"]; $fieldsValuesData[ $importFieldName ] = $elem; } $this->importRecord( $fieldsValuesData, $keys, $autoinc, $addedRecords, $updatedRecords, $errorMessages, $unprocessedData ); $metaData["totalRecords"] = $metaData["totalRecords"] + 1; $row++; } CloseCSVFile($fileHandle); if( $this->connection->dbType == nDATABASE_MSSQLServer && $autoinc ) { $sql = "SET IDENTITY_INSERT ".$this->connection->addTableWrappers( $this->strOriginalTableName )." OFF"; $this->connection->exec( $sql ); } $metaData["addedRecords"] = $addedRecords; $metaData["updatedRecords"] = $updatedRecords; $metaData["errorMessages"] = $errorMessages; $metaData["unprocessedData"] = $unprocessedData; return $metaData; } /** * Import data form an Excel file * @param String filePath * @param Array fieldsData * @param Boolean useFirstLine * @param String dateFormat * @return Array */ protected function importFromExcel( $filePath, $fieldsData, $useFirstLine ) { $ext = getFileExtension( $filePath ); $fileHandle = openImportExcelFile( $filePath, $ext ); $keys = $this->pSet->getTableKeys(); $autoinc = $this->hasAutoincImportFields( $fieldsData ); if( $this->connection->dbType == nDATABASE_MSSQLServer && $autoinc ) { $sql = "SET IDENTITY_INSERT ".$this->connection->addTableWrappers( $this->strOriginalTableName )." ON"; $this->connection->exec( $sql ); } $metaData = ImportDataFromExcel( $fileHandle, $fieldsData, $keys, $this, $autoinc, $useFirstLine ); if( $this->connection->dbType == nDATABASE_MSSQLServer && $autoinc ) { $sql = "SET IDENTITY_INSERT ".$this->connection->addTableWrappers( $this->strOriginalTableName )." OFF"; $this->connection->exec( $sql ); } return $metaData; } /** * Check if there is an auto-incremented field among the import fields * @param Array fieldsData * @return Boolean */ protected function hasAutoincImportFields( $fieldsData ) { // $importFields = $this->pSet->getImportFields(); foreach( $fieldsData as $f ) { if( $this->pSet->isAutoincField( $f[ "fName" ] ) ) return true; } return false; } /** * Get an SQL query inserting a record * @param Array fields * @param Array fieldsValuesData * @return String */ public function getInsertSQL( $fields, $fieldsValuesData ) { $fieldsList = array(); foreach($fields as $field) { $fieldsList[] = $this->getTableField( $field ); } $valuesList = array(); foreach($fieldsValuesData as $key => $val) { if( !is_null($val) ) $valuesList[] = $this->cipherer->AddDBQuotes($key, $val); else $valuesList[] = "NULL"; } return "insert into ".$this->connection->addTableWrappers( $this->strOriginalTableName ) ." (".implode(",", $fieldsList).") values (".implode(",", $valuesList).")"; } /** * Get an SQL query updating a record * @param Array notKeyFields * @param Array fieldsValuesData * @param String updateWhere * @return String */ public function getUpdateSQL( $notKeyFields, $fieldsValuesData, $updateWhere ) { $sql = "update ".$this->connection->addTableWrappers( $this->strOriginalTableName )." set "; $sqlset = array(); foreach($notKeyFields as $field) { $dbFName = $this->getTableField( $field ); if( !is_null($fieldsValuesData[ $field ]) ) $sqlset[] = $dbFName."=".$this->cipherer->AddDBQuotes( $field, $fieldsValuesData[ $field ] ); else $sqlset[] = $dbFName." = NULL"; } $sql.= implode(", ", $sqlset)." where ".$updateWhere; return $sql; } /** * Get where clause condition for an 'update' SQL query * @param Array keyFields * @param Array fieldsValuesData * @return String */ public function getUpdateSQLWhere( $keyFields, $fieldsValuesData ) { $where = array(); foreach($keyFields as $field) { $where[] = $this->getFieldSQL($field) . "=" .$this->cipherer->AddDBQuotes( $field, $fieldsValuesData[ $field ] ); } return implode(" and ", $where); } /** * Prepare fields' values of numeric and time types for db * The fields of other types have been already db-prepared * @param Array fieldsValuesData * @return Array */ protected function prepareFiledsValuesData( $fieldsValuesData ) { global $locale_info; $refinedFieldsValuesData = array(); $this->setUpdatedLatLng($fieldsValuesData); foreach($fieldsValuesData as $field => $val) { $type = $this->pSet->getFieldType($field); if( IsTimeType($type) ) { $value = prepare_for_db( $field, $val, "time", "", $this->tName ); if ( strlen($value) > 0 ) $refinedFieldsValuesData[ $field ] = $value; else $refinedFieldsValuesData[ $field ] = NULL; continue; } if( IsDateFieldType($type) ) { if( !dateInDbFormat( $val ) ) $value = localdatetime2db($val, $this->currentDateFormat); else $value = $val; if ( strlen($value) > 0 ) $refinedFieldsValuesData[ $field ] = $value; else $refinedFieldsValuesData[ $field ] = NULL; continue; } if( !IsNumberType($type) ) { $refinedFieldsValuesData[ $field ] = $val; continue; } $value = str_replace(",", ".", (string)$val); if( strlen($value) > 0 ) { if( strpos($value, $locale_info["LOCALE_SCURRENCY"]) !== FALSE ) { // try to process the currency format $value = str_replace( array($locale_info["LOCALE_SCURRENCY"], " "), array("", ""), $value ); $matches = array(); if( preg_match('/^\((.*)\)$/', $value, $matches) ) $value = -1 * $matches[1]; } $refinedFieldsValuesData[ $field ] = 0 + $value; } else $refinedFieldsValuesData[ $field ] = NULL; } return $refinedFieldsValuesData; } /** * Insert an imported record to the database * @param Array fieldsValuesData An array having the import fields names as 'keys' and the corresponding fields' values as 'values' * @param Array keys The key fields' names * @param Boolean isIdentityOffNeeded The flag indicating if there is any autoincremented import field * @param &Number addedRecords * @param &Number updatedRecords * @param &Array errorMmessages * @param &Array unprocessedData */ public function importRecord( $fieldsValuesData, $keys, $isIdentityOffNeeded, &$addedRecords, &$updatedRecords, &$errorMessages, &$unprocessedData ) { $rawvalues = $fieldsValuesData; $fieldsValuesData = $this->prepareFiledsValuesData( $fieldsValuesData ); $fieldNames = array_keys( $fieldsValuesData ); $errorMessage=""; $failed = false; if( $this->eventsObject->exists("BeforeInsert") ) { // fire event if( $this->eventsObject->BeforeInsert($rawvalues, $fieldsValuesData, $this, $errorMessage) === false ) $failed = true; } if( !$failed ) { // $fieldsValuesData might have been changed in the event $fieldNames = array_keys( $fieldsValuesData ); // try to insert the record $sql = $this->getInsertSQL( $fieldNames, $fieldsValuesData ); if( db_exec_import($sql, $this->connection, $this->connection->addTableWrappers( $this->strOriginalTableName ), $isIdentityOffNeeded) ) { // insert successful $addedRecords = $addedRecords + 1; if( $this->audit ) $this->audit->LogAdd( $this->tName, $fieldsValuesData, GetKeysArray($fieldsValuesData, $this, true) ); return; } $errorMessage = $this->connection->lastError(); // prepare for updating attempt $keyFieldsNames = array_intersect($fieldNames, $keys); // don't update if we don't have all the key field values if( !$keyFieldsNames || count($keyFieldsNames) != count($keys) ) $failed = true; } if( !$failed ) { // prepare update $updateWhere = $this->getUpdateSQLWhere($keyFieldsNames, $fieldsValuesData); $getAllUpdatedSQL = "select * from " .$this->connection->addTableWrappers( $this->strOriginalTableName ). " where " . $updateWhere; $rs = $this->connection->querySilent( $getAllUpdatedSQL ); $data = null; if( $rs ) $data = $rs->fetchAssoc(); if( !$data ) $failed = true; } if( !$failed ) { // do update $notKeyFieldsNames = array_diff($fieldNames, $keys); $sql = $this->getUpdateSQL($notKeyFieldsNames, $fieldsValuesData, $updateWhere); if( !db_exec_import($sql, $this->connection, $this->connection->addTableWrappers( $this->strOriginalTableName ), $isIdentityOffNeeded) ) $failed = true; } if( !$failed ) { // report update successful $updatedRecords = $updatedRecords + 1; if( $this->audit ) { $auditOldValues = array(); foreach ($data as $key => $val) { $auditOldValues[ $key ] = $val; } $this->audit->LogEdit( $this->tName, $fieldsValuesData, $auditOldValues, GetKeysArray($fieldsValuesData, $this) ); } } if( $failed ) { // report error if( !count($unprocessedData) ) $unprocessedData[] = $this->getImportFieldsLogCSVLine( $fieldNames ); // nothing to update $unprocessedData[] = $this->parseValuesDataInLogCSVLine( $rawvalues ); $errorMessages[] = $errorMessage; } } /** * Get a data line for an unprocessed data log * @param Array fieldsValuesData * @return String */ protected function parseValuesDataInLogCSVLine( $fieldsValuesData ) { $values = array(); foreach($fieldsValuesData as $fName => $value) { $fType = $this->pSet->getFieldType($fName); if( !IsBinaryType($fType) ) $values[] = '"'.str_replace('"', '""', $value).'"'; } return implode(",", $values); } /** * Get a headers line for an unprocessed data log * @param Array importFields * @return String */ protected function getImportFieldsLogCSVLine( $importFields ) { $headerFields = array(); foreach( $importFields as $fName ) { $fType = $this->pSet->getFieldType($fName); if( !IsBinaryType($fType) ) $headerFields[] = '"'.str_replace('"', '""', $fName).'"'; } return implode(",", $headerFields); } /** * Get content for an unprocessed data log * @param Array unprocessedData * @return String */ protected function getUnprocessedDataContent( $unprocessedData ) { global $useUTF8; $content = $headerLine.implode( "\r\n", $unprocessedData ); return $useUTF8 ? "\xEF\xBB\xBF".$content : $content; } /** * Get report text * @param Number totalRecords * @param Number addedRecords * @param Number updatedRecords * @param Boolean isNotLogFile * @rturn String */ protected function getBasicReportText( $totalRecords, $addedRecords, $updatedRecords, $isNotLogFile = true, $lineBreak = "
", $errorMessages = array(), $unprocessedData = array() ) { $importedReords = $addedRecords + $updatedRecords; $notImportedRecords = $totalRecords - $importedReords; $boldBegin = ""; $boldEnd = ""; $reportText = ""; if( $isNotLogFile ) { $boldBegin = ""; $boldEnd = ""; } else { $reportText .= mlang_message("IMPORT_INTO")." ".$this->strOriginalTableName.$lineBreak. str_format_datetime( db2time( now() ) ) .$lineBreak.$lineBreak; } $reportText .= mysprintf(mlang_message("IMPORT_RECORD_PROCESSED_SUCCESSFULLY"), array($boldBegin.$importedReords.$boldEnd, $boldBegin.$totalRecords.$boldEnd)) .$lineBreak. mysprintf(mlang_message("IMPORT_RECORDS_ADDED"), array($boldBegin.$addedRecords.$boldEnd)) .$lineBreak. mysprintf(mlang_message("IMPORT_RECORDS_UPDATED"), array($boldBegin.$updatedRecords.$boldEnd)) .$lineBreak; if( $notImportedRecords ) $reportText.= mysprintf(mlang_message("IMPORT_RECORDS_PROC_WITH_ERRORS"), array($boldBegin.$notImportedRecords.$boldEnd)); if( $notImportedRecords && count($errorMessages) ) { $reportText .= ":"; for( $i = 0; $i < count($errorMessages); $i++ ) { if( $isNotLogFile ) { $reportText.= $lineBreak.$errorMessages[ $i ]; } else { $reportText.= $lineBreak.$lineBreak.$errorMessages[ $i ].$lineBreak.$unprocessedData[ $i + 1 ]; } } } return $reportText; } /** * Get a temporary importing file name * @return String */ public function getImportTempFileName() { return "import".$this->getUniqueFileNameSuffix(); } /** * Get a temporary log file name * @return String */ public function getImportLogFileName() { return "importLog".$this->getUniqueFileNameSuffix(); } /** * Get an unprocessed data CSV file name * @return String */ public function getUnprocessedDataFileName() { return "importUnprocessed".$this->getUniqueFileNameSuffix(); } /** * Get the unique name suffix containig the date stamp * @return String */ protected function getUniqueFileNameSuffix() { $dateMarker = getYMDdate( time() ); return $dateMarker."_".$this->tName."_".generatePassword(5); } /** * Remove temp import files older than 3 days * from the 'templates_c' directory */ public function removeOldTemporaryFiles() { $this->deleteTemporaryFilesFromDir( "templates_c/" ); } public function deleteTemporaryFilesFromDir( $dir ) { $tempFilesDirectory = getabspath($dir); $fileNamesList = getFileNamesFromDir( $tempFilesDirectory ); $currentTime = strtotime(now()); // the word "import" + some letters + the 'Y-m-d' formatted date value + "_" + the table name + "_" + the unique sequence of length 5 + any extension $tempNamePattern = "/^import.*([\d]{4}-(0[1-9]|1[0-2])-([0-2][1-9]|3[0-1])).*_".$this->tName."_.{5}\.\w+/"; foreach($fileNamesList as $fileName) { $matches = array(); if( preg_match($tempNamePattern, $fileName, $matches) ) { $timeFromFileName = strtotime( $matches[1] ); if( $timeFromFileName !== FALSE && $currentTime - $timeFromFileName > 259200 ) deleteImportTempFile( $tempFilesDirectory.$fileName ); } } } public function importExplode($importText) { $flag = true; $tmpText = ""; $j = 0; $lines = array(); for($i=0;$itemplatefile; if( $this->eventsObject->exists("BeforeShowImport") ) $this->eventsObject->BeforeShowImport($this->xt, $templatefile, $this); $hiddenBricks = array( "import_rawtext_control", "import_preview", "import_process", "import_results", "error_message" ); $this->xt->displayBricksHidden( $hiddenBricks ); $this->display( $templatefile ); } } ?>