一、问题

将图片在windows下用图片查看器修改后,上传到s3中,调用getimagesize获取图片信息总是返回false,其它图片正常;

代码如下:

$fileName = 's3://sdk1/20150317/174290_1_1428371.JPG';
$size = getimagesize($fileName);
var_dump($size);

以上代码总是输出false。

即部分图片调用成功,部分调用失败;

图片上传后,可以对上传的临时文件调用getimagesize获取图片信息;

PHP的版本为5.6.2

二、分析过程:

1、准备知识

先说下PHP中对流的封装,通过函数stream_wrapper_register,我们可以注册一个新的URL,像上面的s3开头的文件;

AWS封装了一套对这类文件的操作,包括读、写、定位、打开目录等函数,这方面资料可以看下PHP文档,AWS的封装代码可以看下AWS的PHP的SDK。

通过追代码,发现对S3文件的请求最终会转成一个HTTPS的请求,https://sdk1.s3.cn-north-1.amazonaws.com.cn/20150317/174290_1_1428371.JPG

2、代码追踪

看下getimagesize函数的实现,

这个是调用php_getimagesize_from_any来实现的,

重要函数为php_getimagesize_from_stream,看下这个函数:

会先读取文件的前三字节,获取文件类型,具体可以看下php_getimagetype函数;

如果是jpg类型的图片,会调用php_handle_jpeg函数,

其中函数php_next_marker会读取文件的二进制流当前字节,根据不同字节作不同的处理,

如果当前字节为宏M_APP0至M_APP15,即0xe0到0xef,表示是APP或变量;

出问题的图片当前是variable,看下php_skip_variables函数

如果当前是一个变量,则要跳过这个变量,读取下一块信息,这里调用php_stream_seek来进行seek操作,

看两块关键代码,上面一段表示seek的位置在已经读取的范围内;

下一块表示这个流不支持seek操作,返回失败;

在我们的例子里,上面表示正常情况,下面表示失败情况的;

我们再回到s3的seek操作的封装:

return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false;

即不支持seek,所以失败了;

明白了吗,原理就是getimagesize为从文件的二进制流中读取图片信息,而这个信息是文件的位置是不固定的,必须一块一块的解析,正常的图片的相关信息是在文件前8192个字节之内,而

出错的是8192之外的,如果在8192之外的,需要先将文件流定位到相应位置,再从该位置读取信息,而s3开头的路径不支持seek操作,导致PHP读不文件元信息。

三、改进方法

改写Stream::seek方法

public function seek($offset, $whence = SEEK_SET)

{

if ($whence == SEEK_SET)

{

$pos = $this->ftell();

if ($pos < $offset)

{

$this->read($offset - $pos);

}

}

return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false;

最新文章

  1. solr suggest智能提示配置
  2. D3树状图异步按需加载数据
  3. python课程第四周重点记录
  4. 方法过滤器,分布式缓存 Memcached实现Session解决方案
  5. “requireJs前传”之为什么要用前端模块化?
  6. 京东电话面试——PHP开发
  7. uva 12171 hdu 1771 Sculpture
  8. Java学习之异常处理
  9. Web静态和动态项目委托代理基于面向方面编程AOP
  10. 基于Debian系统配置Nginx环境的Node.js应用教程
  11. caffe源码 卷积层
  12. C++内存机制中内存溢出、内存泄露、内存越界和栈溢出的区别和联系
  13. 【机器学习】--Kmeans从初识到应用
  14. spring boot常见问题
  15. JDK8 新特性流式数据处理
  16. 基于socket构造c/s 架构软件
  17. Java 分布式和集中式理解
  18. 我的阿里、腾讯暑期实习Offer经历
  19. Linux系列——安装双系统Ubuntu
  20. &lt;Effective C++&gt;读书摘要--Inheritance and Object-Oriented Design&lt;二&gt;

热门文章

  1. C++生成元
  2. Linux C++实现一服务器与多客户端之间的通信
  3. Nginx学习简记_part2
  4. 技术揭秘:华为云DLI背后的核心计算引擎
  5. Golang | 简介channel常见用法,完成goroutin通信
  6. 详细了解JS Map,它和传统对象有什么区别?
  7. unity 模板测试 详解
  8. 【Unity C#编程】自定义数据
  9. Forward Rendering VS Deferred Rendering
  10. 良许被百万大V安排得服服帖帖,还跟美女小姐姐合影了……