public function ajaxProcessBackupFiles() { $this->nextParams = $this->currentParams; $this->stepDone = false; if (empty($this->backupFilesFilename)) { $this->next = 'error'; $this->nextDesc = $this->l('error during backupFiles'); $this->nextQuickInfo[] = '[ERROR] backupFiles filename has not been set'; return false; } if (empty($this->nextParams['filesForBackup'])) { // @todo : only add files and dir listed in "originalPrestashopVersion" list $filesToBackup = $this->_listFilesInDir($this->prodRootDir); file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList, serialize($filesToBackup)); $this->nextQuickInfo[] = sprintf($this->l('%s Files to backup.'), sizeof($this->toBackupFileList)); $this->nextParams['filesForBackup'] = $this->toBackupFileList; // delete old backup, create new if (!empty($this->backupFilesFilename) && file_exists($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename)) { unlink($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } $this->nextQuickInfo[] = sprintf($this->l('backup files initialized in %s'), $this->backupFilesFilename); } $filesToBackup = unserialize(file_get_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList)); ///////////////////// $this->next = 'backupFiles'; // @TODO : display percent instead of this $this->nextDesc = sprintf($this->l('Backup files in progress. %s files left'), sizeof($filesToBackup)); if (is_array($filesToBackup)) { // @TODO later // 1) calculate crc32 or md5 of next file // 2) use the provided xml with crc32 calculated from previous versions ? // or simply use the latest dir ? //$current = crc32(file_get_contents($file)); //$file = $this->nextParams['filesForBackup'][0]; //$latestFile = str_replace(_PS_ROOT_DIR_,$this->latestRootDir,$file); // if (file_exists($latestFile)) // $latest = crc32($latestFile); // else // $latest = ''; if (!self::$force_pclZip && class_exists('ZipArchive', false)) { $zip_archive = true; $zip = new ZipArchive(); $zip->open($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename, ZIPARCHIVE::CREATE); } else { $zip_archive = false; // pclzip can be already loaded (server configuration) if (!class_exists('PclZip', false)) { require_once dirname(__FILE__) . '/pclzip.lib.php'; } $zip = new PclZip($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } if ($zip) { $this->next = 'backupFiles'; // @TODO all in one time will be probably too long // 1000 ok during test, but 10 by 10 to be sure $this->stepDone = false; // @TODO min(self::$loopBackupFiles, sizeof()) for ($i = 0; $i < self::$loopBackupFiles; $i++) { if (sizeof($filesToBackup) <= 0) { $this->stepDone = true; $this->status = 'ok'; $this->next = 'backupDb'; $this->nextDesc = $this->l('All files saved. Now backup Database'); $this->nextQuickInfo[] = $this->l('all files have been added to archive.'); break; } // filesForBackup already contains all the correct files $file = array_shift($filesToBackup); $archiveFilename = ltrim(str_replace($this->prodRootDir, '', $file), DIRECTORY_SEPARATOR); if ($zip_archive) { $added_to_zip = $zip->addFile($file, $archiveFilename); if ($added_to_zip) { $this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s left.'), $archiveFilename, sizeof($filesToBackup)); } else { // if an error occur, it's more safe to delete the corrupted backup $zip->close(); if (file_exists($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename)) { unlink($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } $this->next = 'error'; $this->nextDesc = sprintf($this->l('error when trying to add %1$s to archive %2$s.'), $archiveFilename, $backupFilePath); break; } } else { $files_to_add[] = $file; $this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s left.'), $archiveFilename, sizeof($filesToBackup)); } } if ($zip_archive) { $zip->close(); } else { $added_to_zip = $zip->add($files_to_add, PCLZIP_OPT_REMOVE_PATH, $this->prodRootDir); $zip->privCloseFd(); if (!$added_to_zip) { $this->nextQuickInfo[] = '[ERROR] error on backup using pclzip : ' . $zip->errorInfo(true); $this->next = 'error'; } } file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList, serialize($filesToBackup)); return true; } else { $this->next = 'error'; $this->nextDesc = $this->l('unable to open archive'); return false; } } else { $this->stepDone = true; $this->next = 'backupDb'; $this->nextDesc = 'All files saved. Now backup Database'; return true; } // 4) save for display. }
public function ajaxProcessBackupFiles() { if (!$this->getConfig('PS_AUTOUP_BACKUP')) { $this->stepDone = true; $this->next = 'backupDb'; $this->next_desc = 'File backup skipped.'; return true; } $this->nextParams = $this->currentParams; $this->stepDone = false; if (empty($this->backupFilesFilename)) { $this->next = 'error'; $this->error = 1; $this->next_desc = $this->l('Error during backupFiles'); $this->nextErrors[] = $this->l('[ERROR] backupFiles filename has not been set'); $this->nextQuickInfo[] = $this->l('[ERROR] backupFiles filename has not been set'); return false; } if (empty($this->nextParams['filesForBackup'])) { // @todo : only add files and dir listed in "originalPrestashopVersion" list $filesToBackup = $this->_listFilesInDir($this->prodRootDir, 'backup', false); file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList, base64_encode(serialize($filesToBackup))); if (count($this->toBackupFileList)) { $this->nextQuickInfo[] = sprintf($this->l('%s Files to backup.'), count($this->toBackupFileList)); } $this->nextParams['filesForBackup'] = $this->toBackupFileList; // delete old backup, create new if (!empty($this->backupFilesFilename) && file_exists($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename)) { unlink($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } $this->nextQuickInfo[] = sprintf($this->l('backup files initialized in %s'), $this->backupFilesFilename); } $filesToBackup = unserialize(base64_decode(file_get_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList))); $this->next = 'backupFiles'; if (count($this->toBackupFileList)) { $this->next_desc = sprintf($this->l('Backup files in progress. %d files left'), count($filesToBackup)); } if (is_array($filesToBackup)) { $res = false; if (!self::$force_pclZip && class_exists('ZipArchive', false)) { $this->nextQuickInfo[] = $this->l('Using class ZipArchive...'); $zip_archive = true; $zip = new ZipArchive(); $res = $zip->open($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename, ZIPARCHIVE::CREATE); if ($res) { $res = isset($zip->filename) && $zip->filename ? true : false; } } if (!$res) { $zip_archive = false; $this->nextQuickInfo[] = $this->l('Using class PclZip...'); // pclzip can be already loaded (server configuration) if (!class_exists('PclZip', false)) { require_once dirname(__FILE__) . '/classes/pclzip.lib.php'; } $zip = new PclZip($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); $res = true; } if ($zip && $res) { $this->next = 'backupFiles'; $this->stepDone = false; $files_to_add = array(); $close_flag = true; for ($i = 0; $i < self::$loopBackupFiles; $i++) { if (count($filesToBackup) <= 0) { $this->stepDone = true; $this->status = 'ok'; $this->next = 'backupDb'; $this->next_desc = $this->l('All files saved. Now backing up database'); $this->nextQuickInfo[] = $this->l('All files have been added to archive.', 'AdminSelfUpgrade', true); break; } // filesForBackup already contains all the correct files $file = array_shift($filesToBackup); $archiveFilename = ltrim(str_replace($this->prodRootDir, '', $file), DIRECTORY_SEPARATOR); $size = filesize($file); if ($size < self::$maxBackupFileSize) { if ($zip_archive) { $added_to_zip = $zip->addFile($file, $archiveFilename); if ($added_to_zip) { if ($filesToBackup) { $this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s files left.', 'AdminSelfUpgrade', true), $archiveFilename, count($filesToBackup)); } } else { // if an error occur, it's more safe to delete the corrupted backup $zip->close(); if (file_exists($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename)) { unlink($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } $this->next = 'error'; $this->error = 1; $this->next_desc = sprintf($this->l('Error when trying to add %1$s to archive %2$s.', 'AdminSelfUpgrade', true), $file, $archiveFilename); $close_flag = false; break; } } else { $files_to_add[] = $file; if (count($filesToBackup)) { $this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %3$s) added to archive. %2$s files left.', 'AdminSelfUpgrade', true), $archiveFilename, count($filesToBackup), $size); } else { $this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %2$s) added to archive.', 'AdminSelfUpgrade', true), $archiveFilename, $size); } } } else { $this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %2$s) has been skipped during backup.', 'AdminSelfUpgrade', true), $archiveFilename, $size); $this->nextErrors[] = sprintf($this->l('File %1$s (size: %2$s) has been skipped during backup.', 'AdminSelfUpgrade', true), $archiveFilename, $size); } } if ($zip_archive && $close_flag && is_object($zip)) { $zip->close(); } elseif (!$zip_archive) { $added_to_zip = $zip->add($files_to_add, PCLZIP_OPT_REMOVE_PATH, $this->prodRootDir); if ($added_to_zip) { $zip->privCloseFd(); } if (!$added_to_zip) { if (file_exists($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename)) { unlink($this->backupPath . DIRECTORY_SEPARATOR . $this->backupFilesFilename); } $this->nextQuickInfo[] = sprintf($this->l('[ERROR] Error on backup using PclZip: %s.'), $zip->errorInfo(true)); $this->nextErrors[] = sprintf($this->l('[ERROR] Error on backup using PclZip: %s.'), $zip->errorInfo(true)); $this->next = 'error'; } } file_put_contents($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->toBackupFileList, base64_encode(serialize($filesToBackup))); return true; } else { $this->next = 'error'; $this->next_desc = $this->l('unable to open archive'); return false; } } else { $this->stepDone = true; $this->next = 'backupDb'; $this->next_desc = $this->l('All files saved. Now backing up database.'); return true; } // 4) save for display. }
function backup() { DHDO::logger('Begining Backup.'); global $wpdb; if (!is_dir(content_url() . '/upgrade/')) { DHDO::logger('Upgrade folder missing. This will cause serious issues with WP in general, so we will create it for you.'); mkdir(content_url() . '/upgrade/'); } // Pull in data for what to backup $sections = get_option('dh-do-backupsection'); if (!$sections) { $sections = array(); } $file = WP_CONTENT_DIR . '/upgrade/dreamobject-backups.zip'; $fileurl = content_url() . '/upgrade/dreamobject-backups.zip'; // Pre-Cleanup if (file_exists($file)) { @unlink($file); DHDO::logger('Leftover zip file found, deleting ' . $file . ' ...'); } try { $zip = new ZipArchive($file); $zaresult = true; DHDO::logger('ZipArchive found and will be used for backups.'); } catch (Exception $e) { $error_string = $e->getMessage(); $zip = new PclZip($file); DHDO::logger('ZipArchive not found. Error: ' . $error_string); DHDO::logger('PclZip will be used for backups.'); require_once ABSPATH . '/wp-admin/includes/class-pclzip.php'; $zaresult = false; } $backups = array(); // All me files! if (in_array('files', $sections)) { DHDO::logger('Calculating backup size...'); $trimdisk = WP_CONTENT_DIR; $diskcmd = sprintf("du -s %s", WP_CONTENT_DIR); $diskusage = exec($diskcmd); $diskusage = trim(str_replace($trimdisk, '', $diskusage)); DHDO::logger(size_format($diskusage * 1024) . ' of diskspace will be processed.'); if ($diskusage < 2000 * 1024) { $backups = array_merge($backups, DHDO::rscandir(WP_CONTENT_DIR)); DHDO::logger(count($backups) . ' files added to backup list.'); } else { DHDO::logger('ERROR! PHP is unable to backup your wp-content folder. Please consider cleaning out unused files (like plugins and themes).'); } if (file_exists(ABSPATH . 'wp-config.php')) { $backups[] = ABSPATH . 'wp-config.php'; DHDO::logger('wp-config.php added to backup list.'); } } // And me DB! if (in_array('database', $sections)) { set_time_limit(300); $sqlhash = wp_hash(wp_rand()); $sqlfile = WP_CONTENT_DIR . '/upgrade/' . $sqlhash . '.sql'; $tables = $wpdb->get_col("SHOW TABLES LIKE '" . $wpdb->prefix . "%'"); $tables_string = implode(' ', $tables); // Pre cleanup if (file_exists($sqlfile)) { @unlink($sqlfile); DHDO::logger('Leftover sql file found, deleting ' . $sqlfile . ' ...'); } $dbcmd = sprintf("mysqldump -h'%s' -u'%s' -p'%s' %s %s --single-transaction 2>&1 >> %s", DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, $tables_string, $sqlfile); exec($dbcmd); $sqlsize = size_format(@filesize($sqlfile)); DHDO::logger('SQL file created: ' . $sqlfile . ' (' . $sqlsize . ').'); $backups[] = $sqlfile; DHDO::logger('SQL added to backup list.'); } if (!empty($backups)) { set_time_limit(300); // Increased timeout to 5 minutes. If the zip takes longer than that, I have a problem. if ($zaresult != 'true') { DHDO::logger('Creating zip file using PclZip.'); DHDO::logger('NOTICE: If the log stops here, PHP failed to create a zip of your wp-content folder. Please consider increasing the server\'s PHP memory, RAM or CPU.'); $zip->create($backups); } else { DHDO::logger('Creating zip file using ZipArchive.'); DHDO::logger('NOTICE: If the log stops here, PHP failed to create a zip of your wp-content folder. Please consider cleaning out unused files (like plugins and themes), or increasing the server\'s PHP memory, RAM or CPU.'); try { $zip->open($file, ZipArchive::CREATE); $trimpath = ABSPATH; foreach ($backups as $backupfiles) { if (strpos($backupfiles, DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR) === false) { $zip->addFile($backupfiles, 'dreamobjects-backup' . str_replace($trimpath, '/', $backupfiles)); //DHDO::logger( $backupfiles ); } } $zip->close(); } catch (Exception $e) { $error_string = $e->getMessage(); DHDO::logger('ZipArchive failed to complete: ' . $error_string); } } if (@file_exists($file)) { DHDO::logger('Calculating zip file size ...'); $zipsize = size_format(@filesize($file)); DHDO::logger('Zip file generated: ' . $file . ' (' . $zipsize . ').'); } else { @unlink($file); DHDO::logger('Zip file failed to generate. Nothing will be backed up.'); } // Delete SQL if (file_exists($sqlfile)) { @unlink($sqlfile); DHDO::logger('Deleting SQL file: ' . $sqlfile . ' ...'); } // Upload if (@file_exists($file)) { $s3 = AwsS3DHDO::factory(array('key' => get_option('dh-do-key'), 'secret' => get_option('dh-do-secretkey'), 'base_url' => get_option('dh-do-endpoint'))); $bucket = get_option('dh-do-bucket'); $parseUrl = parse_url(trim(home_url())); $url = $parseUrl['host']; if (isset($parseUrl['path'])) { $url .= $parseUrl['path']; } // Rename file $newname = $url . '/' . date_i18n('Y-m-d-His', current_time('timestamp')) . '.zip'; DHDO::logger('New filename ' . $newname . '.'); // Uploading set_time_limit(180); DHDO::logger('Beginning upload to Object Store servers.'); // Check the size of the file before we upload, in order to compensate for large files if (@filesize($file) >= 100 * 1024 * 1024) { // Files larger than 100megs go through Multipart DHDO::logger('Filesize is over 100megs, using Multipart uploader.'); // High Level DHDO::logger('Prepare the upload parameters and upload parts in 25M chunks.'); $uploader = UploadBuilder::newInstance()->setClient($s3)->setSource($file)->setBucket($bucket)->setKey($newname)->setMinPartSize(25 * 1024 * 1024)->setOption('Metadata', array('UploadedBy' => 'DreamObjectsBackupPlugin', 'UploadedDate' => date_i18n('Y-m-d-His', current_time('timestamp'))))->setOption('ACL', 'private')->setConcurrency(3)->build(); // This will be called in the following try $uploader->getEventDispatcher()->addListener('multipart_upload.after_part_upload', function ($event) { DHDO::logger('Part ' . $event["state"]->count() . ' uploaded ...'); }); try { DHDO::logger('Begin upload. This may take a while (5min for every 75 megs or so).'); set_time_limit(180); $uploader->upload(); DHDO::logger('Upload complete'); } catch (MultipartUploadException $e) { $uploader->abort(); DHDO::logger('Upload failed: ' . $e->getMessage()); } } else { // If it's under 100megs, do it the old way DHDO::logger('Filesize is under 100megs. This will be less spammy.'); set_time_limit(180); // 3 min try { $result = $s3->putObject(array('Bucket' => $bucket, 'Key' => $newname, 'SourceFile' => $file, 'ContentType' => 'application/zip', 'ACL' => 'private', 'Metadata' => array('UploadedBy' => 'DreamObjectsBackupPlugin', 'UploadedDate' => date_i18n('Y-m-d-His', current_time('timestamp'))))); DHDO::logger('Upload complete'); } catch (S3Exception $e) { DHDO::logger('Upload failed: ' . $e->getMessage()); } } /* // https://dreamxtream.wordpress.com/2013/10/29/aws-php-sdk-logging-using-guzzle/ $s3->getEventDispatcher()->removeSubscriber($logPlugin); */ } else { DHDO::logger('Nothing to upload.'); } // Cleanup if (file_exists($file)) { @unlink($file); DHDO::logger('Deleting zip file: ' . $file . ' ...'); } if (file_exists($sqlfile)) { @unlink($sqlfile); DHDO::logger('Deleting SQL file: ' . $sqlfile . ' ...'); } } // Cleanup Old Backups DHDO::logger('Checking for backups to be deleted.'); if ($backup_result = 'Yes' && get_option('dh-do-retain') && get_option('dh-do-retain') != 'all') { $num_backups = get_option('dh-do-retain'); $s3 = AwsS3DHDO::factory(array('key' => get_option('dh-do-key'), 'secret' => get_option('dh-do-secretkey'), 'base_url' => get_option('dh-do-endpoint'))); $bucket = get_option('dh-do-bucket'); $parseUrl = parse_url(trim(home_url())); $prefixurl = $parseUrl['host']; if (isset($parseUrl['path'])) { $prefixurl .= $parseUrl['path']; } $backups = $s3->getIterator('ListObjects', array('Bucket' => $bucket, "Prefix" => $prefixurl)); if ($backups !== false) { $backups = $backups->toArray(); krsort($backups); $count = 0; foreach ($backups as $object) { if (++$count > $num_backups) { $s3->deleteObject(array('Bucket' => $bucket, 'Key' => $object['Key'])); DHDO::logger('Removed backup ' . $object['Key'] . ' from DreamObjects, per user retention choice.'); } } } } else { DHDO::logger('Per user retention choice, not deleteing a single old backup.'); } DHDO::logger('Backup Complete.'); DHDO::logger(''); }