2010-11-12 54 views
2

是的我有一個PHP內存的問題。我的主人提供最大值。使用64M的內存限制,不知何故,當我上傳+裁剪功能超過這個內存,並IM即時接收錯誤(並不總是,但取決於圖像的大小)PHP:處理內存和代碼的低內存使用率

當我上傳一個約1 MB或更低的圖像,它上傳,您可以裁剪並保存。

但是,當我上傳大約2 MB或更高的圖像(我對uploadfunction的限制是6mb)時,它會上傳,然後當您裁剪圖像並想要保存圖像時,我會收到「內存不足錯誤」。

我試圖在gd中的任何函數之後使用imagedestroy(),我不再使用它,但是這並沒有影響它。雖然即時通訊在功能上只使用GD功能

那麼有沒有什麼能夠在上傳的情況下釋放我的記憶?

或者一般來說如何釋放php內存的使用?

這裏是我的腳本:

switch($action) { 

    case 'upload': 


    $userid = $USER; 
    $user = getUserInfo($userid); 
    $lasttime = $user['showURP']["photo_lasttime"]; 

    $upload_name = "file"; 
    $max_file_size_in_bytes = 8388608; 
    $extension_whitelist = array("jpg", "gif", "png", "jpeg"); 

    /* checking extensions */ 
    $path_info = pathinfo($_FILES[$upload_name]['name']); 
    $file_extension = $path_info["extension"]; 
    $is_valid_extension = false; 
    foreach ($extension_whitelist as $extension) { 
     if (strcasecmp($file_extension, $extension) == 0) { 
      $is_valid_extension = true; 
      break; 
     } 
    } 
    if (!$is_valid_extension) { 
     echo "{"; 
     echo  "error: 'Filtype not allowed!'\n"; 
     echo "}"; 
     exit(0); 
    } 
    /* checking filetype*/ 
switch(exif_imagetype($_FILES[$upload_name]['tmp_name'])) { 
    case IMAGETYPE_GIF: 
    case IMAGETYPE_JPEG: 
    case IMAGETYPE_PNG: 
     break; 
    default: 
     echo "{"; 
     echo  "error: 'This is no real image!'\n"; 
     echo "}"; 
     exit(0); 
} 

    /* file size check */ 
    $file_size = @filesize($_FILES[$upload_name]["tmp_name"]); 
    if (!$file_size || $file_size > $max_file_size_in_bytes) { 
     echo "{"; 
     echo  "error: 'Filesize exceeds the limit: 6MB'\n"; 
     echo "}"; 
     exit(0); 
    } 




    if(isset($_FILES[$upload_name])) 
     if ($_FILES[$upload_name]["error"] > 0) { 
      echo "Error: " . $_FILES["file"]["error"] . "<br />"; 
      } else { 
       $userfile = stripslashes($_FILES[$upload_name]['name']); 
       $file_size = $_FILES[$upload_name]['size']; 
       $file_temp = $_FILES[$upload_name]['tmp_name']; 
       $file_type = $_FILES[$upload_name]["type"]; 
       $file_err = $_FILES[$upload_name]['error']; 
       $file_name = $userfile; 

       if(move_uploaded_file($file_temp, "images/profilePhoto/".$file_name)) { 
        echo "{"; 
        echo  "msg: '".$file_name."'"; 
        echo "}"; 
       } 
      } 
    break; 

    case 'crop': 
    if ($_SERVER['REQUEST_METHOD'] == 'POST') { 


     $jpeg_quality = 90; 

     $src = "images/profilePhoto/".$_POST['fname']; 
     $ext= pathinfo($src, PATHINFO_EXTENSION); 


    if($ext == "jpg" OR $ext == "jpeg" OR $ext == "JPG"){ 
     $img_r = imagecreatefromjpeg($src); // <-- im getting out of memory error on this line 

    }elseif($ext == "png" OR $ext == "PNG"){ 
     $img_r = imagecreatefrompng($src); 
    }elseif($ext == "gif" OR $ext == "GIF"){ 
     $img_r = imagecreatefromgif($src); 
    } 

     if($_POST['fixed'] == 0) { 
      $targ_w = $_POST['w']; 
      $targ_h = $_POST['h']; 
     } 
     else { 
      $targ_h = $_POST['sizeh']; 
      $targ_w = $_POST['sizew']; 
     } 

     $dst_r = ImageCreateTrueColor($targ_w, $targ_h); 

     imagecopyresampled($dst_r,$img_r,0,0,$_POST['x'],$_POST['y'], 
     $targ_w,$targ_h,$_POST['w'],$_POST['h']); 
     imagedestroy($img_r); // free memory 

    $path_thumbs = "images/profilePhoto/thumbs"; 
     $filename = $USER . ".jpg"; 
     $thumb_path = $path_thumbs . '/' . $filename; 

     imagejpeg($dst_r,$thumb_path,$jpeg_quality); 
     imagedestroy($dst_r); // free memory 

     echo json_encode(array(
      'filename'=>$thumb_path 
     )); 
     unlink($src);  


    } 
    break; 
} 

