2012-03-01 39 views
0

我開發一個網站,用戶可以上傳多個圖像到服務器/網站,在我的上傳腳本中,我已經把圖像大小限制爲10MB。這是因爲我認爲很多現代相機拍攝大型圖像。PHP圖像上傳和調整大小內存不足(96MB內存限制)

上傳腳本一次一個地獲取每個圖像,並將其調整爲3個不同的版本,900x600,600x450和更小的縮略圖圖像,並且還將水印圖像放在2個更大圖像的頂部。

我把我的php.ini memory_limit設置爲96MB,我推測這很容易。

經過一番測試,我上傳了一張6.38MB大小的JPG圖片,分辨率爲6143 x 3855 px。我收到錯誤消息「致命錯誤:允許的內存大小100663296字節用盡(試圖分配24572字節)」

您認爲這是合理的需要這麼多的內存上傳和處理這種大小的圖像?或者你認爲這更可能是我腳本中編碼的問題?

96 MB內存限制對我來說似乎很重要。其他人有哪些經驗處理大型圖片上傳?我應該將內存限制設置爲128MB或更高?或者我應該看看重寫我的上傳腳本?

我的代碼如下加入:

 //If a new image has been added, resize and upload to filesystem 
     if ($_FILES['new_image']['name'] !=''){ 

      $allowed_types=array(
      'image/gif' => '.gif', 
      'image/jpeg' => '.jpg', 
      'image/png' => '.png', 
      'image/x-png' => '.png', 
      'image/pjpeg' => '.jpg' 
     ); 

      $img = $_FILES['new_image']; 

      // Check the file to be uploaded is the correct file type and is under 9MB    

      if ((array_key_exists($img['type'], $allowed_types)) && ($img['size'] < 9000000))    { 
      // File to be uploaded is Valid 


      // File to be uploaded is Valid 

      $imagename = stripslashes($_FILES['new_image']['name']); 

      // make the random file name 
      $randName = md5(rand() * time()); 
      $ext = pathinfo($imagename, PATHINFO_EXTENSION); 


      $imagename = $randName . "." . $ext; 
      $source = $_FILES['new_image']['tmp_name']; 


      // Check if Directory Exists, if not create it 
      if(!file_exists("images/breeds/".$trimmed['profile_id'])) 
      { 
       mkdir("images/breeds/".$trimmed['profile_id']) or die("Could not create images folder for article ".$trimmed['profile_id']); 
      } 

      // Check if thumbnail Directory Exists 
      if(!file_exists("images/breeds/".$trimmed['profile_id']."/thumbs")) 
      { 
       mkdir("images/breeds/".$trimmed['profile_id']."/thumbs") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']); 
      } 

      // Check if thumbnail Directory Exists 
      if(!file_exists("images/breeds/".$trimmed['profile_id']."/large")) 
      { 
       mkdir("images/breeds/".$trimmed['profile_id']."/large") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']); 
      } 


      $LargeImage = "images/breeds/".$trimmed['profile_id']."/large/".$imagename; 
      $NormalImage = "images/breeds/".$trimmed['profile_id']."/".$imagename; 
      $SmallImage = "images/breeds/".$trimmed['profile_id']."/thumbs/".$imagename; 

      //uploaded temp file 
      $file = $_FILES['new_image']['tmp_name']; 


      //Get Image size info 
      list($width, $height, $image_type) = getimagesize($file); 

      //SourceImage 
      switch ($image_type) 
      { 
      case 1: $image = imagecreatefromgif($file); break; 
      case 2: $image = imagecreatefromjpeg($file); break; 
      case 3: $image = imagecreatefrompng($file); break; 
      default: trigger_error('Unsupported filetype!', E_USER_WARNING); break; 
      } 


      // Constraints for Large Image 
      $max_width = 900; 
      $max_height = 600; 
      $ratioh = $max_height/$height; 
      $ratiow = $max_width/$width; 
      $ratio = min($ratioh, $ratiow); 

      if (($height < $max_height) && ($width < $max_width)) { 
      //keep same dimensions 
      $modwidth = $width; 
      $modheight = $height; 
      } else { 
      // New dimensions 
      $modwidth = intval($ratio*$width); 
      $modheight = intval($ratio*$height); 
      } 

      $tmpLarge = imagecreatetruecolor($modwidth, $modheight); 

      imagecopyresampled($tmpLarge, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ; 

      // Add Watermark to large image at top right 

      $wm = "images/p4h-wm-200.png"; 
      $wmImage = imagecreatefrompng($wm); 
      $wmW = imagesx($wmImage); 
      $wmH = imagesy($wmImage); 

      $photoW = imagesx($tmpLarge); 
      $photoH = imagesy($tmpLarge); 
      $dest_x = $photoW - $wmW - 10; 
      $dest_y = 10; 

      // imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100); 
      imagecopy($tmpLarge, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH); 


      switch ($image_type) 
      { 
      case 1: imagegif($tmpLarge,$LargeImage); break; 
      case 2: imagejpeg($tmpLarge,$LargeImage, 80); break; 
      case 3: imagepng($tmpLarge,$LargeImage, 0); break; 
      default: trigger_error('Failed resize image!', E_USER_WARNING); break; 
      } 


      // Destroy tmp images to free memory 
      imagedestroy($tmpLarge); 
      imagedestroy($wmImage); 


      // Constraints for Normal Image 
      $max_width = 550; 
      $max_height = 413; 
      $ratioh = $max_height/$height; 
      $ratiow = $max_width/$width; 
      $ratio = min($ratioh, $ratiow); 

      if (($height < $max_height) && ($width < $max_width)) { 
      //keep same dimensions 
      $modwidth = $width; 
      $modheight = $height; 
      } else { 
      // New dimensions 
      $modwidth = intval($ratio*$width); 
      $modheight = intval($ratio*$height); 
      } 

      $tmpNormal = imagecreatetruecolor($modwidth, $modheight); 

      imagecopyresampled($tmpNormal, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ; 

      // Add Watermark to large image at top right 

      $wm = "images/p4h-wm-150.png"; 
      $wmImage = imagecreatefrompng($wm); 
      $wmW = imagesx($wmImage); 
      $wmH = imagesy($wmImage); 

      $photoW = imagesx($tmpNormal); 
      $photoH = imagesy($tmpNormal); 
      $dest_x = $photoW - $wmW - 10; 
      $dest_y = 10; 

      // imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100); 
      imagecopy($tmpNormal, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH); 

      switch ($image_type) 
      { 
      case 1: imagegif($tmpNormal,$NormalImage); break; 
      case 2: imagejpeg($tmpNormal,$NormalImage, 90); break; 
      case 3: imagepng($tmpNormal,$NormalImage, 0); break; 
      default: trigger_error('Failed resize image!', E_USER_WARNING); break; 
      } 

      // Destroy tmp images to free memory 
      imagedestroy($tmpNormal); 
      imagedestroy($wmImage); 


      // Now that the full size image has been saved, resize the thumbnail one to a fixed size for homepage display 
      // Constraints 
      $thumb_width = 150; 
      $thumb_height = 112.5; 

     // Calculate stuff and resize image accordingly  
     $src_ratio = $width/$height; 
     $dst_ratio = $thumb_width/$thumb_height; 
     if($src_ratio < $dst_ratio) // trim top and bottom 
     { 
      $ratio = $width/$thumb_width; 
      $crop_height = $thumb_height*$ratio; 
      $src_y = round(($height-$crop_height)/2); 
      $crop_width = $width; 
      $src_x = 0; 
     } 
     else // trim left and right 
     { 
      $ratio = $height/$thumb_height; 
      $crop_width = $thumb_width*$ratio; 
      $src_x = round(($width-$crop_width)/2); 
      $crop_height = $height; 
      $src_y = 0; 
     } 


      $tmpSmall = imagecreatetruecolor($thumb_width, $thumb_height); 

      imagecopyresampled($tmpSmall, $image, 0, 0, $src_x, $src_y, $thumb_width, $thumb_height, $crop_width, $crop_height); 

      switch ($image_type) 
      { 
      case 1: imagegif($tmpSmall,$SmallImage); break; 
      case 2: imagejpeg($tmpSmall,$SmallImage, 90); break; 
      case 3: imagepng($tmpSmall,$SmallImage, 0); break; 
      default: trigger_error('Failed resize image!', E_USER_WARNING); break; 
      } 

     // Destroy images to free memory 
     imagedestroy($image); 
     imagedestroy($tmpSmall); 
+3

你是否在你完成它們之後摧毀/釋放圖像?你是否一次打開4張圖像,或者是連續創建,保存和銷燬? – horatio 2012-03-01 15:57:07

+0

發佈代碼可能會有所幫助。還有哪些庫/工具用於調整圖像大小? – masnun 2012-03-01 15:59:32

+0

請參閱我上面添加的代碼 – user1052096 2012-03-01 16:09:07

回答

0

JPG是6.38MB,但要變換的圖像,所使用的內部表示爲原始未壓縮的一個。

圖像是23.6萬像素

它的未壓縮表示可以是32位(4字節),每個像素,即:4 * 23.6MBytes = 94兆字節。

所以,我會說,你需要有這樣大的圖像來處理?

如果是,則將memory_limit設置得更高 如果不是,則將可上載的圖像大小限制爲在您的內存設置中處理更合理的內容。

+0

該網站是一個分類廣告的網站,人們將上傳圖片到他們的廣告。我想確保我允許上傳合理尺寸的圖片。如果每次有人試圖上載一張圖片時都會感到煩惱,因爲它回覆說它太大了。 – user1052096 2012-03-01 16:03:43

+0

因此,在這種情況下,我會建議將php內存限制至少設置在256MB左右,並在嘗試處理圖像以防萬一它太大時對上傳腳本執行快速計算。 – dweeves 2012-03-01 16:05:16

0

你可能需要給PHP提供更多的提示,可以釋放內存。一個簡單的$some_variable = null;通常就足夠了。

完成圖像(主圖像及其每個縮略圖)後,請將引用變量設置爲null以幫助釋放內存。

否則,請嘗試在腳本頂部和整個腳本的各個位置打印或記錄memory_get_usage()http://www.php.net/manual/en/function.memory-get-usage.php)的結果,以追蹤內存越來越深的情況。

+0

我使用imagedestroy()在完成圖像時釋放內存,請參閱我上面添加的代碼。 – user1052096 2012-03-01 16:19:20

0

6143x3855圖像將需要至少 71,043,795字節的存儲器僅用於原始像素數據(每個像素3個字節)。然後你創建一系列其他圖像,以容納原始等的調整大小的版本...

難怪你的內存不足。

+0

看起來像我的腳本可能是好的,那麼我只需要將我的內存限制提高到256MB。 – user1052096 2012-03-01 16:21:19