设为首页 收藏本站
查看: 1019|回复: 0

[经验分享] php判断图片是否存在的几种方法

[复制链接]

尚未签到

发表于 2017-12-29 21:38:20 | 显示全部楼层 |阅读模式
  在我们日常的开发中,经常需要用到判断图片是否存在,存在则显示,不存在则显示默认图片,那么我们用到的判断有哪些呢?今天我们就来看下几个常用的方法:
  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);
  
}
  

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


  •   最终处理的函数是 php_getimagesize_from_stream

  •   负责判断文件类型的函数是 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] =>>  
[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; //返回或者显示结果
  
}
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-429510-1-1.html 上篇帖子: php实现简单消息发送+极光推送系统 下篇帖子: php多关键字查询
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表