如何确保下载到服务器的远程图像实际上是PHP的图像?

时间:2015-06-26 05:37:22

标签: php gd

我正在构建一个PHP应用程序,它将作为SugarCRM模块分发给数百或数千个用户。我正在处理的功能允许用户从远程URL上传图像。

StackOverflow具有相同的功能,如底部图像所示。

我在其他服务器上提到这个问题,因为我的上传功能需要在许多服务器配置和网络主机上非常可靠!

为了使其在获取和下载远程图像方面更加可靠,我在fetch_image($image_url)函数中进行了一些检查,例如......

ini_get('allow_url_fopen')查看他们是否允许file_get_contents()使用网址而不是文件路径。

我使用function_exists('curl_init')查看是否安装了CURL。

除了使用多种方法获取远程图像。我现在还需要确保从远程服务器返回或构建的文件实际上是合法的映像文件而不是某种恶意文件!

大多数服务器至少安装了GD image processor所以也许它可以在我的图像上以某种方式使用以确保它是一个图像?

到目前为止我的代码低于......

检查以确保图像是图像的任何帮助!

套接字方法似乎实际上生成了一个保存在服务器临时文件夹中的文件。其他方法只返回图像的字符串。

<?php

class GrabAndSave {

    public $imageName;
    public $imageFolderPath = 'remote-uploads/'; // Folder to Cache Amazon Images in
    public $remote_image_url;
    public $local_image_url;
    public $temp_file  = '';
    public $temp_file_prefix = 'tmp';

    public function __construct(){
        //
    }

    public function fetch_image($image_url) {

        // check if CURL is installed
        if (function_exists('curl_init')){
            return $this->curl_fetch_image($image_url);
        // Check if PHP allows file_get_contents to use URL instead of file paths
        }elseif(ini_get('allow_url_fopen')){
            return $this->fopen_fetch_image($image_url);
        // Try Sockets
        }else{
            return $this->sockets_fetch_image($image_url);
        }
    }



    public function curl_fetch_image($image_url) {

        if (function_exists('curl_init')) {
             //Initialize a new resource for curl
             $ch = curl_init();

             //Set the url the retrieve
             curl_setopt($ch, CURLOPT_URL, $image_url);

             //Return the value instead of outputting to the browser
             curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

             $image = curl_exec($ch);
             curl_close($ch);

             if ($image) {
                  //Do stuff with the image
                  return $image;
             } else {
                  //Show error message
             }

        }else{
            die('cURL is not enabled on this server.');
        }
    }


    public function fopen_fetch_image($url) {
        $image = file_get_contents($url, false, $context);
        return $image;
    }


    public function sockets_fetch_image($image_url)
    {
        if($this->temp_file)
        {
            throw new Exception('Resource has been downloaded already.');
        }

        $this->temp_file = tempnam(sys_get_temp_dir(), $this->temp_file_prefix);

        $srcResource = fopen($image_url, 'r');
        $destResource = fopen($this->temp_file, 'w+');

        stream_copy_to_stream($srcResource, $destResource);

        return $this->temp_file;
    }


    public function save_image($image_filename, $raw_image_string){
            $local_image_file = fopen($this->imageFolderPath . $image_filename, 'w+');
            chmod($this->imageFolderPath . $image_filename, 0755);
            fwrite($local_image_file, $raw_image_string);
            fclose($local_image_file);
    }

}

使用远程URL图像上传预览StackOverflow图像对话框
enter image description here

2 个答案:

答案 0 :(得分:1)

一种简单有效的方法是在文件上使用getimagesize。合法文件将为许多常见图像文件类型提供图像元数据阵列。 (顺便说一下,这也可用于强制执行其他约束,例如图像尺寸。)

请记住,即使合法图像也可能包含恶意代码,因为过去各种图像查看器都会出现图像数据流的安全问题。它可以添加一层安全性,以便在传送图像之前对其进行内部转换,以保护客户端。

答案 1 :(得分:0)

你可以

  • 检查响应标头,尤其是“Content-Type”标头
  • 检查文件mime类型
  • 检查实际文件签名
  • 尝试从文件中实际创建图像资源
  • 其它...