使用PHP上传图像

在过去的几个月里,我一直在用PHP和MySQL构建一个活动推广网站,任何人都可以注册并添加他们的本地活动的详细信息以及我调整大小的海报。 就目前而言,我已经让整个过程在本地和托管服务上运行良好,但在网站上线之前,我对我的方式有几个问题。 这是我用来处理图片上传的功能代码。我在本节之前检查了文件大小。
$extension = substr($filename, strpos($filename,'.'), strlen($filename)-1); 
$filetypes = array('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.JPG', '.PNG', '.JPEG', '.GIF', '.BMP');
if($_FILES['image']['error'] == 4){
  $error = "No image";
  return $error; 
}
else if(($_FILES['image']['error'] == 2) || ($_FILES['image']['error'] == 1)){
  $error = "File size too big";
  return $error;
}
else if(!in_array($extension, $filetypes)){
  $error = "This isn't an image that is supported";
  return $error;
}
else if(($_FILES['image']['error'] == 7) || ($_FILES['image']['error'] == 3)){
  $error = "Error occurred. Try again";
  return $error;
}
else{
  if(($extension == '.jpg') || ($extension == '.jpeg')){
    $source = imagecreatefromjpeg($uploaded);
  }
  else if($extension == '.png'){
    $source = imagecreatefrompng($uploaded);
  }
  else{
    $source = imagecreatefromgif($uploaded);
  }
  list($width, $height) = getimagesize($uploaded);
  $ratio = $width / $height;
  $new_width = 300;
  $new_height = round(300 / $ratio); 
  $canvas = imagecreatetruecolor($new_width, $new_height);
  imagecopyresampled($canvas, $source, 0, 0, 0, 0, $new_width, $new_height, $width,       $height);
  $name = date("dmyHis").rand(0, 9);
  $path = $_SERVER[ 'DOCUMENT_ROOT' ] . '/images/uploaded/'.$name.'.jpg';
  $new_image = imagejpeg($canvas, $path,  100);
  $poster['name'] = $name.'.jpg';
  $poster['width'] = $new_width;
  $poster['height'] = $new_height;
  return $name.'.jpg';
}
就目前而言,我知道有几个错误,或者还没有完全查看过,例如某些图像从imagecreatefromwhatever中抛出错误,以及图像名称是否有“。”在它,它也会抛出一个错误。 完成此过程后,我会将图像名称保存到MySQL中的“海报”字段中,该字段将用于在查看时从文件夹中获取正确的图像。 我真正想知道的是,如果图像上传可能会遇到任何其他问题吗? 我期待相当多的流量,因此这些代码在大量使用时运行良好吗? 还有其他陷阱或事情我应该注意什么? 我是否使用最好的方法来完成工作? 我目前的文件大小限制是2MB,这个太高了吗? 即使用户上传的内容超过2MB,脚本仍会运行,我认为该文件将上传到服务器进行名称剥离和文件大小比较等,这将如何影响我的带宽使用? 原始文件在服务器上停留多长时间? 如果有人对这个问题有任何好的阅读,我会非常感激! 谢谢。 编辑:格式化。 编辑2:我没有说清楚原始文件。我的意思是我使用$ _FILES变量访问的原始文件。说它是1.9MB,在整个我摆弄扩展的时候,服务器上会有1.9MB的价值吗?一旦我创建了新图像,我应该清除这个吗?     
已邀请:
用户在文件名中发送的扩展名不能被信任或依赖。一些用户认为将'jpg'改为'gif'会使它成为gif等。 我建议使用getimagesize FIRST检查它是否是有效图像并获得exif类型。不要担心提取扩展,因为它没用。 exif类型将在getimagesize返回的数组中。 此外,CYMK图像是一个问题。有些人设法上传CYMK jpeg。检查通道将检测这些图像。它应该是3,RGB。
$image_info=getimagesize($your_image_file);
if($image_info['channels']==4)
  {
  //it's invalid - cymk
  //browsers cannot display these images. It might be possible to convert them to RGB explicitly...
  }

$real_exif=$image_info[2];
if($real_exif>0 && $real_exif<4){
 //it is a png, gif or jpg
 }
