文件存到aws的S3后, 调用getimagesize失败分析
一、问题
将图片在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;
文件存到aws的S3后, 调用getimagesize失败分析的更多相关文章
- 上传文件到aws的s3存储
只要有aws-cli客户端就可以上传文件到aws的S3存储.可以在任意机器上.这里以centos为例. 1.安装python.pip. # yum install -y python python-p ...
- AWS系列-S3实现文件服务页面展示
最近由于业务需求,对于备份的数据存放到S3上面,并需要页面展示.而且还能下载. 把这个桶里面的对象,都在某个静态页面展示.并且 我可以把这个对象下载下来. 首页内容就是 桶里面的对象. 并且可以随时查 ...
- bootstrap的datepicker在选择日期后调用某个方法
bootstrap的datepicker在选择日期后调用某个方法 2016-11-08 15:14 1311人阅读 评论(0) 收藏 举报 首先感谢网易LOFTER博主Ivy的博客,我才顿悟了问题所在 ...
- python调用另一个文件中的代码,pycharm环境下:同文件夹下文件(.py)之间的调用,出现红线问题
如何调用另一个python文件中的代码无论我们选择用何种语言进行程序设计时,都不可能只有一个文件(除了“hello world”),通常情况下,我们都需要在一个文件中调用另外一个文件的函数呀数据等等, ...
- 痞子衡嵌入式:JLink Script文件基础及其在IAR下调用方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是JLink Script文件基础及其在IAR下调用方法. JLink可以说是MCU开发者最熟悉的调试工具了,相比于其他调试器(比如DAP ...
- 为什么需要在TypedArray后调用recycle
当我们没有在使用TypedArray后调用recycle,编译器会提示“This TypedArray should be recycled after use with #recycle()”. 官 ...
- shell 脚本文件Windows传到Linux后编码问题
shell 脚本文件Windows传到Linux后编码问题 下面这个标红的位置出现,是由于脚本从Windows机器上直接传到linux文件格式不对导致的. cat -v a.sh help^M exi ...
- java笔试题: ——将e:/source文件夹下的文件打个zip包后拷贝到f:/文件夹下面
将e:/source文件夹下的文件打个zip包后拷贝到f:/文件夹下面 import java.io.*; import java.util.zip.ZipEntry; import java.uti ...
- Java基础知识强化之IO流笔记52:IO流练习之 把一个文件中的字符串排序后再写入另一个文件案例
1. 把一个文件中的字符串排序后再写入另一个文件 已知s.txt文件中有这样的一个字符串:"hcexfgijkamdnoqrzstuvwybpl" 请编写程序读取数据内容,把数据排 ...
随机推荐
- linux驱动之内核多线程(二)
本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545702.html 内核多线程是在项目中使用到,自己也不熟悉,遇到一个很囧的问题, ...
- JavaScript学习系列博客_35_JavaScript 正则表达式的使用
正则表达式的使用 先说RegExp对象的一个方法 test() - 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,如果符合则返回true,否则返回false. 1.用正则表达式来检查一个 ...
- 封装Vue Element的form表单组件
前两天封装了一个基于vue和Element的table表格组件,阅读的人还是很多的,看来大家都是很认同组件化.高复用这种开发模式的,毕竟开发效率高,代码优雅,逼格高嘛.虽然这两天我的心情很糟糕,就像& ...
- springMVC入门(五)------统一异常处理
简介 系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过异常捕获获取异常信息,后者需通过规范代码.提高代码路绑定减少运行时异常的发生 异常处理思路:无论dao层.ser ...
- Eclipse导入项目后JSP页面出现报红
Multiple annotations found at this line:- javax.servlet.jsp.JspException cannot be resolved to a typ ...
- HTTP基本原理-Network各列标签的含义
第一列 Name:请求的名称,一般会将URL的最后一部分内容当作名称 第二列 Status:响应的状态码,显示为 200,则代表相应是正常的.通过状态码,我们可以判断发送了请求之后是否得到了正常的相应 ...
- SVG的引入历程
直接引入编辑器会报错 Google: typescript svg cannot find module找到 这个网址 我放到了 shims-vue.d.ts 里面 declare module &q ...
- 通过DatabaseMetaData数据库元信息类,获取特定数据库的元信息
数据库版本:mysql8.0.18 ide:idea 2019.3 可以看到代码中连接的数据库为course_select,是一个学生的选课系统的数据库 然后通过DatabaseMetaData的ge ...
- RabbitMQ系列随笔——介绍及安装
一.RabbitMQ介绍 RabbitMQ是由erlang开发的AMQP(Advanced Message Queuing Protocol)的开源实现.他是高级消息队列协议,是应用层协议的一个开放标 ...
- 前端测试框架 Jest
前端测试工具一览 前端测试工具也和前端的框架一样纷繁复杂,其中常见的测试工具,大致可分为测试框架.断言库.测试覆盖率工具等几类.在正式开始本文之前,我们先来大致了解下它们: 测试框架 测试框架的作用是 ...