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

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; //返回或者显示结果
}

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

  1. 原生JS—实现图片循环切换的两种方法

    今天我们主要讲讲如何使用原生JS实现图片的循环切换的方法.多余的话我们就不多说了,我们一个一个开始讲吧. 1  原生JS实现图片循环切换 -- 方法一 在上栗子之前我们先简单介绍一下所用的一些知识点. ...

  2. C#判断字符串为空的几种方法和效率判断

    C#判断字符串为空的几种方法和效率判断 string定义 1.1 string str1="":会定义指针(栈),并在内存里划一块值为空的存储空间(堆),指针指向这个空间.1.2 ...

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

    下午写JS验证,有一个需求需要判断 checkbox是否被选择,查阅相关资料后,总结以下4种方法,分享给大家. <!DOCTYPE html> <html lang="en ...

  4. 获取图片base64编码的几种方法

    前文中我们聊了 Data URI 和 base64编码,稍微回顾下.base64编码 是将数据用 64 个可打印的字符进行编码的方式,任何数据底层实现都是二进制,所以都可以进行 base64编码,ba ...

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

    目录 1. 通过 URL Rewrite Module 组件 2. 通过 nginx 图片防盗链 3.自定义 HttpHandler 处理 4. 通过 MVC 自定义路由规则防盗链 5. 通过 MVC ...

  6. iOS常见用户头像的圆形图片裁剪常见的几种方法

    在开发中,基本上APP的用户头像的处理都需要把用户所上传的方形图片,处理为圆形图片.在这里就总结三种常见的处理圆形图片的方法. 1.使用位图上下文 2.使用UIView的layer进行处理 3.使用r ...

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

    css的应用十分广泛,即便用在图片的效果中也是方法多样,本文下面就介绍五种为图片添加特殊效果边框的CSS写法阴影效果 通过使用带有一些padding之的背景图来添加阴影效果. HTML <img ...

  8. 如何通过PHP判断年份是否是闰年----两种方法

    1.定义:闰年是对4取余为0,对100取余不等于0,对400取余等于0的年是闰年. 2.代码: 第一种方法:直接函数判断 $day = date('Y'); if ($day%4==0&&am ...

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

    在程序开发过程中,少不了要处理字符串,并且常常要判断字符串是否为空,通常有哪些判断方法,以及不同方法的效率又怎么样? 在 C# 中,通常有三种判断字符串是否为空的方法,下面分别探讨. 1.str.Le ...

随机推荐

  1. emacs24 颜色主题设置

    Emacs24 颜色主题设置 在Linux上写程序,永远绕不过的2个东西就是vi和emacs.emacs是早晚要接触的东西.本文就从配置颜色主题(color-theme)开始.用命令:$ sudo a ...

  2. Android反编译获取资源文件-android学习之旅(69)

    有时候你看到一些很好看的布局,会考虑别人怎么实现的,回想参考一下,那么这时候反编译一下是很必要的. 要用到的工具apktool.bat和aapt.exe和apktool.jar(要最新版本) 下载前两 ...

  3. HTML移动开发参考

    小强的HTML5移动开发之路 http://blog.csdn.net/dawanganban/article/details/17591373 其他: http://blog.csdn.net/gf ...

  4. 【翻译】在Ext JS应用程序中使用自定义图标

    原文:Using Custom Icons in Your Ext JS App 作者:Lee BoonstraLee is a technical trainer at Sencha. She's ...

  5. 我所理解的Android 启动模式

    首先,这是从 一个开源网站转载的,觉得写得不错,对我们之前理解的activity的启动模式是一个新的理解方式,并给出实际的应用场景. 任务栈是什么 任务栈Task,是一种用来放置Activity实例的 ...

  6. 手持机设备公司(WINCE/ANDROID/LINUX)

    1.深圳扬创科技有限公司网址: http://www.yctek.com/ 2.无锡盈达聚力科技有限公司 点击打开链接 3.上海鲲博通信技术有限公司(主要为用WINCE开发导航产品) 点击打开链接 4 ...

  7. Tomcat configuration DataSource

    1. configuration MySql Connection DataSource 原理介绍 java 调用 Tomcat 中的 ConnectionPool 通过Context 中去查找  j ...

  8. Xcode出现may cause a leak的解决

    比如如下代码: -(void)performSelector:(SEL)selector onNode:(CCNode *)node withObject:(id)object recursive:( ...

  9. gtk+程序在关闭主窗口时的事件流

    当鼠标单击gtk+窗口的关闭按钮时,程序首先接收到delete_event,当该事件处理函数返回TRUE表示事件已处理禁止进一步传播,从而取消关闭操作:当返回FALSE时,事件消息进一步向上传播,此时 ...

  10. Struts2(XWork)中的Container 一

    本文是<<struts2 技术内幕>>的学习笔记 在进行面向对象编程的时候,我们不可避免地要使用继承实现等等java提供的语法支持.但是复杂的对象关系也为对象生命周期的管理带来 ...