public function ajaxProcessBackupDb() { if (!$this->getConfig('PS_AUTOUP_BACKUP')) { $this->stepDone = true; $this->nextParams['dbStep'] = 0; $this->next_desc = sprintf($this->l('Database backup skipped. Now upgrading files...'), $this->backupName); $this->next = 'upgradeFiles'; return true; } $relative_backup_path = str_replace(_PS_ROOT_DIR_, '', $this->backupPath); $report = ''; if (!ConfigurationTest::test_dir($relative_backup_path, false, $report)) { $this->next_desc = $this->l('Backup directory is not writable '); $this->nextQuickInfo[] = 'Backup directory is not writable '; $this->nextErrors[] = 'Backup directory is not writable "' . $this->backupPath . '"'; $this->next = 'error'; $this->error = 1; return false; } $this->stepDone = false; $this->next = 'backupDb'; $this->nextParams = $this->currentParams; $start_time = time(); $psBackupAll = true; $psBackupDropTable = true; if (!$psBackupAll) { $ignore_stats_table = array(_DB_PREFIX_ . 'connections', _DB_PREFIX_ . 'connections_page', _DB_PREFIX_ . 'connections_source', _DB_PREFIX_ . 'guest', _DB_PREFIX_ . 'statssearch'); } else { $ignore_stats_table = array(); } // INIT LOOP if (!file_exists($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupDbList)) { if (!is_dir($this->backupPath . DIRECTORY_SEPARATOR . $this->backupName)) { mkdir($this->backupPath . DIRECTORY_SEPARATOR . $this->backupName); } $this->nextParams['dbStep'] = 0; $tablesToBackup = $this->db->executeS('SHOW TABLES LIKE "' . _DB_PREFIX_ . '%"', true, false); file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupDbList, base64_encode(serialize($tablesToBackup))); } if (!isset($tablesToBackup)) { $tablesToBackup = unserialize(base64_decode(file_get_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupDbList))); } $found = 0; $views = ''; // MAIN BACKUP LOOP // $written = 0; do { if (!empty($this->nextParams['backup_table'])) { // only insert (schema already done) $table = $this->nextParams['backup_table']; $lines = $this->nextParams['backup_lines']; } else { if (count($tablesToBackup) == 0) { break; } $table = current(array_shift($tablesToBackup)); $this->nextParams['backup_loop_limit'] = 0; } if ($written == 0 || $written > self::$max_written_allowed) { // increment dbStep will increment filename each time here $this->nextParams['dbStep']++; // new file, new step $written = 0; if (isset($fp)) { fclose($fp); } $backupfile = $this->backupPath . DIRECTORY_SEPARATOR . $this->backupName . DIRECTORY_SEPARATOR . $this->backupDbFilename; $backupfile = preg_replace("#_XXXXXX_#", '_' . str_pad($this->nextParams['dbStep'], 6, '0', STR_PAD_LEFT) . '_', $backupfile); // start init file // Figure out what compression is available and open the file if (file_exists($backupfile)) { $this->next = 'error'; $this->error = 1; $this->nextErrors[] = sprintf($this->l('Backup file %s already exists. Operation aborted.'), $backupfile); $this->nextQuickInfo[] = sprintf($this->l('Backup file %s already exists. Operation aborted.'), $backupfile); } if (function_exists('bzopen')) { $backupfile .= '.bz2'; $fp = bzopen($backupfile, 'w'); } elseif (function_exists('gzopen')) { $backupfile .= '.gz'; $fp = gzopen($backupfile, 'w'); } else { $fp = fopen($backupfile, 'w'); } if ($fp === false) { $this->nextErrors[] = sprintf($this->l('Unable to create backup database file %s.'), addslashes($backupfile)); $this->nextQuickInfo[] = sprintf($this->l('Unable to create backup database file %s.'), addslashes($backupfile)); $this->next = 'error'; $this->error = 1; $this->next_desc = $this->l('Error during database backup.'); return false; } $written += fwrite($fp, '/* Backup ' . $this->nextParams['dbStep'] . ' for ' . Tools14::getHttpHost(false, false) . __PS_BASE_URI__ . "\n * at " . date('r') . "\n */\n"); $written += fwrite($fp, "\n" . 'SET SESSION sql_mode = \'\';' . "\n\n"); $written += fwrite($fp, "\n" . 'SET NAMES \'utf8\';' . "\n\n"); $written += fwrite($fp, "\n" . 'SET FOREIGN_KEY_CHECKS=0;' . "\n\n"); // end init file } // Skip tables which do not start with _DB_PREFIX_ if (strlen($table) <= strlen(_DB_PREFIX_) || strncmp($table, _DB_PREFIX_, strlen(_DB_PREFIX_)) != 0) { continue; } // start schema : drop & create table only if (empty($this->currentParams['backup_table'])) { // Export the table schema $schema = $this->db->executeS('SHOW CREATE TABLE `' . $table . '`', true, false); if (count($schema) != 1 || !(isset($schema[0]['Table']) && isset($schema[0]['Create Table']) || isset($schema[0]['View']) && isset($schema[0]['Create View']))) { fclose($fp); if (file_exists($backupfile)) { unlink($backupfile); } $this->nextErrors[] = sprintf($this->l('An error occurred while backing up. Unable to obtain the schema of %s'), $table); $this->nextQuickInfo[] = sprintf($this->l('An error occurred while backing up. Unable to obtain the schema of %s'), $table); $this->next = 'error'; $this->error = 1; $this->next_desc = $this->l('Error during database backup.'); return false; } // case view if (isset($schema[0]['View'])) { $views .= '/* Scheme for view' . $schema[0]['View'] . " */\n"; if ($psBackupDropTable) { // If some *upgrade* transform a table in a view, drop both just in case $views .= 'DROP VIEW IF EXISTS `' . $schema[0]['View'] . '`;' . "\n"; $views .= 'DROP TABLE IF EXISTS `' . $schema[0]['View'] . '`;' . "\n"; } $views .= preg_replace('#DEFINER=[^\\s]+\\s#', 'DEFINER=CURRENT_USER ', $schema[0]['Create View']) . ";\n\n"; $written += fwrite($fp, "\n" . $views); $ignore_stats_table[] = $schema[0]['View']; } elseif (isset($schema[0]['Table'])) { // Case common table $written += fwrite($fp, '/* Scheme for table ' . $schema[0]['Table'] . " */\n"); if ($psBackupDropTable && !in_array($schema[0]['Table'], $ignore_stats_table)) { // If some *upgrade* transform a table in a view, drop both just in case $written += fwrite($fp, 'DROP VIEW IF EXISTS `' . $schema[0]['Table'] . '`;' . "\n"); $written += fwrite($fp, 'DROP TABLE IF EXISTS `' . $schema[0]['Table'] . '`;' . "\n"); // CREATE TABLE $written += fwrite($fp, $schema[0]['Create Table'] . ";\n\n"); } // schema created, now we need to create the missing vars $this->nextParams['backup_table'] = $table; $lines = $this->nextParams['backup_lines'] = explode("\n", $schema[0]['Create Table']); } } // end of schema // POPULATE TABLE if (!in_array($table, $ignore_stats_table)) { do { $backup_loop_limit = $this->nextParams['backup_loop_limit']; $data = $this->db->executeS('SELECT * FROM `' . $table . '` LIMIT ' . (int) $backup_loop_limit . ',200', false, false); $this->nextParams['backup_loop_limit'] += 200; $sizeof = $this->db->numRows(); if ($data && $sizeof > 0) { // Export the table data $written += fwrite($fp, 'INSERT INTO `' . $table . "` VALUES\n"); $i = 1; while ($row = $this->db->nextRow($data)) { // this starts a row $s = '('; foreach ($row as $field => $value) { $tmp = "'" . $this->db->escape($value, true) . "',"; if ($tmp != "'',") { $s .= $tmp; } else { foreach ($lines as $line) { if (strpos($line, '`' . $field . '`') !== false) { if (preg_match('/(.*NOT NULL.*)/Ui', $line)) { $s .= "'',"; } else { $s .= 'NULL,'; } break; } } } } $s = rtrim($s, ','); if ($i < $sizeof) { $s .= "),\n"; } else { $s .= ");\n"; } $written += fwrite($fp, $s); ++$i; } $time_elapsed = time() - $start_time; } else { unset($this->nextParams['backup_table']); unset($this->currentParams['backup_table']); break; } } while ($time_elapsed < self::$loopBackupDbTime && $written < self::$max_written_allowed); } $found++; $time_elapsed = time() - $start_time; $this->nextQuickInfo[] = sprintf($this->l('%1$s table has been saved.'), $table); } while ($time_elapsed < self::$loopBackupDbTime && $written < self::$max_written_allowed); // end of loop if (isset($fp)) { $written += fwrite($fp, "\n" . 'SET FOREIGN_KEY_CHECKS=1;' . "\n\n"); fclose($fp); unset($fp); } file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupDbList, base64_encode(serialize($tablesToBackup))); if (count($tablesToBackup) > 0) { $this->nextQuickInfo[] = sprintf($this->l('%1$s tables have been saved.'), $found); $this->next = 'backupDb'; $this->stepDone = false; if (count($tablesToBackup)) { $this->next_desc = sprintf($this->l('Database backup: %s table(s) left...'), count($tablesToBackup)); $this->nextQuickInfo[] = sprintf($this->l('Database backup: %s table(s) left...'), count($tablesToBackup)); } return true; } if ($found == 0 && !empty($backupfile)) { if (file_exists($backupfile)) { unlink($backupfile); } $this->nextErrors[] = sprintf($this->l('No valid tables were found to back up. Backup of file %s canceled.'), $backupfile); $this->nextQuickInfo[] = sprintf($this->l('No valid tables were found to back up. Backup of file %s canceled.'), $backupfile); $this->error = 1; $this->next_desc = sprintf($this->l('Error during database backup for file %s.'), $backupfile); return false; } else { unset($this->nextParams['backup_loop_limit']); unset($this->nextParams['backup_lines']); unset($this->nextParams['backup_table']); if ($found) { $this->nextQuickInfo[] = sprintf($this->l('%1$s tables have been saved.'), $found); } $this->stepDone = true; // reset dbStep at the end of this step $this->nextParams['dbStep'] = 0; $this->next_desc = sprintf($this->l('Database backup done in filename %s. Now upgrading files...'), $this->backupName); $this->next = 'upgradeFiles'; return true; } }