2012-03-01 38 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