Edit File by line
/home/barbar84/www/wp-conte.../plugins/updraftp...
File: backup.php
@unlink($cache_file_base.'-zfb.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3500] Fix | Delete
} else {
[3501] Fix | Delete
$info_array = array('makezip_recursive_batchedbytes' => $this->makezip_recursive_batchedbytes);
[3502] Fix | Delete
if (!file_put_contents($cache_file_base.'-info.tmp', serialize($info_array))) {
[3503] Fix | Delete
@unlink($cache_file_base.'-zfs.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3504] Fix | Delete
@unlink($cache_file_base.'-zfb.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3505] Fix | Delete
}
[3506] Fix | Delete
if ($dhandle = gzopen($cache_file_base.'-zfd.gz.tmp', 'w')) {
[3507] Fix | Delete
if (!gzwrite($dhandle, serialize($this->zipfiles_dirbatched))) {
[3508] Fix | Delete
$aborted_on_dirbatched = true;
[3509] Fix | Delete
}
[3510] Fix | Delete
gzclose($dhandle);
[3511] Fix | Delete
} else {
[3512] Fix | Delete
$aborted_on_dirbatched = true;
[3513] Fix | Delete
}
[3514] Fix | Delete
if (!empty($aborted_on_dirbatched)) {
[3515] Fix | Delete
@unlink($cache_file_base.'-zfs.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3516] Fix | Delete
@unlink($cache_file_base.'-zfd.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3517] Fix | Delete
@unlink($cache_file_base.'-zfb.gz.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3518] Fix | Delete
@unlink($cache_file_base.'-info.tmp');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3519] Fix | Delete
// @codingStandardsIgnoreLine
[3520] Fix | Delete
} else {
[3521] Fix | Delete
// Success.
[3522] Fix | Delete
}
[3523] Fix | Delete
}
[3524] Fix | Delete
}
[3525] Fix | Delete
}
[3526] Fix | Delete
[3527] Fix | Delete
/*
[3528] Fix | Delete
Class variables that get altered:
[3529] Fix | Delete
zipfiles_batched
[3530] Fix | Delete
makezip_recursive_batchedbytes
[3531] Fix | Delete
zipfiles_skipped_notaltered
[3532] Fix | Delete
zipfiles_dirbatched
[3533] Fix | Delete
Class variables that the result depends upon (other than the state of the filesystem):
[3534] Fix | Delete
makezip_if_altered_since
[3535] Fix | Delete
existing_files
[3536] Fix | Delete
*/
[3537] Fix | Delete
[3538] Fix | Delete
}
[3539] Fix | Delete
[3540] Fix | Delete
// Any not yet dispatched? Under our present scheme, at this point nothing has yet been despatched. And since the enumerating of all files can take a while, we can at this point do a further modification check to reduce the chance of overlaps.
[3541] Fix | Delete
// This relies on us *not* touch()ing the zip file to indicate to any resumption 'behind us' that we're already here. Rather, we're relying on the combined facts that a) if it takes us a while to search the directory tree, then it should do for the one behind us too (though they'll have the benefit of cache, so could catch very fast) and b) we touch *immediately* after finishing the enumeration of the files to add.
[3542] Fix | Delete
// $retry_on_error is here being used as a proxy for 'not the second time around, when there might be the remains of the file on the first time around'
[3543] Fix | Delete
if ($retry_on_error) $updraftplus->check_recent_modification($destination);
[3544] Fix | Delete
// Here we're relying on the fact that both PclZip and ZipArchive will happily operate on an empty file. Note that BinZip *won't* (for that, may need a new strategy - e.g. add the very first file on its own, in order to 'lay down a marker')
[3545] Fix | Delete
if (empty($do_bump_index)) touch($destination);
[3546] Fix | Delete
[3547] Fix | Delete
if (count($this->zipfiles_dirbatched) > 0 || count($this->zipfiles_batched) > 0) {
[3548] Fix | Delete
[3549] Fix | Delete
$updraftplus->log(sprintf("Total entities for the zip file: %d directories, %d files (%d skipped as non-modified), %s MB", count($this->zipfiles_dirbatched), count($this->zipfiles_batched), count($this->zipfiles_skipped_notaltered), round($this->makezip_recursive_batchedbytes/1048576, 1)));
[3550] Fix | Delete
[3551] Fix | Delete
// No need to warn if we're going to retry anyway. (And if we get killed, the zip will be rescanned for its contents upon resumption).
[3552] Fix | Delete
$warn_on_failures = ($retry_on_error) ? false : true;
[3553] Fix | Delete
$add_them = $this->makezip_addfiles($warn_on_failures);
[3554] Fix | Delete
[3555] Fix | Delete
if (is_wp_error($add_them)) {
[3556] Fix | Delete
foreach ($add_them->get_error_messages() as $msg) {
[3557] Fix | Delete
$updraftplus->log("Error returned from makezip_addfiles: ".$msg);
[3558] Fix | Delete
}
[3559] Fix | Delete
$error_occurred = true;
[3560] Fix | Delete
} elseif (false === $add_them) {
[3561] Fix | Delete
$updraftplus->log("Error: makezip_addfiles returned false");
[3562] Fix | Delete
$error_occurred = true;
[3563] Fix | Delete
}
[3564] Fix | Delete
[3565] Fix | Delete
}
[3566] Fix | Delete
[3567] Fix | Delete
// Reset these variables because the index may have changed since we began
[3568] Fix | Delete
[3569] Fix | Delete
$itext = empty($this->index) ? '' : $this->index+1;
[3570] Fix | Delete
$destination_base = $backup_file_basename.'-'.$whichone.$itext.'.zip.tmp';
[3571] Fix | Delete
$destination = $this->updraft_dir.'/'.$destination_base;
[3572] Fix | Delete
[3573] Fix | Delete
// ZipArchive::addFile sometimes fails - there's nothing when we expected something.
[3574] Fix | Delete
// Did not used to have || $error_occured here. But it is better to retry, than to simply warn the user to check his logs.
[3575] Fix | Delete
if (((file_exists($destination) || $this->index == $original_index) && @filesize($destination) < 90 && 'UpdraftPlus_ZipArchive' == $this->use_zip_object) || ($error_occurred && $retry_on_error)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3576] Fix | Delete
// This can be made more sophisticated if feedback justifies it. Currently we just switch to PclZip. But, it may have been a BinZip failure, so we could then try ZipArchive if that is available. If doing that, make sure that an infinite recursion isn't made possible.
[3577] Fix | Delete
$updraftplus->log("makezip_addfiles(".$this->use_zip_object.") apparently failed (file=".basename($destination).", type=$whichone, size=".filesize($destination).") - retrying with PclZip");
[3578] Fix | Delete
$saved_zip_object = $this->use_zip_object;
[3579] Fix | Delete
$this->use_zip_object = 'UpdraftPlus_PclZip';
[3580] Fix | Delete
$ret = $this->make_zipfile($source, $backup_file_basename, $whichone, false);
[3581] Fix | Delete
$this->use_zip_object = $saved_zip_object;
[3582] Fix | Delete
return $ret;
[3583] Fix | Delete
}
[3584] Fix | Delete
[3585] Fix | Delete
// zipfiles_added > 0 means that $zip->close() has been called. i.e. An attempt was made to add something: something _should_ be there.
[3586] Fix | Delete
// Why return true even if $error_occurred may be set? 1) Because in that case, a warning has already been logged. 2) Because returning false causes an error to be logged, which means it'll all be retried again. Also 3) this has been the pattern of the code for a long time, and the algorithm has been proven in the real-world: don't change what's not broken.
[3587] Fix | Delete
// (file_exists($destination) || $this->index == $original_index) might be an alternative to $this->zipfiles_added > 0 - ? But, don't change what's not broken.
[3588] Fix | Delete
if (false == $error_occurred || $this->zipfiles_added > 0) {
[3589] Fix | Delete
return true;
[3590] Fix | Delete
} else {
[3591] Fix | Delete
$updraftplus->log("makezip failure: zipfiles_added=".$this->zipfiles_added.", error_occurred=".$error_occurred." (method=".$this->use_zip_object.")");
[3592] Fix | Delete
return false;
[3593] Fix | Delete
}
[3594] Fix | Delete
[3595] Fix | Delete
}
[3596] Fix | Delete
[3597] Fix | Delete
/**
[3598] Fix | Delete
* This function is an ugly, conservative workaround for https://bugs.php.net/bug.php?id=62119. It does not aim to always work-around, but to ensure that nothing is made worse.
[3599] Fix | Delete
*
[3600] Fix | Delete
* @param String $element
[3601] Fix | Delete
*
[3602] Fix | Delete
* @return String
[3603] Fix | Delete
*/
[3604] Fix | Delete
private function basename($element) {
[3605] Fix | Delete
$dirname = dirname($element);
[3606] Fix | Delete
$basename_manual = preg_replace('#^[\\/]+#', '', substr($element, strlen($dirname)));
[3607] Fix | Delete
$basename = basename($element);
[3608] Fix | Delete
if ($basename_manual != $basename) {
[3609] Fix | Delete
$locale = setlocale(LC_CTYPE, "0");
[3610] Fix | Delete
if ('C' == $locale) {
[3611] Fix | Delete
setlocale(LC_CTYPE, 'en_US.UTF8');
[3612] Fix | Delete
$basename_new = basename($element);
[3613] Fix | Delete
if ($basename_new == $basename_manual) $basename = $basename_new;
[3614] Fix | Delete
setlocale(LC_CTYPE, $locale);
[3615] Fix | Delete
}
[3616] Fix | Delete
}
[3617] Fix | Delete
return $basename;
[3618] Fix | Delete
}
[3619] Fix | Delete
[3620] Fix | Delete
/**
[3621] Fix | Delete
* Determine if a file should be stored without compression
[3622] Fix | Delete
*
[3623] Fix | Delete
* @param String $file - the filename
[3624] Fix | Delete
*
[3625] Fix | Delete
* @return Boolean
[3626] Fix | Delete
*/
[3627] Fix | Delete
private function file_should_be_stored_without_compression($file) {
[3628] Fix | Delete
if (!is_array($this->extensions_to_not_compress)) return false;
[3629] Fix | Delete
foreach ($this->extensions_to_not_compress as $ext) {
[3630] Fix | Delete
$ext_len = strlen($ext);
[3631] Fix | Delete
if (strtolower(substr($file, -$ext_len, $ext_len)) == $ext) return true;
[3632] Fix | Delete
}
[3633] Fix | Delete
return false;
[3634] Fix | Delete
}
[3635] Fix | Delete
[3636] Fix | Delete
/**
[3637] Fix | Delete
* This method will add a manifest file to the backup zip
[3638] Fix | Delete
*
[3639] Fix | Delete
* @param String $whichone - the type of backup (e.g. 'plugins', 'themes')
[3640] Fix | Delete
*
[3641] Fix | Delete
* @return Boolean - success/failure status
[3642] Fix | Delete
*/
[3643] Fix | Delete
private function updraftplus_include_manifest($whichone) {
[3644] Fix | Delete
global $updraftplus;
[3645] Fix | Delete
[3646] Fix | Delete
$manifest_name = "updraftplus-manifest.json";
[3647] Fix | Delete
$manifest = trailingslashit($this->updraft_dir).$manifest_name;
[3648] Fix | Delete
[3649] Fix | Delete
$updraftplus->log(sprintf("Creating file manifest ($manifest_name) for incremental backup (included: %d, skipped: %d)", count($this->zipfiles_batched), count($this->zipfiles_skipped_notaltered)));
[3650] Fix | Delete
[3651] Fix | Delete
if (false === ($handle = fopen($manifest, 'w+'))) return $updraftplus->log("Failed to open manifest file ($manifest_name)");
[3652] Fix | Delete
[3653] Fix | Delete
$this->manifest_path = $manifest;
[3654] Fix | Delete
[3655] Fix | Delete
$version = 1;
[3656] Fix | Delete
[3657] Fix | Delete
$go_to_levels = array(
[3658] Fix | Delete
'plugins' => 2,
[3659] Fix | Delete
'themes' => 2,
[3660] Fix | Delete
'uploads' => 3,
[3661] Fix | Delete
'others' => 3
[3662] Fix | Delete
);
[3663] Fix | Delete
[3664] Fix | Delete
$go_to_levels = apply_filters('updraftplus_manifest_go_to_level', $go_to_levels, $whichone);
[3665] Fix | Delete
[3666] Fix | Delete
$go_to_level = isset($go_to_levels[$whichone]) ? $go_to_levels[$whichone] : 'all';
[3667] Fix | Delete
[3668] Fix | Delete
$directory = '';
[3669] Fix | Delete
[3670] Fix | Delete
if ('more' == $whichone) {
[3671] Fix | Delete
foreach ($this->zipfiles_batched as $index => $dir) {
[3672] Fix | Delete
$directory = '"directory":"' . dirname($index) . '",';
[3673] Fix | Delete
}
[3674] Fix | Delete
}
[3675] Fix | Delete
[3676] Fix | Delete
if (false === fwrite($handle, '{"version":'.$version.',"type":"'.$whichone.'",'.$directory.'"listed_levels":"'.$go_to_level.'","contents":{"directories":[')) $updraftplus->log("First write to manifest file failed ($manifest_name)");
[3677] Fix | Delete
[3678] Fix | Delete
// First loop: find out which is the last entry, so that we don't write the comma after it
[3679] Fix | Delete
$last_dir_index = false;
[3680] Fix | Delete
foreach ($this->zipfiles_dirbatched as $index => $dir) {
[3681] Fix | Delete
if ('all' !== $go_to_level && substr_count($dir, '/') > $go_to_level - 1) continue;
[3682] Fix | Delete
$last_dir_index = $index;
[3683] Fix | Delete
}
[3684] Fix | Delete
[3685] Fix | Delete
// Second loop: write out the entry
[3686] Fix | Delete
foreach ($this->zipfiles_dirbatched as $index => $dir) {
[3687] Fix | Delete
if ('all' !== $go_to_level && substr_count($dir, '/') > $go_to_level - 1) continue;
[3688] Fix | Delete
fwrite($handle, json_encode($dir).(($index != $last_dir_index) ? ',' : ''));
[3689] Fix | Delete
}
[3690] Fix | Delete
[3691] Fix | Delete
// Now do the same for files
[3692] Fix | Delete
fwrite($handle, '],"files":[');
[3693] Fix | Delete
[3694] Fix | Delete
$last_file_index = false;
[3695] Fix | Delete
foreach ($this->zipfiles_batched as $store_as) {
[3696] Fix | Delete
if ('all' !== $go_to_level && substr_count($store_as, '/') > $go_to_level - 1) continue;
[3697] Fix | Delete
$last_file_index = $store_as;
[3698] Fix | Delete
}
[3699] Fix | Delete
foreach ($this->zipfiles_skipped_notaltered as $store_as) {
[3700] Fix | Delete
if ('all' !== $go_to_level && substr_count($store_as, '/') > $go_to_level - 1) continue;
[3701] Fix | Delete
$last_file_index = $store_as;
[3702] Fix | Delete
}
[3703] Fix | Delete
[3704] Fix | Delete
foreach ($this->zipfiles_batched as $store_as) {
[3705] Fix | Delete
if ('all' !== $go_to_level && substr_count($store_as, '/') > $go_to_level - 1) continue;
[3706] Fix | Delete
fwrite($handle, json_encode($store_as).(($store_as != $last_file_index) ? ',' : ''));
[3707] Fix | Delete
}
[3708] Fix | Delete
[3709] Fix | Delete
foreach ($this->zipfiles_skipped_notaltered as $store_as) {
[3710] Fix | Delete
if ('all' !== $go_to_level && substr_count($store_as, '/') > $go_to_level - 1) continue;
[3711] Fix | Delete
fwrite($handle, json_encode($store_as).(($store_as != $last_file_index) ? ',' : ''));
[3712] Fix | Delete
}
[3713] Fix | Delete
[3714] Fix | Delete
fwrite($handle, ']}}');
[3715] Fix | Delete
fclose($handle);
[3716] Fix | Delete
[3717] Fix | Delete
$this->zipfiles_batched[$manifest] = $manifest_name;
[3718] Fix | Delete
[3719] Fix | Delete
$updraftplus->log("Successfully created file manifest (size: ".filesize($manifest).")");
[3720] Fix | Delete
[3721] Fix | Delete
return true;
[3722] Fix | Delete
}
[3723] Fix | Delete
[3724] Fix | Delete
// Q. Why don't we only open and close the zip file just once?
[3725] Fix | Delete
// A. Because apparently PHP doesn't write out until the final close, and it will return an error if anything file has vanished in the meantime. So going directory-by-directory reduces our chances of hitting an error if the filesystem is changing underneath us (which is very possible if dealing with e.g. 1GB of files)
[3726] Fix | Delete
[3727] Fix | Delete
/**
[3728] Fix | Delete
* We batch up the files, rather than do them one at a time. So we are more efficient than open,one-write,close.
[3729] Fix | Delete
* To call into here, the array $this->zipfiles_batched must be populated (keys=paths, values=add-to-zip-as values). It gets reset upon exit from here.
[3730] Fix | Delete
*
[3731] Fix | Delete
* @param Boolean $warn_on_failures See if it warns on faliures or not
[3732] Fix | Delete
*
[3733] Fix | Delete
* @return Boolean|WP_Error
[3734] Fix | Delete
*/
[3735] Fix | Delete
private function makezip_addfiles($warn_on_failures) {
[3736] Fix | Delete
[3737] Fix | Delete
global $updraftplus;
[3738] Fix | Delete
[3739] Fix | Delete
// Used to detect requests to bump the size
[3740] Fix | Delete
$bump_index = false;
[3741] Fix | Delete
$ret = true;
[3742] Fix | Delete
[3743] Fix | Delete
$zipfile = $this->zip_basename.((0 == $this->index) ? '' : ($this->index+1)).'.zip.tmp';
[3744] Fix | Delete
[3745] Fix | Delete
$maxzipbatch = $updraftplus->jobdata_get('maxzipbatch', 26214400);
[3746] Fix | Delete
if ((int) $maxzipbatch < 1024) $maxzipbatch = 26214400;
[3747] Fix | Delete
[3748] Fix | Delete
// Short-circuit the null case, because we want to detect later if something useful happenned
[3749] Fix | Delete
if (count($this->zipfiles_dirbatched) == 0 && count($this->zipfiles_batched) == 0) return true;
[3750] Fix | Delete
[3751] Fix | Delete
// If on PclZip, then if possible short-circuit to a quicker method (makes a huge time difference - on a folder of 1500 small files, 2.6s instead of 76.6)
[3752] Fix | Delete
// This assumes that makezip_addfiles() is only called once so that we know about all needed files (the new style)
[3753] Fix | Delete
// This is rather conservative - because it assumes zero compression. But we can't know that in advance.
[3754] Fix | Delete
$force_allinone = false;
[3755] Fix | Delete
if (0 == $this->index && $this->makezip_recursive_batchedbytes < $this->zip_split_every) {
[3756] Fix | Delete
// So far, we only have a processor for this for PclZip; but that check can be removed - need to address the below items
[3757] Fix | Delete
// TODO: Is this really what we want? Always go all-in-one for < 500MB???? Should be more conservative? Or, is it always faster to go all-in-one? What about situations where we might want to auto-split because of slowness - check that that is still working.
[3758] Fix | Delete
// TODO: Test this new method for PclZip - are we still getting the performance gains? Test for ZipArchive too.
[3759] Fix | Delete
if ('UpdraftPlus_PclZip' == $this->use_zip_object && ($this->makezip_recursive_batchedbytes < 512*1048576 || (defined('UPDRAFTPLUS_PCLZIP_FORCEALLINONE') && UPDRAFTPLUS_PCLZIP_FORCEALLINONE == true && 'UpdraftPlus_PclZip' == $this->use_zip_object))) {
[3760] Fix | Delete
$updraftplus->log("Only one archive required (".$this->use_zip_object.") - will attempt to do in single operation (data: ".round($this->makezip_recursive_batchedbytes/1024, 1)." KB, split: ".round($this->zip_split_every/1024, 1)." KB)");
[3761] Fix | Delete
// $updraftplus->log("PclZip, and only one archive required - will attempt to do in single operation (data: ".round($this->makezip_recursive_batchedbytes/1024, 1)." KB, split: ".round($this->zip_split_every/1024, 1)." KB)");
[3762] Fix | Delete
$force_allinone = true;
[3763] Fix | Delete
// if(!class_exists('PclZip')) require_once(ABSPATH.'/wp-admin/includes/class-pclzip.php');
[3764] Fix | Delete
// $zip = new PclZip($zipfile);
[3765] Fix | Delete
// $remove_path = ($this->whichone == 'wpcore') ? untrailingslashit(ABSPATH) : WP_CONTENT_DIR;
[3766] Fix | Delete
// $add_path = false;
[3767] Fix | Delete
// Remove prefixes
[3768] Fix | Delete
// $backupable_entities = $updraftplus->get_backupable_file_entities(true);
[3769] Fix | Delete
// if (isset($backupable_entities[$this->whichone])) {
[3770] Fix | Delete
// if ('plugins' == $this->whichone || 'themes' == $this->whichone || 'uploads' == $this->whichone) {
[3771] Fix | Delete
// $remove_path = dirname($backupable_entities[$this->whichone]);
[3772] Fix | Delete
// To normalise instead of removing (which binzip doesn't support, so we don't do it), you'd remove the dirname() in the above line, and uncomment the below one.
[3773] Fix | Delete
// #$add_path = $this->whichone;
[3774] Fix | Delete
// } else {
[3775] Fix | Delete
// $remove_path = $backupable_entities[$this->whichone];
[3776] Fix | Delete
// }
[3777] Fix | Delete
// }
[3778] Fix | Delete
// if ($add_path) {
[3779] Fix | Delete
// $zipcode = $zip->create($this->source, PCLZIP_OPT_REMOVE_PATH, $remove_path, PCLZIP_OPT_ADD_PATH, $add_path);
[3780] Fix | Delete
// } else {
[3781] Fix | Delete
// $zipcode = $zip->create($this->source, PCLZIP_OPT_REMOVE_PATH, $remove_path);
[3782] Fix | Delete
// }
[3783] Fix | Delete
// if ($zipcode == 0) {
[3784] Fix | Delete
// $updraftplus->log("PclZip Error: ".$zip->errorInfo(true), 'warning');
[3785] Fix | Delete
// return $zip->errorCode();
[3786] Fix | Delete
// } else {
[3787] Fix | Delete
// UpdraftPlus_Job_Scheduler::something_useful_happened();
[3788] Fix | Delete
// return true;
[3789] Fix | Delete
// }
[3790] Fix | Delete
}
[3791] Fix | Delete
}
[3792] Fix | Delete
[3793] Fix | Delete
// 05-Mar-2013 - added a new check on the total data added; it appears that things fall over if too much data is contained in the cumulative total of files that were addFile'd without a close-open cycle; presumably data is being stored in memory. In the case in question, it was a batch of MP3 files of around 100MB each - 25 of those equals 2.5GB!
[3794] Fix | Delete
[3795] Fix | Delete
$data_added_since_reopen = 0;
[3796] Fix | Delete
// static $data_added_this_resumption = 0;
[3797] Fix | Delete
// $max_data_added_any_resumption = $updraftplus->jobdata_get('max_data_added_any_resumption', 0);
[3798] Fix | Delete
[3799] Fix | Delete
// The following array is used only for error reporting if ZipArchive::close fails (since that method itself reports no error messages - we have to track manually what we were attempting to add)
[3800] Fix | Delete
$files_zipadded_since_open = array();
[3801] Fix | Delete
[3802] Fix | Delete
$zip = new $this->use_zip_object;
[3803] Fix | Delete
if (file_exists($zipfile)) {
[3804] Fix | Delete
$opencode = $zip->open($zipfile);
[3805] Fix | Delete
$original_size = filesize($zipfile);
[3806] Fix | Delete
clearstatcache();
[3807] Fix | Delete
} else {
[3808] Fix | Delete
$create_code = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CREATE')) ? ZIPARCHIVE::CREATE : 1;
[3809] Fix | Delete
$opencode = $zip->open($zipfile, $create_code);
[3810] Fix | Delete
$original_size = 0;
[3811] Fix | Delete
}
[3812] Fix | Delete
[3813] Fix | Delete
if (true !== $opencode) return new WP_Error('no_open', sprintf(__('Failed to open the zip file (%s) - %s', 'updraftplus'), $zipfile, $zip->last_error));
[3814] Fix | Delete
[3815] Fix | Delete
if (apply_filters('updraftplus_include_manifest', false, $this->whichone, $this)) {
[3816] Fix | Delete
$this->updraftplus_include_manifest($this->whichone);
[3817] Fix | Delete
}
[3818] Fix | Delete
[3819] Fix | Delete
// Make sure all directories are created before we start creating files
[3820] Fix | Delete
while ($dir = array_pop($this->zipfiles_dirbatched)) {
[3821] Fix | Delete
$zip->addEmptyDir($dir);
[3822] Fix | Delete
}
[3823] Fix | Delete
$zipfiles_added_thisbatch = 0;
[3824] Fix | Delete
[3825] Fix | Delete
// Go through all those batched files
[3826] Fix | Delete
foreach ($this->zipfiles_batched as $file => $add_as) {
[3827] Fix | Delete
[3828] Fix | Delete
if (!file_exists($file)) {
[3829] Fix | Delete
$updraftplus->log("File has vanished from underneath us; dropping: $add_as");
[3830] Fix | Delete
continue;
[3831] Fix | Delete
}
[3832] Fix | Delete
[3833] Fix | Delete
$fsize = filesize($file);
[3834] Fix | Delete
[3835] Fix | Delete
$large_file_warning_key = 'vlargefile_'.md5($this->whichone.'#'.$add_as);
[3836] Fix | Delete
[3837] Fix | Delete
if (defined('UPDRAFTPLUS_SKIP_FILE_OVER_SIZE') && UPDRAFTPLUS_SKIP_FILE_OVER_SIZE && $fsize > UPDRAFTPLUS_SKIP_FILE_OVER_SIZE) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3838] Fix | Delete
$updraftplus->log("File is larger than the user-configured (UPDRAFTPLUS_SKIP_FILE_OVER_SIZE) maximum (is: ".round($fsize/1024, 1)." KB); will skip: ".$add_as);
[3839] Fix | Delete
continue;
[3840] Fix | Delete
} elseif ($fsize > UPDRAFTPLUS_WARN_FILE_SIZE) {
[3841] Fix | Delete
[3842] Fix | Delete
$log_msg = __('A very large file was encountered: %s (size: %s Mb)', 'updraftplus');
[3843] Fix | Delete
[3844] Fix | Delete
// Was this warned about on a previous run?
[3845] Fix | Delete
if ($updraftplus->warning_exists($large_file_warning_key)) {
[3846] Fix | Delete
$updraftplus->log_remove_warning($large_file_warning_key);
[3847] Fix | Delete
$large_file_warning_key .= '-2';
[3848] Fix | Delete
$log_msg .= ' - '.__('a second attempt is being made (upon further failure it will be skipped)', 'updraftplus');
[3849] Fix | Delete
} elseif ($updraftplus->warning_exists($large_file_warning_key.'-2') || $updraftplus->warning_exists($large_file_warning_key.'-final')) {
[3850] Fix | Delete
$updraftplus->log_remove_warning($large_file_warning_key.'-2');
[3851] Fix | Delete
$large_file_warning_key .= '-final';
[3852] Fix | Delete
$log_msg .= ' - '.__('two unsuccessful attempts were made to include it, and it will now be omitted from the backup', 'updraftplus');
[3853] Fix | Delete
}
[3854] Fix | Delete
[3855] Fix | Delete
$updraftplus->log(sprintf($log_msg, $add_as, round($fsize/1048576, 1)), 'warning', $large_file_warning_key);
[3856] Fix | Delete
[3857] Fix | Delete
if ('-final' == substr($large_file_warning_key, -6, 6)) {
[3858] Fix | Delete
continue;
[3859] Fix | Delete
}
[3860] Fix | Delete
}
[3861] Fix | Delete
[3862] Fix | Delete
// Skips files that are already added
[3863] Fix | Delete
if (!isset($this->existing_files[$add_as]) || $this->existing_files[$add_as] != $fsize) {
[3864] Fix | Delete
[3865] Fix | Delete
@touch($zipfile);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3866] Fix | Delete
$zip->addFile($file, $add_as);
[3867] Fix | Delete
$zipfiles_added_thisbatch++;
[3868] Fix | Delete
[3869] Fix | Delete
if (method_exists($zip, 'setCompressionName') && $this->file_should_be_stored_without_compression($add_as) && false == $zip->setCompressionName($add_as, ZipArchive::CM_STORE)) {
[3870] Fix | Delete
$updraftplus->log("Zip: setCompressionName failed on: $add_as");
[3871] Fix | Delete
}
[3872] Fix | Delete
[3873] Fix | Delete
// N.B., Since makezip_addfiles() can get called more than once if there were errors detected, potentially $zipfiles_added_thisrun can exceed the total number of batched files (if they get processed twice).
[3874] Fix | Delete
$this->zipfiles_added_thisrun++;
[3875] Fix | Delete
$files_zipadded_since_open[] = array('file' => $file, 'addas' => $add_as);
[3876] Fix | Delete
[3877] Fix | Delete
$data_added_since_reopen += $fsize;
[3878] Fix | Delete
// $data_added_this_resumption += $fsize;
[3879] Fix | Delete
/* Conditions for forcing a write-out and re-open:
[3880] Fix | Delete
- more than $maxzipbatch bytes have been batched
[3881] Fix | Delete
- more than 2.0 seconds have passed since the last time we wrote
[3882] Fix | Delete
- that adding this batch of data is likely already enough to take us over the split limit (and if that happens, then do actually split - to prevent a scenario of progressively tinier writes as we approach but don't actually reach the limit)
[3883] Fix | Delete
- more than 500 files batched (should perhaps intelligently lower this as the zip file gets bigger - not yet needed)
[3884] Fix | Delete
*/
[3885] Fix | Delete
[3886] Fix | Delete
// Add 10% margin. It only really matters when the OS has a file size limit, exceeding which causes failure (e.g. 2GB on 32-bit)
[3887] Fix | Delete
// Since we don't test before the file has been created (so that zip_last_ratio has meaningful data), we rely on max_zip_batch being less than zip_split_every - which should always be the case
[3888] Fix | Delete
$reaching_split_limit = ($this->zip_last_ratio > 0 && $original_size>0 && ($original_size + 1.1*$data_added_since_reopen*$this->zip_last_ratio) > $this->zip_split_every) ? true : false;
[3889] Fix | Delete
[3890] Fix | Delete
if (!$force_allinone && ($zipfiles_added_thisbatch > UPDRAFTPLUS_MAXBATCHFILES || $reaching_split_limit || $data_added_since_reopen > $maxzipbatch || (time() - $this->zipfiles_lastwritetime) > 2)) {
[3891] Fix | Delete
[3892] Fix | Delete
// We are coming towards a limit and about to close the zip, check if this is a more file backup and the manifest file has made it into this zip if not add it
[3893] Fix | Delete
if (apply_filters('updraftplus_include_manifest', false, $this->whichone, $this)) {
[3894] Fix | Delete
[3895] Fix | Delete
$manifest = false;
[3896] Fix | Delete
[3897] Fix | Delete
foreach ($files_zipadded_since_open as $info) {
[3898] Fix | Delete
if ('updraftplus-manifest.json' == $info['file']) $manifest = true;
[3899] Fix | Delete
}
[3900] Fix | Delete
[3901] Fix | Delete
if (!$manifest) {
[3902] Fix | Delete
@touch($zipfile);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3903] Fix | Delete
$path = array_search('updraftplus-manifest.json', $this->zipfiles_batched);
[3904] Fix | Delete
$zip->addFile($path, 'updraftplus-manifest.json');
[3905] Fix | Delete
$zipfiles_added_thisbatch++;
[3906] Fix | Delete
[3907] Fix | Delete
if (method_exists($zip, 'setCompressionName') && $this->file_should_be_stored_without_compression($this->zipfiles_batched[$path])) {
[3908] Fix | Delete
if (false == $zip->setCompressionName($this->zipfiles_batched[$path], ZipArchive::CM_STORE)) {
[3909] Fix | Delete
$updraftplus->log("Zip: setCompressionName failed on: $this->zipfiles_batched[$path]");
[3910] Fix | Delete
}
[3911] Fix | Delete
}
[3912] Fix | Delete
[3913] Fix | Delete
// N.B., Since makezip_addfiles() can get called more than once if there were errors detected, potentially $zipfiles_added_thisrun can exceed the total number of batched files (if they get processed twice).
[3914] Fix | Delete
$this->zipfiles_added_thisrun++;
[3915] Fix | Delete
$files_zipadded_since_open[] = array('file' => $path, 'addas' => 'updraftplus-manifest.json');
[3916] Fix | Delete
$data_added_since_reopen += filesize($path);
[3917] Fix | Delete
// $data_added_this_resumption += filesize($path);
[3918] Fix | Delete
}
[3919] Fix | Delete
}
[3920] Fix | Delete
[3921] Fix | Delete
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
[3922] Fix | Delete
$something_useful_sizetest = false;
[3923] Fix | Delete
[3924] Fix | Delete
if ($data_added_since_reopen > $maxzipbatch) {
[3925] Fix | Delete
$something_useful_sizetest = true;
[3926] Fix | Delete
$updraftplus->log("Adding batch to zip file (".$this->use_zip_object."): over ".round($maxzipbatch/1048576, 1)." MB added on this batch (".round($data_added_since_reopen/1048576, 1)." MB, ".count($this->zipfiles_batched)." files batched, $zipfiles_added_thisbatch (".$this->zipfiles_added_thisrun.") added so far); re-opening (prior size: ".round($original_size/1024, 1).' KB)');
[3927] Fix | Delete
} elseif ($zipfiles_added_thisbatch > UPDRAFTPLUS_MAXBATCHFILES) {
[3928] Fix | Delete
$updraftplus->log("Adding batch to zip file (".$this->use_zip_object."): over ".UPDRAFTPLUS_MAXBATCHFILES." files added on this batch (".round($data_added_since_reopen/1048576, 1)." MB, ".count($this->zipfiles_batched)." files batched, $zipfiles_added_thisbatch (".$this->zipfiles_added_thisrun.") added so far); re-opening (prior size: ".round($original_size/1024, 1).' KB)');
[3929] Fix | Delete
} elseif (!$reaching_split_limit) {
[3930] Fix | Delete
$updraftplus->log("Adding batch to zip file (".$this->use_zip_object."): over 2.0 seconds have passed since the last write (".round($data_added_since_reopen/1048576, 1)." MB, $zipfiles_added_thisbatch (".$this->zipfiles_added_thisrun.") files added so far); re-opening (prior size: ".round($original_size/1024, 1).' KB)');
[3931] Fix | Delete
} else {
[3932] Fix | Delete
$updraftplus->log("Adding batch to zip file (".$this->use_zip_object."): possibly approaching split limit (".round($data_added_since_reopen/1048576, 1)." MB, $zipfiles_added_thisbatch (".$this->zipfiles_added_thisrun.") files added so far); last ratio: ".round($this->zip_last_ratio, 4)."; re-opening (prior size: ".round($original_size/1024, 1).' KB)');
[3933] Fix | Delete
}
[3934] Fix | Delete
[3935] Fix | Delete
if (!$zip->close()) {
[3936] Fix | Delete
// Though we will continue processing the files we've got, the final error code will be false, to allow a second attempt on the failed ones. This also keeps us consistent with a negative result for $zip->close() further down. We don't just retry here, because we have seen cases (with BinZip) where upon failure, the existing zip had actually been deleted. So, to be safe we need to re-scan the existing zips.
[3937] Fix | Delete
$ret = false;
[3938] Fix | Delete
$this->record_zip_error($files_zipadded_since_open, $zip->last_error, $warn_on_failures);
[3939] Fix | Delete
}
[3940] Fix | Delete
[3941] Fix | Delete
// if ($data_added_this_resumption > $max_data_added_any_resumption) {
[3942] Fix | Delete
// $max_data_added_any_resumption = $data_added_this_resumption;
[3943] Fix | Delete
// $updraftplus->jobdata_set('max_data_added_any_resumption', $max_data_added_any_resumption);
[3944] Fix | Delete
// }
[3945] Fix | Delete
[3946] Fix | Delete
$zipfiles_added_thisbatch = 0;
[3947] Fix | Delete
[3948] Fix | Delete
// This triggers a re-open, later
[3949] Fix | Delete
unset($zip);
[3950] Fix | Delete
$files_zipadded_since_open = array();
[3951] Fix | Delete
// Call here, in case we've got so many big files that we don't complete the whole routine
[3952] Fix | Delete
if (filesize($zipfile) > $original_size) {
[3953] Fix | Delete
[3954] Fix | Delete
// It is essential that this does not go above 1, even though in reality (and this can happen at the start, if just 1 file is added (e.g. due to >2.0s detection) the 'compressed' zip file may be *bigger* than the files stored in it. When that happens, if the ratio is big enough, it can then fire the "approaching split limit" detection (very) prematurely
[3955] Fix | Delete
$this->zip_last_ratio = ($data_added_since_reopen > 0) ? min((filesize($zipfile) - $original_size)/$data_added_since_reopen, 1) : 1;
[3956] Fix | Delete
[3957] Fix | Delete
// We need a rolling update of this
[3958] Fix | Delete
$original_size = filesize($zipfile);
[3959] Fix | Delete
[3960] Fix | Delete
// Move on to next zip?
[3961] Fix | Delete
if ($reaching_split_limit || filesize($zipfile) > $this->zip_split_every) {
[3962] Fix | Delete
$bump_index = true;
[3963] Fix | Delete
// Take the filesize now because later we wanted to know we did clearstatcache()
[3964] Fix | Delete
$bumped_at = round(filesize($zipfile)/1048576, 1);
[3965] Fix | Delete
}
[3966] Fix | Delete
[3967] Fix | Delete
// Need to make sure that something_useful_happened() is always called
[3968] Fix | Delete
[3969] Fix | Delete
// How long since the current run began? If it's taken long (and we're in danger of not making it at all), or if that is forseeable in future because of general slowness, then we should reduce the parameters.
[3970] Fix | Delete
if (!$something_useful_sizetest) {
[3971] Fix | Delete
UpdraftPlus_Job_Scheduler::something_useful_happened();
[3972] Fix | Delete
} else {
[3973] Fix | Delete
[3974] Fix | Delete
// Do this as early as possible
[3975] Fix | Delete
UpdraftPlus_Job_Scheduler::something_useful_happened();
[3976] Fix | Delete
[3977] Fix | Delete
$time_since_began = max(microtime(true)- $this->zipfiles_lastwritetime, 0.000001);
[3978] Fix | Delete
$normalised_time_since_began = $time_since_began*($maxzipbatch/$data_added_since_reopen);
[3979] Fix | Delete
[3980] Fix | Delete
// Don't measure speed until after ZipArchive::close()
[3981] Fix | Delete
$rate = round($data_added_since_reopen/$time_since_began, 1);
[3982] Fix | Delete
[3983] Fix | Delete
$updraftplus->log(sprintf("A useful amount of data was added after this amount of zip processing: %s s (normalised: %s s, rate: %s KB/s)", round($time_since_began, 1), round($normalised_time_since_began, 1), round($rate/1024, 1)));
[3984] Fix | Delete
[3985] Fix | Delete
// We want to detect not only that we need to reduce the size of batches, but also the capability to increase them. This is particularly important because of ZipArchive()'s (understandable, given the tendency of PHP processes being terminated without notice) practice of first creating a temporary zip file via copying before acting on that zip file (so the information is atomic). Unfortunately, once the size of the zip file gets over 100MB, the copy operation beguns to be significant. By the time you've hit 500MB on many web hosts the copy is the majority of the time taken. So we want to do more in between these copies if possible.
[3986] Fix | Delete
[3987] Fix | Delete
/* "Could have done more" - detect as:
[3988] Fix | Delete
- A batch operation would still leave a "good chunk" of time in a run
[3989] Fix | Delete
- "Good chunk" means that the time we took to add the batch is less than 50% of a run time
[3990] Fix | Delete
- We can do that on any run after the first (when at least one ceiling on the maximum time is known)
[3991] Fix | Delete
- But in the case where a max_execution_time is long (so that resumptions are never needed), and we're always on run 0, we will automatically increase chunk size if the batch took less than 6 seconds.
[3992] Fix | Delete
*/
[3993] Fix | Delete
[3994] Fix | Delete
// At one stage we had a strategy of not allowing check-ins to have more than 20s between them. However, once the zip file got to a certain size, PHP's habit of copying the entire zip file first meant that it *always* went over 18s, and thence a drop in the max size was inevitable - which was bad, because with the copy time being something that only grew, the outcome was less data being copied every time
[3995] Fix | Delete
[3996] Fix | Delete
// Gather the data. We try not to do this unless necessary (may be time-sensitive)
[3997] Fix | Delete
if ($updraftplus->current_resumption >= 1) {
[3998] Fix | Delete
$time_passed = $updraftplus->jobdata_get('run_times');
[3999] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function