exif类型作为常量返回,如IMAGETYPE_GIF,其中数字,1是gif,2是jpg,3是png。您可以使用image_type_to_extension转换为文本文件扩展名。 现在,有时我发现getimagesize无法为有效的图像找到exif类型,并且可以使用imagemagick / GD进行处理。它没有为这些返回EXIF,因此被错误地拒绝了。我想出了这个卑鄙的黑客,至少要检测出类型并试一试......
  $handle=@fopen($temp_name,'r');
  if($handle)
    {
    $chars=fread($handle,24);
    if(stripos($chars,'jfif')!==false)
        {$type=2;} // found a jpg
    elseif(stripos($chars,'png')!==false)
      {$type=3;} // found a png
    elseif(stripos($chars,'gif')!==false)
      {$type=1;} // found a gif
    else
      {
      //file type could not be determined
      }
    }
    
Rich,我做的很相似,主要是iMagick。 GD在功能上是相似的,所以我希望没有问题。我的网站每周处理一百张图片,没有问题,可靠地服务到~1k /周。我在后端进行了所有处理,因为看起来你在这个例子中正在做,所以很少担心重入的流量(例如DIGG上的拾取)会破坏你的服务器。 通过允许任何类型的上传,您可以通过漏洞打开自己面临的最大挑战。您可能听说过IT安全人员说,防止黑客入侵的唯一方法就是下网......就像那样。我不会完全害怕,因为看起来你采取了公平的步骤来审核文件类型和大小。另一个考虑因素是查看服务器上的权限 - 打开目录只写入服务器的用户代理并阻止浏览到目录以获得额外的安全性。如果您想要倍加安全,请写入其他帐户(如果您有这样的帐户)以限制您的代码曝光。这没有必要,但如果您有疑虑,这是一个很好的额外步骤。最后,将您的上传器放在一个带有验证码的简单密码系统后面,以阻止自动漏洞检查程序....通过简单的注册步骤为用户提供免费访问。这是一个小的UI麻烦,但可以在安全方面做出一切改变。 如果用户文件超过2mb限制,我可能会考虑停止该过程。这就是我。如果某些用户尝试在服务器上强制使用带有.jpg文件扩展名的错误文件,则不希望系统崩溃和刻录。带宽可能只是一个问题,如果你是自己托管,或者如果你是通过巨额支付,这会提高你的带宽,但即使每天上传一百次,你也可能不会推动标准服务器超出其手段,除非访问该站点的相应流量为数千。大多数主机将允许您监视服务器负载。我和HostGator一起便宜了 文件无限期地保留在服务器上,假设您的帐户没有任何不良影响并且您支付账单。因此,请确保将上传文件夹与任何其他内容分开 - 一旦上传了几百个文件,就会变成一场噩梦。经常备份,只是为了安全起见。     
首先,做得好,看起来你在其中投入了大量的精力。 有一些东西可以让你的生活变得更轻松。下面列出的事情不是让你失望,而是让你学习! 你把第一个
.
的所有东西都当作现在的延伸。因此,当有人在文件名中放入
.
时出错。这可以做得更好。
$extension = '';
if ( preg_match("/\.([a-z]+)$/i",$filename,$match) )
{
    $extension = strtolower($match[1]);
}
将为您提供小写的扩展名,不带点,这意味着您不必测试JPG以及jpg等(实际上,在上传浏览器时会告诉您文件类型,无论扩展名如何,但是我们暂时跳过它 - 扩展测试会很好) 图像读数,
if JPG else if PNG else GIF
并不是很干净:你也应该测试gif,然后再转到“else”类别,然后抛出一个错误。 (这意味着你可以放弃之前的支票!) 当你说
$source = imagecreatefrom...($filename)
时你最好用@来预先设置它以避免在损坏的图像上发出警告(通常,不要使用@,但在这种情况下你无法知道图像是否已损坏)。然后总是检查返回值(总是这样做),比如
$source = @imagecreatefrompng($filename);
if ( !$source ) return "Error parsing image";
图像现在已加载,因此大小如果已知;您不必再次查询该文件。而不是
getimagesize()
你可以使用
imagesx($source)
imagesy($source)
我认为这足以解决现在的问题。 ;-) 编辑:在文件名中使用rand(0,9)的小问题btw意味着如果多个客户端在同一秒内上传,则文件混乱的可能性很大。 (每秒上传11次你肯定有问题)     
我遇到了一个允许用户上传的网站的问题:文件会正确上传,然后在我重新加载页面后不会显示。 我发现我没有正确地改变文件的权限,而且服务器主要是标记对大多数用户来说非法的东西.... 我使用CHMOD函数在上传后更改权限,然后它可靠地工作。 这是一篇关于它的文章(不是我的文章,但它很有用): http://drupal.org/node/34028     

要回复问题请先登录注册