php判断图片是否存在的几种方法

在我们日常的开发中,经常需要用到判断图片是否存在,存在则显示,不存在则显示默认图片,那么我们用到的判断有哪些呢?今天我们就来看下几个常用的方法:

1、getimagesize()函数

getimagesize 函数并不属于 GD 扩展的部分,标准安装的 PHP 都可以使用这个函数。可以先看看这个函数的文档描述:http://php.net/manual/zh/function.getimagesize.php

如果指定的文件如果不是有效的图像,会返回 false,返回数据中也有表示文档类型的字段。如果不用来获取文件的大小而是使用它来判断上传文件是否是图片文件,看起来似乎是个很不错的方案,当然这需要屏蔽掉可能产生的警告,比如代码这样写:

<?php
$filesize = @getimagesize(‘/path/to/image.png‘);
if ($filesize) {
    do_upload();
}

# 另外需要注意的是,你不可以像下面这样写:
# if ($filesize[2] == 0)
# 因为 $filesize[2] 可能是 1 到 16 之间的整数,但却绝对不对是0。

但是如果你仅仅是做了这样的验证,那么很不幸,你成功的在代码里种下了一个 webshell 的隐患。

要分析这个问题,我们先来看一下这个函数的原型:

static void php_getimagesize_from_stream(php_stream *stream, zval **info, INTERNAL_FUNCTION_PARAMETERS)
{
    ...
    itype = php_getimagetype(stream, NULL TSRMLS_CC);
    switch( itype) {
        ...
    }
    ...
}

