我正在使用Wordpress的WP-Filebase插件,并且当脚本需要更多内存时会遇到一些非常糟糕的结果。特别是./wp-filebase/classes/Sync.php
中的脚本这是有问题的脚本。为它的长度道歉,有一个pastebin here。
我的问题是 - 这个编码真的很糟糕,因为它使用了大量的内存。当尝试同步500MB的文件时,内存限制仍为512.
一般来说,如何改进此脚本以减少内存使用?
static function DEcho($str) {
echo $str;
@ob_flush();
@flush();
}
static function UpdateItemsPath() {
wpfb_loadclass('File','Category');
$cats = WPFB_Category::GetCats();
$files = WPFB_File::GetFiles2();
foreach(array_keys($cats) as $i) $cats[$i]->Lock(true);
foreach(array_keys($files) as $i) $files[$i]->GetLocalPath(true);
foreach(array_keys($cats) as $i) {
$cats[$i]->Lock(false);
$cats[$i]->DBSave();
}
}
static function SyncCats()
{
$updated_cats = array();
// sync file count
$cats = WPFB_Category::GetCats();
foreach(array_keys($cats) as $i)
{
$cat = $cats[$i];
$child_files = $cat->GetChildFiles(false);
$num_files = (int)count($child_files);
$num_files_total = (int)count($cat->GetChildFiles(true));
if($num_files != $cat->cat_num_files || $num_files_total != $cat->cat_num_files_total)
{
$cat->cat_num_files = $num_files;
$cat->cat_num_files_total = $num_files_total;
$cat->DBSave();
$updated_cats[] = $cat;
}
// update category names
if($child_files) {
foreach($child_files as $file) {
if($file->file_category_name != $cat->GetTitle()) {
$file->file_category_name = $cat->GetTitle();
if(!$file->locked)
$file->DBSave();
}
}
}
@chmod ($cat->GetLocalPath(), octdec(WPFB_PERM_DIR));
}
return $updated_cats;
}
静态函数同步($ hash_sync = false,$ output = false) { @ini_set('max_execution_time','0'); @set_time_limit(0);
wpfb_loadclass("Admin", "GetID3");
require_once(ABSPATH . 'wp-admin/includes/file.php');
$result = array('missing_files' => array(), 'missing_folders' => array(), 'changed' => array(), 'not_added' => array(), 'error' => array(), 'updated_categories' => array());
$sync_id3 = !WPFB_Core::GetOpt('disable_id3');
// some syncing/updating
self::UpdateItemsPath();
WPFB_Admin::SyncCustomFields();
$files = WPFB_File::GetFiles2();
$cats = WPFB_Category::GetCats();
if($output) self::DEcho('<p>'. __('Checking for file changes...',WPFB).' ');
$db_files = array();
foreach($files as $id => /* & PHP 4 compability */ $file)
{
$file_path = str_replace('//','/',str_replace('\\', '/', $file->GetLocalPath(true)));
$db_files[] = $file_path;
if($file->GetThumbPath())
$db_files[] = str_replace('//','/',str_replace('\\', '/', $file->GetThumbPath()));
if($file->file_category > 0 && is_null($file->GetParent()))
$result['warnings'][] = sprintf(__('Category (ID %d) of file %s does not exist!', WPFB), $file->file_category, $file->GetLocalPathRel());
// TODO: check for file changes remotly
if($file->IsRemote())
continue;
if(!@is_file($file_path) || !@is_readable($file_path))
{
$result['missing_files'][$id] = $file;
continue;
}
if($hash_sync) $file_hash = @md5_file($file_path);
$file_size = (int)@filesize($file_path);
$file_mtime = filemtime($file_path);
$file_analyzetime = !$sync_id3 ? $file_mtime : WPFB_GetID3::GetFileAnalyzeTime($file);
if(is_null($file_analyzetime)) $file_analyzetime = 0;
if( ($hash_sync && $file->file_hash != $file_hash)
|| $file->file_size != $file_size || $file->file_mtime != $file_mtime
|| $file_analyzetime < $file_mtime)
{
$file->file_size = $file_size;
$file->file_mtime = $file_mtime;
$file->file_hash = $hash_sync ? $file_hash : @md5_file($file_path);
if($sync_id3)
WPFB_GetID3::UpdateCachedFileInfo($file);
$res = $file->DBSave();
if(!empty($res['error']))
$result['error'][$id] = $file;
else
$result['changed'][$id] = $file;
}
}
if($output) self::DEcho('done!</p>');
foreach($cats as $id => $cat) {
$cat_path = $cat->GetLocalPath(true);
if(!@is_dir($cat_path) || !@is_readable($cat_path))
{
$result['missing_folders'][$id] = $cat;
continue;
}
}
if($output) self::DEcho('<p>'. __('Searching for new files...',WPFB).' ');
// search for not added files
$upload_dir = str_replace('//','/',str_replace('\\', '/', WPFB_Core::UploadDir()));
$upload_dir_len = strlen($upload_dir);
$all_files = str_replace('//','/',str_replace('\\', '/', list_files($upload_dir)));
$num_all_files = count($all_files);
$new_files = array();
$num_new_files = 0;
$num_files_to_add = 0;
// 1ps filter (check extension, special file names, and filter existing file names and thumbnails)
$fext_blacklist = array_map('strtolower', array_map('trim', explode(',', WPFB_Core::GetOpt('fext_blacklist'))));
for($i = 0; $i < $num_all_files; $i++)
{
$fn = $all_files[$i];
$fbn = basename($fn);
if(strlen($fn) < 2 || $fbn{0} == '.' || strpos($fn, '/.tmp') !== false
|| $fbn == '_wp-filebase.css' || strpos($fbn, '_caticon.') !== false
|| in_array($fn, $db_files)
|| !is_file($fn) || !is_readable($fn)
|| (!empty($fext_blacklist) && in_array(trim(strrchr($fbn, '.'),'.'), $fext_blacklist)) // check for blacklisted extension
)
continue;
$new_files[$num_new_files] = $fn;
$num_new_files++;
}
$num_files_to_add = $num_new_files;
$thumbnails = array();
// look for thumnails
// find files that have names formatted like thumbnails e.g. file-XXxYY.(jpg|jpeg|png|gif)
for($i = 1; $i < $num_new_files; $i++)
{
$len = strrpos($new_files[$i], '.');
// file and thumbnail should be neighbours in the list, so only check the prev element for matching name
if(strlen($new_files[$i-1]) > ($len+2) && substr($new_files[$i-1],0,$len) == substr($new_files[$i],0,$len) && !in_array($new_files[$i-1], $db_files))
{
$suffix = substr($new_files[$i-1], $len);
$matches = array();
if(preg_match(WPFB_File::$thumbnail_regex, $suffix, $matches) && ($is = getimagesize($new_files[$i-1])))
{
if($is[0] == $matches[1] && $is[1] == $matches[2])
{
//ok, found a thumbnail here
$thumbnails[$new_files[$i]] = basename($new_files[$i-1]);
$new_files[$i-1] = ''; // remove the file from the list
$num_files_to_add--;
continue;
}
}
}
}
if(WPFB_Core::GetOpt('base_auto_thumb')) {
for($i = 0; $i < $num_new_files; $i++)
{
$len = strrpos($new_files[$i], '.');
$ext = strtolower(substr($new_files[$i], $len+1));
if($ext != 'jpg' && $ext != 'png' && $ext != 'gif') {
$prefix = substr($new_files[$i], 0, $len);
for($ii = $i-1; $ii >= 0; $ii--)
{
if(substr($new_files[$ii],0, $len) != $prefix) break;
$e = strtolower(substr($new_files[$ii], $len+1));
if($e == 'jpg' || $e == 'png' || $e == 'gif') {
$thumbnails[$new_files[$i]] = basename($new_files[$ii]);
$new_files[$ii] = ''; // remove the file from the list
$num_files_to_add--;
break;
}
}
for($ii = $i+1; $ii < $num_new_files; $ii++)
{
if(substr($new_files[$ii],0, $len) != $prefix) break;
$e = strtolower(substr($new_files[$ii], $len+1));
if($e == 'jpg' || $e == 'png' || $e == 'gif') {
$thumbnails[$new_files[$i]] = basename($new_files[$ii]);
$new_files[$ii] = ''; // remove the file from the list
$num_files_to_add--;
break;
}
}
}
}
}
if($output && $num_files_to_add > 0) {
echo "<p>";
printf(__('%d Files found, %d new.', WPFB), $num_all_files, $num_files_to_add);
echo "</p>";
include(WPFB_PLUGIN_ROOT.'extras/progressbar.class.php');
$progress_bar = new progressbar(0, $num_files_to_add);
$progress_bar->print_code();
} else {
if($output) self::DEcho('done!</p>');
}
for($i = 0; $i < $num_new_files; $i++)
{
$fn = $new_files[$i];
if(empty($fn)) continue;
$fbn = basename($fn);
$res = WPFB_Admin::AddExistingFile($fn, empty($thumbnails[$fn]) ? null : $thumbnails[$fn]);
if(empty($res['error']))
$result['added'][] = empty($res['file']) ? substr($fn, $upload_dir_len) : $res['file'];
else
$result['error'][] = $res['error'] . " (file $fn)";
if(!empty($progress_bar))
$progress_bar->step(1);
}
if(!empty($progress_bar))
$progress_bar->complete();
// chmod
if($output) self::DEcho('<p>Setting permissions...');
@chmod ($upload_dir, octdec(WPFB_PERM_DIR));
for($i = 0; $i < count($db_files); $i++)
{
if(file_exists($db_files[$i]))
{
@chmod ($db_files[$i], octdec(WPFB_PERM_FILE));
if(!is_writable($db_files[$i]) && !is_writable(dirname($db_files[$i])))
$result['warnings'][] = sprintf(__('File <b>%s</b> is not writable!', WPFB), substr($db_files[$i], $upload_dir_len));
}
}
if($output) self::DEcho('done!</p>');
// sync categories
if($output) self::DEcho('<p>Syncing categories... ');
$result['updated_categories'] = self::SyncCats();
if($output) self::DEcho('done!</p>');
wpfb_call('Setup','ProtectUploadPath');
WPFB_File::UpdateTags();
return $result;
}
}
答案 0 :(得分:1)
我的猜测是md5_file()
功能。当禁用散列时,内存问题是否仍然存在?为了计算md5,必须将文件读入内存。我不确定PHP的实现细节,但这可能是问题,特别是对于大文件。
如果您需要散列,请查看此处的评论:http://php.net/manual/en/function.md5-file.php - 他们建议使用openssl md5sum
实用程序而不是md5_file()
。 md5sum
是通过exec()
启动的,因此php内存限制不适用。应该对大型和大型文件进行更多的战斗测试。
$result = explode(" ", exec("md5sum $file_path"));
echo "Hash = ".$result[0]."<br />";
所以你试着替换:
if($hash_sync) $file_hash = @md5_file($file_path);
使用:
if($hash_sync) {
$file_hash = explode(" ", exec("md5sum $file_path"));
$file_hash = $file_hash[0];
}
答案 1 :(得分:0)
我在回答下面使用emteh's
来修改wp-filebase中的另一个if语句,如果有人想解决他们的问题。
第99行,其中显示
if($hash_sync) {
$file_hash = explode(" ", exec("md5sum $file_path"));
$file_hash = $file_hash[0];
}
//新行修复第115行if语句
$new_file_hash = explode(" ", exec("md5sum $file_path"));
$new_file_hash = $new_file_hash[0];
115行左右替换
$file->file_hash = $hash_sync ? $file_hash : @md5_file($file_path);
与
$file->file_hash = $hash_sync ? $file_hash : $new_file_hash;