/** * Read a xml file and add all files to archive * * @throws Exception */ protected function addFiles() { // Check if xml exists if (!file_exists(TL_ROOT . '/' . $GLOBALS['TL_CONFIG']['uploadPath'] . '/syncCto_backups/dependencies.xml')) { throw new Exception("Missing dependencies.xml for autoupdater."); } // Create a new reader $objXMLReader = new XMLReader(); $objXMLReader->open(TL_ROOT . '/' . $GLOBALS['TL_CONFIG']['uploadPath'] . '/syncCto_backups/dependencies.xml'); $strCurrentNode = ""; // Run through each line while ($objXMLReader->read()) { switch ($objXMLReader->nodeType) { case XMLReader::ELEMENT: $strCurrentNode = $objXMLReader->localName; break; case XMLReader::TEXT: case XMLReader::CDATA: if ($strCurrentNode == "path") { // Check if file is in blacklist foreach ($this->arrBlackFiles as $strBlackfile) { if (preg_match('^' . $strBlackfile . '^i', $objXMLReader->value)) { continue; } } // Remove the TL_ROOT and the first '/' $strPath = preg_replace("/^TL_ROOT\\//i", "", $objXMLReader->value, 1); // If we have a sql parse it if (preg_match("/\\.sql\$/i", $strPath)) { $this->parseSQL($strPath); } // If file exists add it to archive if (file_exists(TL_ROOT . "/" . $strPath)) { if (!$this->objZipArchive->addFile($strPath, "FILES/" . $strPath)) { throw new Exception("Could not add the file " . $strPath . " to the archive."); } } } break; } } // Add the dependencies.xml if (!$this->objZipArchive->addFile($GLOBALS['TL_CONFIG']['uploadPath'] . '/syncCto_backups/dependencies.xml', "FILES/" . $GLOBALS['TL_CONFIG']['uploadPath'] . '/syncCto_backups/dependencies.xml')) { throw new Exception('Could not add the file /' . $GLOBALS['TL_CONFIG']['uploadPath'] . '/syncCto_backups/dependencies.xml to the archive.'); } }
/** * Make a incremental backup from a filelist * * @param string $srtXMLFilelist Path to XML filelist * @param stirng $strZipFolder Path to the folder * @param string $strZipFile Name of zipfile. If empty a filename will be create. * @return array array{"folder"=>[string],"file"=>[string],"fullpath"=>[string],"xml"=>[string],"done"=>[boolean]} * @throws Exception */ public function runIncrementalDump($srtXMLFilelist, $strZipFolder, $strZipFile = null, $intMaxFilesPerRun = 5) { $floatTimeStart = microtime(true); // Check if filelist exists if (!file_exists(TL_ROOT . DIRECTORY_SEPARATOR . $srtXMLFilelist)) { throw new Exception("File not found: " + $srtXMLFilelist); } // Create, check zip name if ($strZipFile == null || $strZipFile == "") { $strZipFile = date($this->strTimestampFormat) . "_" . $this->strSuffixZipName; } else { $strZipFile = str_replace(array(" "), array("_"), preg_replace("/\\.zip\\z/i", "", $strZipFile)) . ".zip"; } // Build Path $strZipFolder = $this->objSyncCtoHelper->standardizePath($strZipFolder); $strZipPath = $this->objSyncCtoHelper->standardizePath($strZipFolder, $strZipFile); // Open XML Reader $objXml = new DOMDocument("1.0", "UTF-8"); $objXml->load(TL_ROOT . DIRECTORY_SEPARATOR . $srtXMLFilelist); // Check if we have some files if ($objXml->getElementsByTagName("file")->length == 0) { return array("folder" => $strZipFolder, "file" => $strZipFile, "fullpath" => $strZipPath, "xml" => $srtXMLFilelist, "done" => true); } // Open ZipArchive $objZipArchive = new ZipArchiveCto(); if (($mixError = $objZipArchive->open($strZipPath, ZipArchiveCto::CREATE)) !== true) { throw new Exception($GLOBALS['TL_LANG']['MSC']['error'] . ": " . $objZipArchive->getErrorDescription($mixError)); } // Get all files $objFilesList = $objXml->getElementsByTagName("file"); $objNodeFiles = $objXml->getElementsByTagName("files")->item(0); $arrFinished = array(); $intRuns = 0; // Run through each foreach ($objFilesList as $file) { // Check if file exists if (file_exists(TL_ROOT . DIRECTORY_SEPARATOR . $file->nodeValue)) { $objZipArchive->addFile($file->nodeValue, $file->nodeValue); } // Add file to finished list $arrFinished[] = $file; $intRuns++; // After 5 files add all to zip if ($intRuns == $intMaxFilesPerRun) { $objZipArchive->close(); $objZipArchive->open($strZipPath, ZipArchiveCto::CREATE); $intRuns = 0; } // Check time out if (microtime(true) - $floatTimeStart > $this->intMaxExecutionTime) { break; } } // Remove finished files from xml foreach ($arrFinished as $value) { $objNodeFiles->removeChild($value); } // Close XML and zip $objXml->save(TL_ROOT . DIRECTORY_SEPARATOR . $srtXMLFilelist); $objZipArchive->close(); if ($objXml->getElementsByTagName("file")->length == 0) { $booFinished = true; } else { $booFinished = false; } // Return informations return array("folder" => $strZipFolder, "file" => $strZipFile, "fullpath" => $strZipPath, "xml" => $srtXMLFilelist, "done" => $booFinished); }
/** * Function for creating a sql/xml dump file. * * @param array $mixTables Table or a list of tables for backup * @param string $strZip Name of zip file * @param bool $booTempFolder Should the tmp folde used instead of backupfolder * @return void */ public function runDump($mixTables, $booTempFolder, $booOnlyMachine = true) { // Set time limit to unlimited set_time_limit(0); // Set limit for db query. Ticket #163 if ($GLOBALS['TL_CONFIG']['syncCto_custom_settings'] == true && intval($GLOBALS['TL_CONFIG']['syncCto_db_query_limt']) > 0) { $intElementsPerRequest = intval($GLOBALS['TL_CONFIG']['syncCto_db_query_limt']); } else { $intElementsPerRequest = 500; } // Add to the backup array all tables if (is_array($mixTables)) { $this->arrBackupTables = array_merge($this->arrBackupTables, $mixTables); } else { if ($mixTables != "" && $mixTables != null) { $this->arrBackupTables[] = $mixTables; } } // make the backup array unique $this->arrBackupTables = array_unique($this->arrBackupTables); // Check if we have some tables for backup if (!is_array($this->arrBackupTables) || $this->arrBackupTables == null || count($this->arrBackupTables) == 0) { throw new Exception("No tables found for backup."); } // Get a list of all Tables $arrTables = $this->Database->listTables(); // Write some tempfiles $strRandomToken = md5(time() . " | " . rand(0, 65535)); // Write SQL file if ($booOnlyMachine == false) { $objFileSQL = new File($this->objSyncCtoHelper->standardizePath($GLOBALS['SYC_PATH']['tmp'], "TempSQLDump.{$strRandomToken}")); $objFileSQL->write(""); } // Write gzip xml file $objGzFile = new File($this->objSyncCtoHelper->standardizePath($GLOBALS['SYC_PATH']['tmp'], "TempSyncCtoDump.{$strRandomToken}")); $objGzFile->write(""); $objGzFile->close(); // Compression $objGzFile = gzopen(TL_ROOT . "/" . $this->objSyncCtoHelper->standardizePath($GLOBALS['SYC_PATH']['tmp'], "TempSyncCtoDump.{$strRandomToken}"), "wb"); // Create XML File $objXml = new XMLWriter(); $objXml->openMemory(); $objXml->setIndent(true); $objXml->setIndentString("\t"); // XML Start $objXml->startDocument('1.0', 'UTF-8'); $objXml->startElement('database'); // Write meta (header) $objXml->startElement('metatags'); $objXml->writeElement('version', $GLOBALS['SYC_VERSION']); $objXml->writeElement('create_unix', time()); $objXml->writeElement('create_date', date('Y-m-d', time())); $objXml->writeElement('create_time', date('H:i', time())); $objXml->endElement(); // End metatags $objXml->startElement('structure'); foreach ($arrTables as $key => $TableName) { // Check if the current table marked as backup if (!in_array($TableName, $this->arrBackupTables)) { continue; } // Get data $arrStructure = $this->getTableStructure($TableName); // Check if empty if (count($arrStructure) == 0) { continue; } $objXml->startElement('table'); $objXml->writeAttribute("name", $TableName); $objXml->startElement('fields'); if (is_array($arrStructure['TABLE_FIELDS'])) { foreach ($arrStructure['TABLE_FIELDS'] as $keyField => $valueField) { $objXml->startElement('field'); $objXml->writeAttribute("name", $keyField); $objXml->text($valueField); $objXml->endElement(); // End field } } $objXml->endElement(); // End fields $objXml->startElement('definitions'); if (is_array($arrStructure['TABLE_CREATE_DEFINITIONS'])) { foreach ($arrStructure['TABLE_CREATE_DEFINITIONS'] as $keyField => $valueField) { $objXml->startElement('def'); $objXml->writeAttribute("name", $keyField); $objXml->text($valueField); $objXml->endElement(); // End field } } $objXml->endElement(); // End fields $objXml->startElement("option"); $objXml->text($arrStructure['TABLE_OPTIONS']); $objXml->endElement(); $objXml->endElement(); // End table } // Push structure into file. $strXMLFlush = $objXml->flush(true); gzputs($objGzFile, $strXMLFlush, strlen($strXMLFlush)); $objXml->endElement(); // End structure $objXml->startElement('data'); foreach ($arrTables as $key => $TableName) { // Check if the current table marked as backup if (!in_array($TableName, $this->arrBackupTables)) { continue; } // Check if table is in blacklist if (!in_array($TableName, $this->arrBackupTables)) { continue; } // Get fields $fields = $this->Database->listFields($TableName); $arrFieldMeta = array(); foreach ($fields as $key => $value) { if ($value["type"] == "index") { continue; } $arrFieldMeta[$value["name"]] = $value; } $objXml->startElement('table'); $objXml->writeAttribute('name', $TableName); for ($i = 0; true; $i++) { // Push into file. $strXMLFlush = $objXml->flush(true); gzputs($objGzFile, $strXMLFlush, strlen($strXMLFlush)); $objData = $this->Database->prepare("SELECT * FROM {$TableName}")->limit($intElementsPerRequest, $i * $intElementsPerRequest)->executeUncached(); if ($objData->numRows == 0) { break; } while ($row = $objData->fetchAssoc()) { $objXml->startElement('row'); $objXml->writeAttribute("id", $row["id"]); foreach ($row as $field_key => $field_data) { $objXml->startElement('field'); $objXml->writeAttribute("name", $field_key); if (!isset($field_data)) { $objXml->writeAttribute("type", "null"); $objXml->text("NULL"); } else { if ($field_data != "") { switch (strtolower($arrFieldMeta[$field_key]['type'])) { case 'binary': case 'varbinary': case 'blob': case 'tinyblob': case 'mediumblob': case 'longblob': $objXml->writeAttribute("type", "blob"); $objXml->text("0x" . bin2hex($field_data)); break; case 'tinyint': case 'smallint': case 'mediumint': case 'int': case 'integer': case 'bigint': $objXml->writeAttribute("type", "int"); $objXml->text($field_data); break; case 'float': case 'double': case 'real': case 'decimal': case 'numeric': $objXml->writeAttribute("type", "decimal"); $objXml->text($field_data); break; case 'date': case 'datetime': case 'timestamp': case 'time': case 'year': $objXml->writeAttribute("type", "date"); $objXml->text("'" . $field_data . "'"); break; case 'char': case 'varchar': case 'text': case 'tinytext': case 'mediumtext': case 'longtext': case 'enum': case 'set': $objXml->writeAttribute("type", "text"); $objXml->writeCdata(base64_encode(str_replace($this->arrSearchFor, $this->arrReplaceWith, $field_data))); break; default: $objXml->writeAttribute("type", "default"); $objXml->writeCdata(base64_encode(str_replace($this->arrSearchFor, $this->arrReplaceWith, $field_data))); break; } } else { $objXml->writeAttribute("type", "empty"); $objXml->text("''"); } } $objXml->endElement(); // End field } $objXml->endElement(); // End row } } $objXml->endElement(); // End table } $objXml->endElement(); // End data $objXml->endElement(); // End database $strXMLFlush = $objXml->flush(true); gzputs($objGzFile, $strXMLFlush, strlen($strXMLFlush)); gzclose($objGzFile); if ($booOnlyMachine == false) { // Write header for sql file $today = date("Y-m-d"); $time = date("H:i:s"); // Write Header $string .= "-- syncCto SQL Dump\r\n"; $string .= "-- Version " . $GLOBALS['SYC_VERSION'] . "\r\n"; $string .= "-- http://men-at-work.de\r\n"; $string .= "-- \r\n"; $string .= "-- Time stamp : {$today} at {$time}\r\n"; $string .= "\r\n"; $string .= "SET SQL_MODE=\"NO_AUTO_VALUE_ON_ZERO\";\r\n"; $string .= "\r\n"; $string .= "-- --------------------------------------------------------\r\n"; $string .= "\r\n"; $objFileSQL->append($string, ""); $objFileSQL->close(); $string = ""; // Run each table foreach ($arrTables as $key => $TableName) { // Check if table is in blacklist if (!in_array($TableName, $this->arrBackupTables)) { continue; } // Get data $arrStructure = $this->getTableStructure($TableName); // Check if empty if (count($arrStructure) == 0) { continue; } // Write SQL $string .= "-- \r\n"; $string .= "-- Dumping table {$TableName} \r\n"; $string .= "-- \r\n"; $string .= "\r\n"; $string .= $this->buildSQLTable($arrStructure, $TableName); $string .= "\r\n"; $string .= "\r\n"; $objFileSQL->append($string, ""); $objFileSQL->close(); $string = ""; // Get fields $fields = $this->Database->listFields($TableName); $arrFieldMeta = array(); foreach ($fields as $key => $value) { if ($value["type"] == "index") { continue; } $arrFieldMeta[$value["name"]] = $value; } $booFirstEntry = true; for ($i = 0; true; $i++) { $objData = $this->Database->prepare("SELECT * FROM {$TableName}")->limit($intElementsPerRequest, $i * $intElementsPerRequest)->executeUncached(); $strSQL = ""; // Check if we have some files if ($objData->numRows == 0) { // if end reach insert ';' if ($booFirstEntry != true) { $strSQL .= ";\r\n\r\n"; } $strSQL .= "-- --------------------------------------------------------\r\n\r\n"; $objFileSQL->append($strSQL, ""); $objFileSQL->close(); break; } // Start INSERT INTO if ($i == 0) { $strSQL .= "INSERT IGNORE INTO " . $TableName . " (`"; $strSQL .= implode("`, `", array_keys($arrFieldMeta)); $strSQL .= "`) VALUES"; } // Run through each row while ($row = $objData->fetchAssoc()) { $arrTableData = array(); foreach (array_keys($arrFieldMeta) as $fieldName) { if (!isset($row[$fieldName])) { $arrTableData[] = "NULL"; } else { if ($row[$fieldName] != "") { switch (strtolower($arrFieldMeta[$fieldName]['type'])) { case 'blob': case 'tinyblob': case 'mediumblob': case 'longblob': $arrTableData[] = "0x" . bin2hex($row[$fieldName]); break; case 'smallint': case 'int': $arrTableData[] = $row[$fieldName]; break; case 'text': case 'mediumtext': if (strpos($row[$fieldName], "'") != false) { $arrTableData[] = "0x" . bin2hex($row[$fieldName]); break; } default: $arrTableData[] = "'" . str_replace($this->arrSearchFor, $this->arrReplaceWith, $row[$fieldName]) . "'"; break; } } else { $arrTableData[] = "''"; } } } if ($booFirstEntry == true) { $booFirstEntry = false; $strSQL .= "\r\n(" . implode(", ", $arrTableData) . ")"; } else { $strSQL .= ",\r\n(" . implode(", ", $arrTableData) . ")"; } if (strlen($strSQL) > 100000) { $objFileSQL->append($strSQL, ""); $objFileSQL->close(); $strSQL = ""; } } if (strlen($strSQL) != 0) { $objFileSQL->append($strSQL, ""); $objFileSQL->close(); $strSQL = ""; } } } } if ($booOnlyMachine == false) { $objFileSQL->close(); } $strFilename = date($this->strTimestampFormat) . "_" . $this->strSuffixZipName; if ($booTempFolder) { $strPath = $GLOBALS['SYC_PATH']['tmp']; } else { $strPath = $GLOBALS['SYC_PATH']['db']; } $objZipArchive = new ZipArchiveCto(); $objZipArchive->open($strPath . $strFilename, ZipArchiveCto::CREATE); if ($booOnlyMachine == false) { $objZipArchive->addFile("system/tmp/TempSQLDump.{$strRandomToken}", $this->strFilenameSQL); } $objZipArchive->addFile("system/tmp/TempSyncCtoDump.{$strRandomToken}", $this->strFilenameSyncCto); $objZipArchive->close(); $objFiles = Files::getInstance(); if ($booOnlyMachine == false) { $objFiles->delete("system/tmp/TempSQLDump.{$strRandomToken}"); } $objFiles->delete("system/tmp/TempSyncCtoDump.{$strRandomToken}"); return $strFilename; }