我的主機只支持GD庫用於裁剪圖像,所以可以使用ImageMagick的斜面。

,正如我前面提到的,我的主機有64M一個memory_limit的,是不能被設置

+0

爲什麼-1 ?? ... – Karem 2010-11-12 08:59:56

回答

1

請記住,而GD是處理圖像,它不是存儲在一個壓縮格式。因此,GD需要與圖像一起工作的數量與其大小(寬度x高度)成正比,而上傳的圖像可能是壓縮的,因此在您自己的磁盤上可能會小得多。例如,你可能正在上傳一個1MB文件,但該文件實際上是1024x1024像素,因此需要大約4MB的內存供GD加載 - 或者如果它更大(比如說2048x2048),它會是更像是16MB的內存等等。

+0

你好。謝謝,讓我明白!但是我怎樣才能解決這個問題並降低使用率呢? – Karem 2010-11-12 08:52:00

+0

iam確定您已經嘗試過「ini_set(」memory_limit「,」1024M「);?;-) – opHASnoNAME 2010-11-12 08:53:12

+0

是的,我無法更改它,因爲我的最大值爲64M – Karem 2010-11-12 08:59:13

0

文件大小對jpeg不重要,因爲東西是壓縮的。如果你使用這個圖像,它會以位圖的形式存儲在內存中,我認爲這就是你的問題。

您可以嘗試ImageMagick,因爲它不需要像gd那樣多的內存!

ImageMagick on php.net

+0

我的主機不支持Imagemagick – Karem 2010-11-12 08:51:12

4

不幸的是你要通過你的內存限制的約束。 GD庫看起來好像有可怕的內存管理。我只是嘗試加載一個尺寸爲3951x2520 &的圖像,我的腳本內存使用量從加載前的512KB變爲加載後的大約50MB(PHP 5.3.3,Windows 7 Home x64)。實際的圖像應該佔用大約28.49MB的內存,那麼爲什麼GD幾乎增加了這個數量的一倍?我不知道。

編輯:實際上,它看起來像是因爲GD將圖像存儲在內存GD2格式中,這不是內存高效的。

Edit2:看起來GD2格式實際上只是在實際真彩色位圖上膨脹了大約67%。令人驚訝的是,原始GD格式比原始圖像本身或GD2佔用更小的空間。我相信這是由抖動造成的,這在輸出中是顯而易見的。我可以看到將文件加載到原始GD格式的唯一方法是首先使用它的圖像函數(例如imagecreatefromjpeg)加載它,然後使用imagegd(而不是imagegd2)保存它,然後使用imagecreatefromgd重新加載它。這不是非常有效,並且確實發生抖動。

最後編輯

這我覺得是一個比我早了下面一個更好的功能。你給它的文件名稱與目標高度&寬度&它將檢查可用內存並返回true或false,如果你有足夠的執行調整大小。如果你想知道需要多少內存,那麼你可以傳遞true作爲$ returnRequiredMem參數。

function checkMemAvailbleForResize($filename, $targetX, $targetY,$returnRequiredMem = false, $gdBloat = 1.68) { 
    $maxMem = ((int) ini_get('memory_limit') * 1024) * 1024; 
    $imageSizeInfo = getimagesize($filename); 
    $srcGDBytes = ceil((($imageSizeInfo[0] * $imageSizeInfo[1]) * 3) * $gdBloat); 
    $targetGDBytes = ceil((($targetX * $targetY) * 3) * $gdBloat); 
    $totalMemRequired = $srcGDBytes + $targetGDBytes + memory_get_usage(); 
    if ($returnRequiredMem) return $srcGDBytes + $targetGDBytes; 
    if ($totalMemRequired > $maxMem) return false; 
    return true; 
} 

例子:

if (!checkMemAvailableForResize('path/to/file.jpg', 640,480)) die('Cannot resize!'); 

或:

$totalBytesNeeded = checkMemAvailableForResize('path/to/file.jpg',640,480,true); 

此外,您可以調整$ gdBloat參數的情況下,68%的過少或過多的開銷:

checkMemAvailableForResize('path/to/file.jpg',640,480,false, 1.69); 
+0

您好。你的腳本和成功我得到這個錯誤,我想知道你是如何設置尺寸限制?(多少高度px和寬度px)。謝謝 – Karem 2010-11-12 11:26:36

+0

/圖像有多大?1024px * 1024px? – Karem 2010-11-12 11:33:01

+0

那麼例如:512x2048等於1048576像素,但是1024x1024也是如此,你可以設置一個硬性限制,如果你想要1024x1024,那很可能會讓你在正常的範圍內,這個腳本是假設的更靈活,並且更好地計算內存限制,而不是施加硬性限制。第一行控制允許單個圖像佔用多少內存,您可以更改e 32到24或48,這將減少或提高圖像允許採用的RAM的MB數量。 – Klinky 2010-11-12 20:05:30

0

您應該調整圖像大小o n客戶瀏覽器而不是服務器上。 這是用html5 canvas元素製作的。您可以編寫自己的功能或使用插件。有一個很好的jQuery插件來做到這一點。

Blueimp jQuery File Upload