utiObj = new Utility; $this->fiObj = new ActifendFileIntegrity( ABSPATH ); } /** * Zip extension check */ public function zip_check() { if (extension_loaded('zip')) { return True; } return False; } /** * Zip extension and OS check */ public function zip_and_os_check() { if (extension_loaded('zip') || (strtoupper(substr(PHP_OS, 0, 3)) !== "WIN")) { return True; } return False; } /** * actifend_backup_process * After completion of upload to Actifend-cloud status is to be sent * Actifend BE */ public function actifend_backup_process() { // get asset id $result = $this->utiObj->getActifendInfo(); $assetid = $result->asset_id; // Execute Backup process $this->actifend_wordpress_backup($assetid); $statusOpt = get_option('ActifendBackupStatus'); // check if no requests are pending exit without doing anything if ($statusOpt == 'None') exit(0); // Send the status to Actifend BE if ($statusOpt == 'complete') { $backupStatus = 'done'; $statusOpt = 'Backup to Actifend-cloud successful.'; } else { $backupStatus = 'failed'; } $actifend_array = array('status' => $backupStatus, 'zip_enabled' => $this->zip_check(), 'reason' => $statusOpt, 'reqid' => $this->req_id); $actifend_params = json_encode($actifend_array); // send status done status by curl usind the PATCH method when backup send to azure successfully. $actifend_url = ACTIFEND_BACKUP_END_POINT . $assetid . "/wpbackup"; $this->utiObj->actifend_postViaCurl($actifend_url, $actifend_params, "PATCH"); debug_log("Status update sent to Actifend BE."); } /** * actifend_wordpress_backup * * This function create the receive the backup request after that create * the zip of all your wordpress files and database as per the request full * backup and the at send those files to the azure stroage in * chunks of 3MB and then send the done status after completion of all steps. * * @return null */ public function actifend_wordpress_backup($asset_id) { try { debug_log("Check for backup requests initiated ..."); // check if any backup requests are waiting at BE $response = $this->utiObj->getViaCurl(ACTIFEND_BACKUP_END_POINT, $asset_id, 'wpbackup'); if (isset($response) && !empty($response) && !is_wp_error($response)) { if (($response['ResponseCode'] == '2000') && ($response['Message'] == 'success')) { // It create the backup of the files of the wordpress $assetid = $response['Result']['asset_id']; $account_name = $response['Result']['stor_name']; $share_name = $response['Result']['share_name']; $sas_token = $response['Result']['sas_token']; $this->req_id = $response['Result']['_id']; $backup_type = $response['Result']['backup_type']; $this->max_uploads_size = intval($response['Result']['max_uploads_size']); // suspend the crons until backup & restore is completed $this->utiObj->reset_actifend_crons('remove'); // option setting update_option('ActifendBackupStatus', 'initiated'); $file = BACKUP_FILE; // defined in actifendConstants $max_range = 3 * 1024 * 1024; if (strcmp($backup_type, 'full') === 0) { // create the backup zip file $this->actifend_wp_backup(); } else { $backup_type = 'content'; // create the backup zip file $this->actifend_partial_backup(); } // remove the directory used to keep the backup content directory. $this->utiObj->actifend_rrmdir(BACKUP_DIR); // List the files and the directory ---------------------------------- // check if the folder with assetid as name exists $uri = 'https://' . $account_name . '.file.core.windows.net/' . $share_name . "/" . $assetid . "?" . $sas_token . "&restype=directory"; $today = gmdate("D, d M Y G:i:s T"); $az_headers = array("x-ms-date" => $today, "x-ms-version" => "2015-04-05"); $response = wp_remote_head($uri, array('headers' => $az_headers)); $resp_status = $response['response']['code']; if ($resp_status === 404) { debug_log("$assetid Folder does not exist!"); // create the folder! $uri = 'http://' . $account_name . '.file.core.windows.net/' . $share_name . "/" . $assetid . "?" . $sas_token . "&restype=directory"; $az_headers = array_merge($az_headers, array('Content-Length' => '0')); $response = wp_remote_request($uri, array('headers' => $az_headers, 'method' => 'PUT')); if ($response['response']['code'] == 201) { debug_log("$assetid Folder created on Actifend-cloud!"); } // Now create a sub folder $subfolder = date("Y-m-d_G_i_s"); $uri = 'http://' . $account_name . '.file.core.windows.net/' . $share_name . "/" . $assetid . "/" . $subfolder . "?" . $sas_token . "&restype=directory"; $addl_headers = array("x-ms-meta-bkp_type" => $backup_type, "x-ms-meta-category" => "backup"); $args = array_merge($az_headers, $addl_headers); $response = wp_remote_request($uri, array('headers' => $args, 'method' => 'PUT')); if ($response['response']['code'] === 201) { debug_log("Subfolder " . $subfolder . " with metadata created. Now move on and place the file there ...
"); } } elseif ($resp_status === 200) { debug_log("Folder " . $assetid . " exists! move on and look for the subfolder...
"); // Build the subfolder name // create the subfolder as it would not be existing!! $subfolder = date("Y-m-d_G_i_s"); $uri = 'http://' . $account_name . '.file.core.windows.net/' . $share_name . "/" . $assetid . "/" . $subfolder . "?" . $sas_token . "&restype=directory"; $addl_headers = array("x-ms-meta-bkp_type" => $backup_type, "x-ms-meta-category" => "backup", "Content-length" => '0'); $args = array_merge($az_headers, $addl_headers); $response = wp_remote_request($uri, array('headers' => $args, 'method' => 'PUT')); if ($response['response']['code'] === 201) { debug_log("Subfolder " . $subfolder . " with metadata created. Now move on and place the file there ...
"); } else { update_option('ActifendBackupStatus', 'Unable to create the Subfolder in Actifend-cloud.'); exit("Unable to create the folder, exiting!"); } } else { debug_log("
%s
", $response['response']); update_option('ActifendBackupStatus', $response['response']); return; } // Call Azure API to save the file in the storage. $fsize = filesize(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); $uri = 'https://' . $account_name . '.file.core.windows.net/' . $share_name . "/" . $assetid . "/" . $subfolder . "/" . $file . "?" . $sas_token; $today = gmdate("D, d M Y G:i:s T"); $addl_headers = array('Content-Length' => '0', 'x-ms-type' => 'file', 'x-ms-content-length' => (string) $fsize); $heads = array_merge($az_headers, $addl_headers); $response = wp_remote_request($uri, array('headers' => $heads, 'method' => 'PUT')); if (is_wp_error($response) || ($response['response']['code'] == 400)) { debug_log("Starting file upload to Actifend-cloud failed!"); update_option('ActifendBackupStatus', 'File upload to Actifend-cloud incomplete!'); return; } $handle = fopen(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE, "rb"); $uri_range = $uri . '&comp=range'; // For an update operation, the range can be up to 4 MB in size. // file needs to be uploaded in chunks of $max_range (defined above) if ($fsize > $max_range) { $mod = $fsize / $max_range; $iters = round($mod, 0); if ($iters < $mod) { $iters += 1; } } else { $iters = 1; } $start_byte = 0; $ie = 0; for ($i = 1; $i <= $iters; $i++) { // set the start and end byte values for the range $end_byte = $start_byte + $max_range - 1; if ($i == $iters) { $end_byte = $fsize - 1; } // Read the contents in the file $contentLength = $end_byte - $start_byte + 1; $contents = fread($handle, $contentLength); // initiate the api call $addl_headers = array("x-ms-write" => "update", "x-ms-range" => "bytes=" . $start_byte . "-" . $end_byte, "Content-Length" => (string) $contentLength); $heads = array_merge($az_headers, $addl_headers); $response = wp_remote_request($uri_range, array('headers' => $heads, 'body' => $contents, 'method' => 'PUT')); if (is_wp_error($response) || ($response['response']['code'] !== 201)) { debug_log("Upload to Actifend-cloud failed!"); debug_log($response); update_option('ActifendBackupStatus', $response); } else { $start_byte = $end_byte + 1; $ie = $i; } } if ($ie != $iters) { debug_log("File upload incomplete! :("); update_option('ActifendBackupStatus', 'File upload to Actifend-cloud incomplete!'); } else { debug_log("File upload to Azure storage completed!
"); // delete backup zip file unlink(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); update_option('ActifendBackupStatus', 'complete'); // reinitate the cron for backup & restore $this->utiObj->reset_actifend_crons('add'); } }else { debug_log("No backup requests pending!"); update_option('ActifendBackupStatus', 'None'); return; } }elseif(is_wp_error($response)) { debug_log($response->get_error_message()); update_option('ActifendBackupStatus', $response->get_error_message()); return; } } catch (Exception $e) { debug_log($e->getMessage()); update_option('ActifendBackupStatus', $e->getMessage()); return; } } /** * actifend_partial_backup * Takes partial backup and creates a zip file */ public function actifend_partial_backup() { try { // database access credentials. $dbcreds = array( 'db_host' => DB_HOST, //mysql host 'db_uname' => DB_USER, //user 'db_password' => DB_PASSWORD, //pass 'db_to_backup' => DB_NAME, //database name 'db_backup_path' => trailingslashit( BACKUP_DIR ) . trailingslashit( 'wp-db' ), //where to backup 'db_exclude_tables' => array() //tables to exclude ); // use function to backup the sql. $res = $this->__backup_mysql_database($dbcreds); if ($res) { debug_log("Database dump completed successfully."); } else { debug_log("ERROR: Database dump failed."); update_option('ActifendBackupStatus', 'DB dump failed.'); return false; } // // copy the wp-content/uploads in wp_backup directory // $destination = trailingslashit( BACKUP_DIR ) . "wp-content/uploads"; // $this->copy_directory(UPLOADS_DIR, $destination); // Zip the file if ($this->zip_check()) { $this->utiObj->zipData(trailingslashit( BACKUP_DIR ), trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); if (file_exists(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE)) { chmod(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE, 0777); } debug_log("DB backup Zipping complete!"); return true; }else { // send files with pcl zip compression using PclZip $zipDone = $this->utiObj->pclZipData(trailingslashit( BACKUP_DIR ), trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); if ($zipDone != 0) { debug_log("No zip extension. pcl zip is used!"); return true; }else { debug_log("pcl zip compression failed."); update_option('ActifendBackupStatus', 'PclZip compression failed.'); return false; } } } catch (Exception $e) { update_option('ActifendBackupStatus', $e->getMessage()); return false; } } /** * Actifend Wp Backup * * This function copy the all wordpress files and create a .aql file of wordpress database and add those to wp_backup directory.Create a zip file in the wp-content * with wp_backup.zip file. * * @return null * @access private */ private function actifend_wp_backup() { try { $locations = array( WP_CONTENT_DIR => trailingslashit( BACKUP_DIR ) . 'wp-content', ADMIN_DIR => trailingslashit( BACKUP_DIR ) . 'wp-admin', INCLUDES_DIR => trailingslashit( BACKUP_DIR ) . 'wp-includes', ABSPATH => BACKUP_DIR ); // if plugins and themes are in a custom location (other then default wp-content) if (! is_link(trailingslashit( WP_CONTENT_DIR ) . 'plugins') && dirname(WP_PLUGIN_DIR) !== WP_CONTENT_DIR && ! in_array(dirname(WP_PLUGIN_DIR), array_keys($locations))) { debug_log("Backing up plugins from custom location ..."); $locations[WP_PLUGIN_DIR] = trailingslashit( BACKUP_DIR ) . trailingslashit('wp-content') . 'plugins'; } if (! is_link(trailingslashit( WP_CONTENT_DIR ) . 'themes') && dirname(THEMES_DIR) !== WP_CONTENT_DIR && ! in_array(dirname(THEMES_DIR), array_keys($locations))) { debug_log("Backing up themes from custom location ..."); $locations[THEMES_DIR] = trailingslashit( BACKUP_DIR ) . trailingslashit('wp-content') . 'themes'; } // Add uploads folder upto a limit`specified $uploads_size = $this->utiObj->get_size_of_folder( UPLOADS_DIR ); if ($uploads_size > $this->max_uploads_size && $this->max_uploads_size !== 0) { array_push($this->wpcontent2skip, 'uploads'); debug_log("Skipping uploads folder backup ... "); } @mkdir(BACKUP_DIR); foreach ($locations as $source => $destination) { if (strcmp($source, ABSPATH) === 0) { // recursive should be false $this->copy_directory($source, $destination, false); } else { $this->copy_directory($source, $destination); } debug_log("$source folder added to backup."); } // database access credentials. $para = array( 'db_host' => DB_HOST, //mysql host 'db_uname' => DB_USER, //user 'db_password' => DB_PASSWORD, //pass 'db_to_backup' => DB_NAME, //database name 'db_backup_path' => trailingslashit( BACKUP_DIR ) . trailingslashit('wp-db'), //where to backup 'db_exclude_tables' => array() //tables to exclude ); // use function to backup the sql. $res = $this->__backup_mysql_database($para); if ($res) { debug_log("Database dump completed successfully."); } else { debug_log("ERROR: Database dump failed."); } // send files with pcl zip compression using PclZip $zipDone = $this->utiObj->pclZipData(trailingslashit( BACKUP_DIR ), trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); if ($zipDone != 0) { debug_log("PclZip compression DONE!"); return true; }else { debug_log("pcl zip compression failed."); if ($this->zip_check()) { debug_log("Checking with ZIP extension ... "); $this->utiObj->zipData(trailingslashit( BACKUP_DIR ), trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE); if (file_exists(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE)) { chmod(trailingslashit( WP_CONTENT_DIR ) . BACKUP_FILE, 0777); } debug_log("Site backup Zipping complete!"); return true; } else { update_option('ActifendBackupStatus', 'PclZip compression failed.'); return false; } } } catch (Exception $e) { update_option('ActifendBackupStatus', $e->getMessage()); return False; } } /** * copy directory * * Copy directory function is used to copy the full content of one directory to another directory. * Skips folders that are mentioned in the class array variable wpcontent2skip * Skips files with extension .log and file defined as BACKUP_FILE constant that are * inside the source folder * * @param string $source Source directory path. * @param string $destination Destination path where the content of source directory copied. */ private function copy_directory($source, $destination, $recursive=true) { try { if ($source != BACKUP_DIR) { $directory = opendir($source); @mkdir($destination); while (false !== ($file = readdir($directory))) { if (($file != '.') && ($file != '..')) { if (is_dir(trailingslashit($source) . $file) && $recursive === true) { if (! in_array($file, $this->wpcontent2skip)) { $this->copy_directory(trailingslashit($source) . $file, trailingslashit($destination) . $file); } } else { @$ext = pathinfo($file, PATHINFO_EXTENSION); if ($ext != 'log' && $file != BACKUP_FILE) { @copy(trailingslashit($source) . $file, trailingslashit($destination) . $file); } } } } closedir($directory); return True; } } catch (Exception $e) { debug_log($e->getMessage()); update_option('ActifendBackupStatus', $e->getMessage()); return False; } } /** * __backup_mysql_database (using mysqldump method) * @param sql filename * @return void */ private function __backup_mysql_database($params) { try { $this->fiObj->createBaseline(); if (!is_dir($params['db_backup_path'])) { mkdir($params['db_backup_path'], 0777, true); } $dir = trailingslashit( BACKUP_DIR ) . 'wp-db/'; $backup_file_name = $dir . "actifend-db-backup.sql"; $cmd = "mysqldump"; $host = explode(':', DB_HOST); $port = strpos(DB_HOST, ':') ? end($host) : ''; $host = reset($host); // We don't want to create a new DB $cmd .= ' --no-create-db'; // Allow lock-tables to be overridden $cmd .= ' --single-transaction'; // Make sure binary data is exported properly $cmd .= ' --hex-blob'; // Username $cmd .= ' -u ' . escapeshellarg(DB_USER); // Don't pass the password if it's blank if (DB_PASSWORD) $cmd .= ' -p' . escapeshellarg(DB_PASSWORD); // Set the host $cmd .= ' -h ' . escapeshellarg($host); // Set the port if it was set if (!empty($port) && is_numeric($port)) $cmd .= ' -P ' . $port; // The file we're saving too $cmd .= ' -r ' . escapeshellarg($backup_file_name); // Exclude tables if any (default is empty array) $wp_db_exclude_table = array(); if (!empty($wp_db_exclude_table)) { foreach ($wp_db_exclude_table as $wp_db_exclude_table) { $cmd .= ' --ignore-table=' . DB_NAME . '.' . $wp_db_exclude_table; } } // The database we're dumping $cmd .= ' ' . escapeshellarg(DB_NAME); // Pipe STDERR to STDOUT $cmd .= ' 2>&1'; // Store any returned data in an error $stderr = shell_exec($cmd); // Skip the new password warning that is output in mysql > 5.6 if (trim($stderr) === 'Warning: Using a password on the command line interface can be insecure.') { $stderr = ''; } debug_log("mysqldump: SQL Dump completed. Verification to be done."); return $this->verify_mysqldump($backup_file_name); } catch (Exception $e) { debug_log($e->getMessage()); update_option('ActifendBackupStatus', $e->getMessage()); return False; } } public function verify_mysqldump($SQLfilename) { // If we've already passed then no need to check again if (!empty($this->mysqldump_verified)) return true; // If we have an empty file delete it if (@filesize($SQLfilename) === 0) unlink($SQLfilename); // If the file still exists then it must be good if (file_exists($SQLfilename)) return $this->mysqldump_verified = true; return false; } } ?>