为什么我的PHP脚本在生成缩略图时会停止?

为什么我的PHP脚本在生成缩略图时会停止?,php,html,imagemagick,thumbnails,Php,Html,Imagemagick,Thumbnails,我是一名PHP初学者,我正在尝试构建一个图库页面,该页面将输出文件夹中所有195个图像的缩略图。这些图像平均每个8MB。目前的情况如下: 脚本文件夹中的php.ini allow_url_fopen = On display_errors = On enable_dl = Off file_uploads = On max_execution_time = 999 max_input_time = 999 max_input_vars = 1000 memory_limit = 999M pos

我是一名PHP初学者,我正在尝试构建一个图库页面,该页面将输出文件夹中所有195个图像的缩略图。这些图像平均每个8MB。目前的情况如下:

脚本文件夹中的php.ini

allow_url_fopen = On
display_errors = On
enable_dl = Off
file_uploads = On
max_execution_time = 999
max_input_time = 999
max_input_vars = 1000
memory_limit = 999M
post_max_size = 516M
session.gc_maxlifetime = 1440
session.save_path = "/var/cpanel/php/sessions/ea-php74"
upload_max_filesize = 512M
zlib.output_compression = Off
PHP/HTML代码

<?php
DEFINE('UPLOAD_DIR', 'sources/');
DEFINE('THUMB_DIR', 'thumbs/');

function GenerateThumbnail($src, $dest)
{
    $Imagick = new Imagick($src);
    
    $bigWidth = $Imagick->getImageWidth();
    $bigHeight = $Imagick->getImageHeight();
    
    $scalingFactor = 230 / $bigWidth;
    $newheight = $bigHeight * $scalingFactor;
    
    $Imagick->thumbnailImage(230,$newheight,true,true);
    $Imagick->writeImage($dest);
    $Imagick->clear();
    
    return true;    
}

// Get list of files in upload dir
$arrImageFiles = scandir(UPLOAD_DIR);

// Remove non-images
$key = array_search('.', $arrImageFiles);
if ($key !== false) 
    unset($arrImageFiles[$key]);

$key = array_search('..', $arrImageFiles);
if ($key !== false) 
    unset($arrImageFiles[$key]);

$key = array_search('.ftpquota', $arrImageFiles);
if ($key !== false) 
    unset($arrImageFiles[$key]);

$key = array_search('thumbs', $arrImageFiles);
if ($key !== false) 
    unset($arrImageFiles[$key]);

?><!DOCTYPE HTML>
<html lang="fr">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Select Image</title>
</head>
    <body>
<?php
foreach($arrImageFiles as $imageFile)
{
        $thumbFullPath =  THUMB_DIR . "th_" . $imageFile;
        $imageFullPath = UPLOAD_DIR . $imageFile;

        if (! file_exists($thumbFullPath))  
        {           
            GenerateThumbnail($imageFullPath, $thumbFullPath);
        }
        
        echo "<img alt='' src='" . $thumbFullPath . "'>";
    
}
?>              
    </body>
</html>