static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) {
    ...
    php_getimagesize_from_stream(stream, info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
    php_stream_close(stream);
}

PHP_FUNCTION(getimagesize)
{
    php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}

限于篇幅上面隐藏了一些细节,现在从上面的代码中我们知道两件事情就够了:

  1. 最终处理的函数是 php_getimagesize_from_stream
  2. 负责判断文件类型的函数是 php_getimagetype

接下来看一下 php_getimagetype 的实现:

PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
{
    ...
    if (!memcmp(filetype, php_sig_gif, 3)) {
        return IMAGE_FILETYPE_GIF;
    } else if (!memcmp(filetype, php_sig_jpg, 3)) {
        return IMAGE_FILETYPE_JPEG;
    } else if (!memcmp(filetype, php_sig_png, 3)) {
        ...
    }
}

去掉了一些细节,php_sig_gif php_sig_png 等是在文件头部定义的:

PHPAPI const char php_sig_gif[3] = {‘G‘, ‘I‘, ‘F‘};
...
PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
                                    (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};

可以看出来 image type 是根据文件流的前几个字节(文件头)来判断的。那么既然如此,我们可不可以构造一个特殊的 PHP 文件来绕过这个判断呢?不如来尝试一下。

找一个十六进制编辑器来写一个的 PHP 语句,比如:

<?php phpinfo(); ?>

这几个字符的十六进制编码(UTF-8)是这样的:

3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E

我们构造一下,把 PNG 文件的头字节加在前面变成这样的:

8950 4E47 0D0A 1A0A 3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E

最后保存成 .php 后缀的文件(注意上面是文件的十六进制值),比如 test.php。执行一下 php test.php 你会发现完全可以执行成功。那么能用 getimagesize 读取它的文件信息吗?新建一个文件写入代码试一下:

<?php
print_r(getimagesize(‘test.php‘));

执行结果:

Array
(
    [0] => 1885957734
    [1] => 1864902971
    [2] => 3
    [3] => width="1885957734" height="1864902971"
    [bits] => 32
    [mime] => image/png
)

成功读取出来,并且文件也被正常识别为 PNG 文件,虽然宽和高的值都大的有点离谱。

现在你应该明白为什么上文说这里留下了一个 webshell 的隐患的吧。如果这里只有这样的上传判断,而且上传之后的文件是可以访问的,就可以通过这个入口注入任意代码执行了。

那么为什么上面的文件可以 PHP 是可以正常执行的呢?用 token_get_all 函数来看一下这个文件:

<?php
print_r(token_get_all(file_get_contents(‘test.php‘)));

如果显示正常的话你能看到输出数组的第一个元素的解析器代号是 312,通过 token_name 获取到的名称会是 T_INLINE_HTML,也就是说文件头部的信息被当成正常的内嵌的 HTML 代码被忽略掉了。

至于为什么会有一个大的离谱的宽和高,看一下 php_handle_png 函数的实现就能知道,这些信息也是通过读取特定的文件头的位来获取的。

所以,对于正常的图片文件,getimagesize 完全可以胜任,但是对于一些有心构造的文件结构却不行。

在处理用户上传的文件时,先简单粗暴的判断文件扩展名并对文件名做一下处理,保证在服务器上不是 php 文件都不能直接执行也是一种有效的方式。然后可以使用 getimagesize 做一些辅助处理。

2、file_exists()函数

file_exists() 函数检查文件或目录是否存在。

如果指定的文件或目录存在则返回 true,否则返回 false。

eg: file_exists(path);其中的参数path必须是路径,不能是url不然会一直返回false;

注意:

1、文件的任何上级目录,只有写权限时报文件不存在;

2、文件的任何上级目录,只有读权限时也报文件不存在;

3、而当所有上级目录都有执行权限的时候,报文件是存在的,一切都正常。

说明file_exists()在判断文件是否存在的时候是递归判断每个目录是不是有执行权限。

3、file_get_contents()函数

file_get_contents — 将整个文件读入一个字符串

如果失败,file_get_contents() 将返回 FALSE

果要打开有特殊字符的 URL (比如说有空格),就需要使用 urlencode() 进行 URL 编码。

但是此函数如果请求比较多,文件比较大,那么可能会超时未响应,导致服务器挂掉

要设置file_get_contents函数的超时时间,可以用resource $context的timeout参数,代码如下:

 $opts = array(
   ‘http‘=>array(
     ‘method‘=>"GET",
     ‘timeout‘=>10,
   )
 );
 $context = stream_context_create($opts);
 $html =file_get_contents(‘http://www.example.com‘, false, $context);
echo $html;

4、curl方法

实现的功能:

1、实现远程获取和采集内容

2、实现PHP 网页版的FTP上传下载

3、实现模拟登陆:去一个邮件系统,curl可以模拟cookies

4、实现接口对接(API),数据传输等:通过一个平台发送短信啊,抓取和传递所传输的信息。

5、实现模拟Cookie等:登陆的状态下才可以操作一些属性。

如何使用CURL功能

默认情况加PHP是不支持CURL的,需要在php.ini中开启该功能

;extension=php_curl.dll前面的分号去掉

1  整个操作过程中第一步是用cur_init()函数进行初始化

$curl = curl_init(‘http://www.cnblogs.com/imnzq/‘)

2.用curl_setopt()函数进行设置选项。

3.设置后,进行执行事务 curl_exec($curl);

4 最后关闭curl_close();

兼容get和post方法的curl;

function curl($url, $type = ‘get‘, $post_data = null, $second = 30)
{
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, false);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    if (‘post‘ == $type) {
        curl_setopt($ch, CURLOPT_POST, 1); //开启POST
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); //POST数据
    }
    $output = curl_exec($ch);
    curl_close($ch);
    return $output; //返回或者显示结果
}
时间: 2024-09-30 23:35:38

php判断图片是否存在的几种方法的相关文章

jQuery 判断checkbox是否被选中 4种方法

下午写JS验证,有一个需求需要判断 checkbox是否被选择,查阅相关资料后,总结以下4种方法,分享给大家. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jQuery 判断checkbox是否被选中 4种方法</title> <script src="jquery-1.8.3.min

【代码备忘】VC判断自己窗口的另一种方法

欢迎加入我们的QQ群,无论你是否工作,学生,只要有c / vc / c++ 编程经验,就来吧!158427611 FindWindow就不说了,这说 的是另一种:GetProp 代码也差不多: 查询... HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (::IsWindow(hWndPrevious)) { if (::GetProp(hWndPrevious, _FLAG)) { if (::IsI

asp.net MVC 网站图片防盗链的几种方法

目录 1. 通过 URL Rewrite Module 组件 2. 通过 nginx 图片防盗链 3.自定义 HttpHandler 处理 4. 通过 MVC 自定义路由规则防盗链 5. 通过 MVC 自定义 RouteHandler 防盗链 6. 通过 HttpModModule 防盗链 7. 涉及知识点,相关资源 自己网站上的图片被别的网站盗用是一件很令人厌恶的事情,下面是处理图片盗链的几种方法. 在这里先交代一下环境,我用的是 MVC4 ,IIS7 应用程序池为集成模式,以下配置都是基于此

C# 判断字符串为空的4种方法及效率

在程序开发过程中,少不了要处理字符串,并且常常要判断字符串是否为空,通常有哪些判断方法,以及不同方法的效率又怎么样? 在 C# 中,通常有三种判断字符串是否为空的方法,下面分别探讨. 1.str.Length == 0 使用 str.Length == 0,在三种方法中效率是最高的,但容易产生异常.当字符串为空的时候就会产生异常,如 string str; 或者 string str = null; if(str.Length == 0) //产生异常 此时,就会产生对象不能为空的异常. 如果事

使用CSS为图片添加边框的几种方法

css的应用十分广泛,即便用在图片的效果中也是方法多样,本文下面就介绍五种为图片添加特殊效果边框的CSS写法阴影效果 通过使用带有一些padding之的背景图来添加阴影效果. HTML <img class=”shadow” src=”sample.jpg” alt=”" /> CSS img.shadow { background: url(shadow-1000×1000.gif) no-repeat right bottom; padding: 5px 10px 10px 5p

让网页图片变灰色的三种方法

我一直喜欢灰度图像因为我认为他们看起来更有艺术感.很多图片编辑如Photoshop很容易把你的彩色图像变成灰度.甚至有选择调整颜色深度和色调.不幸的是,这样的效果想做在网络上并不容易,因为浏览器有差异. 1.CSS Filter 使用CSS过滤器属性可能是最简单的方法把图像变成灰度.以往,IE浏览器有一个专有的CSS属性称为过滤应用自定义效果包括灰度. 现在,过滤器属性是CSS3规范的一部分,并支持在一些浏览器,Firefox.Chrome和Safari.以前,我们也提到Webkit过滤器,它不

C# 判断字符串为空有哪几种方法

Length法:bool isEmpty = (str.Length == 0);Empty法:bool isEmpty = (str == String.Empty);General法:bool isEmpty = (str == ""); 2.深入内部机制: 要深入探讨其内部机制,需要查看.Net的源代码,同样有三种方法供参考: Rotor法:一个不错的选择就是微软的Rotor,这是微软的一个源代码共享项目. Mono法:另一个不错的选择当然就是真正的开源项目Mono啦! Refl

Python 判断文件是否存在的三种方法

通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做任何操作之前,先判断文件是否存在. 这里将介绍三种判断文件或文件夹是否存在的方法,分别使用os模块.Try语句.pathlib模块. 1.使用os模块 os模块中的os.path.exists()方法用于检验文件是否存在. 判断文件是否存在 import os #如果存在返回True >>>os.path.exists('test_file.txt') >>>True #如果不

Python判断文件是否存在的三种方法【转】

转:http://www.cnblogs.com/jhao/p/7243043.html 通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做任何操作之前,先判断文件是否存在. 这里将介绍三种判断文件或文件夹是否存在的方法,分别使用os模块.Try语句.pathlib模块. 1.使用os模块 os模块中的os.path.exists()方法用于检验文件是否存在. 判断文件是否存在 import os os.path.exists(test_file.tx