PHP上传文件出现文件名被截掉第一个字符的问题
最近用PHP做了一个简单的上传功能,结果出现了一个意想不到的问题。我上传的文件,在获取$_FILES的时候发现文件名的第一个字符被截掉了,因为最开始上传的一直是数字或者字母为名称的文档,也没有太在意这个问题,等到上传中文名称的文档的时候,问题来了,因为只截取了一个字符,而一个汉字是两个字符,所以,乱码出现了。而且不管是本机还是服务器,都出现同样的问题。到这时,我就不得不开始寻找原因了。
代码如下,一目了然。
文件upload.php的内容为:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> <title>上传文件</title> </head> <body> <div id="welcome"> <form method="post" action="upload2.php" enctype="multipart/form-data" > <input name="content" type="file"></input> <input type="submit"/> </form> </div> </body> </html>
submit之后post到页面upload2.php,我们再看看里面的内容:
<?php var_export($_FILES);
逻辑很简单毫无悬念对不对?但是就是出现了我上面描述的那个蛋疼的错误,具体的情况是什么样子的呢?我来描述一下。
首先我选中一个名称为“mima.txt”的文件,确定之后,打印出来的结果为:
array ( 'content' => array ( 'name' => 'ima.txt', 'type' => 'text/plain', 'tmp_name' => 'D:\\wamp\\tmp\\php322.tmp', 'error' => 0, 'size' => 379, ), )
大家可以看到,第一个字符被截掉了,“mima.txt”变成了"ima.txt"。
现在我们来看看中文的, 我选中一个名称为“新建文本文档.txt”的文件,然后上传,打印出来的结果为:
array ( 'content' => array ( 'name' => '��建 文本文档.txt', 'type' => 'text/plain', 'tmp_name' => 'D:\\wamp\\tmp\\php327.tmp', 'error' => 0, 'size' => 10, ), )
很好,乱码了。
通过我各种孜孜不倦的求助搜索引擎,求助好友以及自救之后,一个网页让我豁然开朗。
https://bugs.php.net/bug.php?id=55510
为大家节选一部分
I started going back version by version from 5.3.8 to see where the problem started, and it seems to have begun with 5.3.7, as 5.3.6 works correctly. Once again, I'm just replacing PHP builds -- I'm not modifying any else. With 5.3.6, I get back what I would expect: array(1) { ["filename"]=> array(5) { ["name"]=> string(10) "readme.txt" ["type"]=> string(10) "text/plain" ["tmp_name"]=> string(31) "C:\temp\file_upload\php594F.tmp" ["error"]=> int(0) ["size"]=> int(22) } } With 5.3.7 and 5.3.8, I get back the missing first letter: array(1) { ["filename"]=> array(5) { ["name"]=> string(10) "eadme.txt" ["type"]=> string(10) "text/plain" ["tmp_name"]=> string(31) "C:\temp\file_upload\php594F.tmp" ["error"]=> int(0) ["size"]=> int(22) } } With 5.4.beta1-dev, I'm back to getting everything that I expect: array(1) { ["filename"]=> array(5) { ["name"]=> string(10) "readme.txt" ["type"]=> string(10) "text/plain" ["tmp_name"]=> string(31) "C:\temp\file_upload\php594F.tmp" ["error"]=> int(0) ["size"]=> int(22) } }
也就是说是PHP5.3.8存在这个问题,而我检查之后发现,我本机及服务器的PHP版本都是5.8.3,双双躺枪。
两种简单的解决方案:
一.升级你的PHP版本吧。或者后退也行啊。不要用5.3.8了。
二.重命名文件之后再上传吧,我直接用的随机数加当前时间戳再加上文件拓展名。直接绕过文件名被截断的问题。当然,如果需要保存原文件名又不想修改你的PHP环境的话,那你可以放一个hidden存储你的文件名,提交过去或者hidden里面的文件名即可。