选择图像
我不知道如何解决的两个问题是:

  • 在生成所有缩略图之前(30-50个缩略图之后),脚本似乎会在某个点停止。没有记录任何错误
  • 直到脚本停止,然后我才能看到(不完整的)输出,页面才会加载到浏览器中
  • 以下是我已经尝试过的:

  • 使用输出缓冲(可能不正确,因为新手)
  • 将输出连接到变量中,并在末尾回显(无更改)
  • 使用不同的方法生成缩略图(imagecopyresample、imagescale、ImageMagick等),这只会略微改变成功缩略图的数量

  • 谢谢你的建议,我有点迷路了。

    问题肯定是超时或资源短缺(内存或类似的东西)。显示ImageMagick,每个映像占用315.03 MB内存,CPU占用率为47%。如果以
    foreach
    循环的方式在处理器中循环处理图像,则会产生复合/泄漏。在服务器资源上进行图像转换可能会很昂贵。这也可能是您的图像文件或其他一些奇怪的问题

    Ajax it 解决这些问题的办法是分批处理。创建一个简单的ajax/php循环-使用一个html.php页面进行ajax,并使用一个单独的文件进行处理,如下所示:

    thumb display.php

    <script>
    const batchSize = 5; // number of images per send
    function doThumb(nextIndex) {
        $.ajax({
          url: "thumb-process.php",
          method: "post",
          data: {nextIndex: nextIndex, batchSize: batchSize},
          dataType: "json"
        }).done(function(response) {
          if (response.thumbs) {
             response.thumbs.forEach( th => $('.thumbs').append('<img alt="" src="'+th+'" />') ) ;
          }
          if (response.finished) alert('finished')
          else {
            console.log('processed batch index #' + (nextIndex-batchSize + ' - ' + nextIndex);
            nextIndex += batchSize;
            setTimeout(() => { doThumb(nextIndex) }, 1000);
          }
        }).error(function (e) {
           console.error('Error happened on batch index #' + (nextIndex-batchSize + ' - ' + nextIndex, ' - details: ', e);
        })
        ;
    }
    
    $(document).ready(() => { doThumb(0); } )
    </script>
    
    
    <div class='thumb-list'></div>
    
    function GenerateThumbnail($src, $dest)
    {
        $Imagick = new Imagick($src);
        $bigWidth = $Imagick->getImageWidth();
        $bigHeight = $Imagick->getImageHeight();
        $scalingFactor = 230 / $bigWidth;
        $newheight = $bigHeight * $scalingFactor;
        $Imagick->thumbnailImage(230,$newheight,true,true);
        $Imagick->writeImage($dest);
        $Imagick->clear();
        return true;    
    }
    
    // Get list of files in upload dir
    $arrImageFiles = scandir(UPLOAD_DIR);
    
    // Remove non-images
    $key = array_search('.', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('..', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('.ftpquota', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('thumbs', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    $nextIndex = $_POST['nextIndex'];
    $max = min( ($nextIndex + $_POST['batchSize']), count($arrImageFiles)-1);
    $thumbs = [];
    while($nextIndex < $max){    
      $imageFile = $arrImageFiles[$nextIndex ];
      $thumbFullPath =  THUMB_DIR . "th_" . $imageFile;
      $imageFullPath = UPLOAD_DIR . $imageFile;
      if (!$imageFile) {
        $output = array('finished' => 1) ;
        die(json_encode($output));
      }
      if (! file_exists($thumbFullPath))  {           
        GenerateThumbnail($imageFullPath, $thumbFullPath);
      }
      $thumbs[]= $thumbFullPath ;
      $nextIndex++;
    }
    
    $output = array('thumbs' => $thumbs);
      
    if ($nextIndex >= count($arrImageFiles)-1) $output['finished'] = 1 ;
    
    echo json_encode($output);
    
    
    常量batchSize=5;//每次发送的图像数
    函数doThumb(nextIndex){
    $.ajax({
    url:“thumb process.php”,
    方法:“张贴”,
    数据:{nextIndex:nextIndex,batchSize:batchSize},
    数据类型:“json”
    }).完成(功能(响应){
    if(response.thumbs){
    response.thumbs.forEach(th=>$('.thumbs').append('');
    }
    if(response.finished)警报(‘finished’)
    否则{
    log('processed batch index#'+(nextIndex batchSize+'-'+nextIndex);
    nextIndex+=批量大小;
    setTimeout(()=>{doThumb(nextIndex)},1000);
    }
    }).错误(函数(e){
    console.error('批索引#'+(nextIndex batchSize+'-'+nextIndex'-详细信息:',e)上发生错误);
    })
    ;
    }
    $(document).ready(()=>{doThumb(0);})
    
    thumb process.php

    <script>
    const batchSize = 5; // number of images per send
    function doThumb(nextIndex) {
        $.ajax({
          url: "thumb-process.php",
          method: "post",
          data: {nextIndex: nextIndex, batchSize: batchSize},
          dataType: "json"
        }).done(function(response) {
          if (response.thumbs) {
             response.thumbs.forEach( th => $('.thumbs').append('<img alt="" src="'+th+'" />') ) ;
          }
          if (response.finished) alert('finished')
          else {
            console.log('processed batch index #' + (nextIndex-batchSize + ' - ' + nextIndex);
            nextIndex += batchSize;
            setTimeout(() => { doThumb(nextIndex) }, 1000);
          }
        }).error(function (e) {
           console.error('Error happened on batch index #' + (nextIndex-batchSize + ' - ' + nextIndex, ' - details: ', e);
        })
        ;
    }
    
    $(document).ready(() => { doThumb(0); } )
    </script>
    
    
    <div class='thumb-list'></div>
    
    function GenerateThumbnail($src, $dest)
    {
        $Imagick = new Imagick($src);
        $bigWidth = $Imagick->getImageWidth();
        $bigHeight = $Imagick->getImageHeight();
        $scalingFactor = 230 / $bigWidth;
        $newheight = $bigHeight * $scalingFactor;
        $Imagick->thumbnailImage(230,$newheight,true,true);
        $Imagick->writeImage($dest);
        $Imagick->clear();
        return true;    
    }
    
    // Get list of files in upload dir
    $arrImageFiles = scandir(UPLOAD_DIR);
    
    // Remove non-images
    $key = array_search('.', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('..', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('.ftpquota', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    
    $key = array_search('thumbs', $arrImageFiles);
    if ($key !== false) 
        unset($arrImageFiles[$key]);
    $nextIndex = $_POST['nextIndex'];
    $max = min( ($nextIndex + $_POST['batchSize']), count($arrImageFiles)-1);
    $thumbs = [];
    while($nextIndex < $max){    
      $imageFile = $arrImageFiles[$nextIndex ];
      $thumbFullPath =  THUMB_DIR . "th_" . $imageFile;
      $imageFullPath = UPLOAD_DIR . $imageFile;
      if (!$imageFile) {
        $output = array('finished' => 1) ;
        die(json_encode($output));
      }
      if (! file_exists($thumbFullPath))  {           
        GenerateThumbnail($imageFullPath, $thumbFullPath);
      }
      $thumbs[]= $thumbFullPath ;
      $nextIndex++;
    }
    
    $output = array('thumbs' => $thumbs);
      
    if ($nextIndex >= count($arrImageFiles)-1) $output['finished'] = 1 ;
    
    echo json_encode($output);
    
    函数GenerateThumbnail($src,$dest)
    {
    $Imagick=新Imagick($src);
    $bigWidth=$Imagick->getImageWidth();
    $bighight=$Imagick->getImageHeight();
    $scalingFactor=230/$bigWidth;
    $newheight=$bighight*$scalingFactor;
    $Imagick->thumbnailImage(230,$newheight,true,true);
    $Imagick->writeImage($dest);
    $Imagick->clear();
    返回true;
    }
    //获取上载目录中的文件列表
    $arrImageFiles=scandir(上传目录);
    //删除非图像
    $key=array_search('.',$arrImageFiles);
    如果($key!==false)
    取消设置($arrImageFiles[$key]);
    $key=array_search(“..”,$arrImageFiles);
    如果($key!==false)
    取消设置($arrImageFiles[$key]);
    $key=array_search('.ftpquota',$arrImageFiles);
    如果($key!==false)
    取消设置($arrImageFiles[$key]);
    $key=array_search('thumbs',$arrImageFiles);
    如果($key!==false)
    取消设置($arrImageFiles[$key]);
    $nextIndex=$\u POST['nextIndex'];
    $max=min($nextIndex+$_POST['batchSize']),count($arrImageFiles)-1;
    $thumbs=[];
    而($nextIndex<$max){
    $imageFile=$ARRIGEFILES[$nextIndex];
    $thumbFullPath=THUMB_DIR.“th_u”。$imageFile;
    $imageFullPath=UPLOAD_DIR.$imageFile;
    如果(!$imageFile){
    $output=array('finished'=>1);
    die(json_编码($output));
    }
    如果(!file_存在($thumbFullPath)){
    生成缩略图($imageFullPath,$thumbFullPath);
    }
    $thumbs[]=$thumbFullPath;
    $nextIndex++;
    }
    $output=array('thumbs'=>$thumbs);
    如果($nextIndex>=count($arrImageFiles)-1)$output['finished']=1;
    echo json_编码($output);
    
    ..然后坐下来观察你的控制台。如果你遇到超时或其他错误,你会看到
    nextIndex
    它被阻塞了,你可以用这个数字作为起始索引而不是0重新加载你的页面


    当然,您可以在thumb-display.php中收集数组中的所有文件路径,并通过ajax发送每个文件路径(这样就不必每次重新计算该路径中的所有文件),但就我个人而言,通过post而不是图像路径发送数字会让我感觉更好。请告诉我您是否希望发送大量文件路径而不是索引。

    @kinglish的答案是通过ajax加载它们很好,但我认为这不是正确的方法。这会减轻服务器的一些处理,因为它不运行它们但如果你想让很多用户访问195张图片,这仍然不是一个好的解决方案

    这里最大的问题是,您正试图根据请求处理图像,因此每次页面加载都会请求并重新创建所有195个图像。这对性能不好,而且您网站上的10个用户可能会通过刷新页面几次而使服务器崩溃,除非您为此支付的费用超过10美元/月

    所以,这里有一个更好的解决方案

    仅在198个图像的循环上运行图像处理脚本服务器端。 您可以查看如何运行命令来执行php文件,或者如果您使用SSH连接到linux机器中,只需执行“php yourfile.php”

    脚本运行和处理图像的速度将比通过浏览器请求时快。[不知道细节,只是它是这样工作的]

    将图像存储到“缩略图”目录中,然后像通常通过标签一样加载它们。 TADA的问题解决了。这样你只处理一次,剩下的时间你只为他们服务