优化 php 内存使用?WP-filebase 插件相关


Optimising php memory usage? wp-filebase plugin related

我正在使用Wordpress的WP-Filebase插件,当脚本需要更多内存时,会遇到一些相当粗糙的结果。特别是./wp-filebase/classes/Sync上的脚本.php

这是有问题的脚本。为它的长度道歉,这里有一个糊状物。

我的问题是 - 这是否编码得很糟糕,因为它使用了大量的内存。当它尝试同步 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;

}

静态函数 Sync($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;
    }
}

我的猜测是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];
}

我使用下面的答案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;