PHP 文件上传错误 (UPLOAD_ERR_PARTIAL) / $_FILES 为空或为空"tmp_name"
PHP file upload error (UPLOAD_ERR_PARTIAL) / $_FILES is null or has empty"tmp_name"
我有一个很常见的问题,我花了几个小时阅读了一些相关内容,但我没能解决它,我快要疯了...
上下文
我有一个网站用户可以将图片上传到我的服务器(通常情况下来自iOS / Safari 浏览器)。上传表单的页面是 this one.
后端是用PHP制作的(无框架)。前端是 HTML / Javascript。这是我在 2010 年创建的一个非常古老的网站,所以这不是 "super sexy"! :-)
我做了日志来监控上传结果,我看到 大约 30% 的用户上传失败...我想这不常见!
这些错误来自 2 个来源(尝试多次上传的同一个用户可能混合了这 2 个来源):
$_FILES['myFormFieldName']
是 NULL
$_FILES['myFormFieldName']
不是 NULL 但 $_FILES['myFormFieldName']['error']
是 3 (UPLOAD_ERR_PARTIAL
) 与 $_FILES['xxx']['tmp_name']
和 $_FILES['xx']['type']
空并且 $_FILES['xxx']['size']
是“0”
这些错误似乎不是确定性的...
- 当我自己测试时(使用与上传有问题的用户相同的图片)我没有问题
- 我在我的日志中看到一些用户总是抱怨上传有问题,但其他人则没有。
- 我还看到一些遇到问题的用户在多次重试后成功上传了他们的文件
- 我联系过一位遇到问题的用户,他说他在尝试上传图片时遇到来自 Safari 的
Safari cannot open the page because network connection was lost
错误页面(无论何时他处于 WiFi 或移动 3G/4G 数据中)
代码
HTML 格式上传文件
(限制用户从客户端上传到35M)
<ul class="pageitem">
<form name="empty-custom-native"
enctype="multipart/form-data"
action="/upload.php?method=nativeUpload"
method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="36700160" />
<li class="button" >
<input type="file" name="iosImageFILE" id="iosImageFILE"/>
</li>
</form>
<li class="button directUrlButton" onclick="javascript:onclickNativeUploadForm();">
<input type="button" value="Upload" />
</li>
</ul>
Javascript 被 HTML 调用
(用于提交表单前检查文件输入是否为空)
function onclickNativeUploadForm(){
if( document.getElementById('iosImageFILE').value=="" ){
alert("Please choose an image FIRST !");
} else{
showPleaseWait();
setTimeout(submitNativeUploadForm, 2000);
}
}
function submitNativeUploadForm(){
document.forms['empty-custom-native'].submit();
}
PHP 管理文件上传(提取)的代码
<?php
if( isset($_FILES['iosImageFILE']) && !empty($_FILES['iosImageFILE']) ){
$uploadStatus = $_FILES['iosImageFILE']['error'];
if( $uploadStatus==0 ){
// Copy source file to temp file
if( !move_uploaded_file($_FILES['iosImageFILE']['tmp_name'], $_SERVER['DOCUMENT_ROOT']."/".$userImageTemp) ) {
throw new Exception("fileUploadCopy");
}
} else{
if( $uploadStatus==1 ){ throw new Exception("fileUploadIniSize"); }
else if( $uploadStatus==2 ){ throw new Exception("fileUploadFormSize"); }
else if( $uploadStatus==3 ){ throw new Exception("fileUploadPartial"); } // THIS ERROR ...
else if( $uploadStatus==4 ){ throw new Exception("fileUploadNoFile"); }
else if( $uploadStatus==6 ){ throw new Exception("fileUploadNoTmpDir"); }
else if( $uploadStatus==7 ){ throw new Exception("fileUploadCantWrite"); }
else if( $uploadStatus==8 ){ throw new Exception("fileUploadExtension"); }
else{
throw new Exception("fileUploadSystem");
}
}
} else{
throw new Exception("fileUploadUpload"); // ... OR THIS ERROR
}
// If anything was OK, we continue here with the uploaded file copied in our working dir to do some stuff with it...
?>
所以在我的例子中,我有 fileUploadUpload
或 fileUploadPartial
个例外。
调查
服务器端(php.ini 配置)
我检查了处理文件上传的 PHP 环境变量(使用 ini_get
命令)以检查我没有超过最大文件大小或最大上传数量。
一切似乎都很好,我有相当大的限制,post_max_size
比 upload_max_filesize
大。 upload_tmp_dir
是空的 我猜这意味着我使用默认系统 /tmp
dir?
如果您发现问题或需要检查的其他事项,请告诉我。
注意:我无权访问 php.ini
,但这些值由我的托管服务提供商确定(我在共享托管上)。
file_uploads : '1'
upload_tmp_dir : ''
upload_max_filesize : '128M'
max_file_uploads : '20'
post_max_size : '130M'
max_execution_time : '300'
客户端(HTML/JS代码)
MAX_FILE_SIZE
小于我的 PHP 服务器允许的最大文件大小。
我按预期使用了 enctype="multipart/form-data"
和 method="post"
。
我不做AJAX文件上传,只是用Javascript在用JS提交表单之前检查输入文件是否为空。
服务器端(PHP代码)
当我调试 $_FILES['iosImageFILE']
的内容时,我得到了 fileUploadPartial
错误(对于 fileUploadUpload
错误,这是 null)。
iosImageFILE = {"name":"DD292A1C-9CBF-4843-9E1C-7C815593C67A.png","type":"","tmp_name":"","error":3,"size":0}
服务器端(文件系统)
我试图检查 /tmp
目录,上传的文件应该在该目录中,但我无权访问它。我想检查它不是 "full of old tmp files" 但我猜不是。
事实上,我制作了一个 PHP 脚本来使用 var_export(scandir('/tmp'))
扫描其内容,但我只看到一些 sess_xxxxx
会话文件(大约 7000 个文件)。
代码升级
我已经将我的网站升级并增强为 https(之前是不安全的 http)并将 PHP 版本从 5.6 升级到 7.0)。文件上传问题没有任何改变。
防火墙 ?!?
我可能怀疑我的托管服务提供商存在防火墙问题(我读到它可能会阻止有关文件上传的某些事情...)。
但是他们说我的主机上没有激活防火墙...
结论
我真的不知道接下来要检查什么来调查并找到这个问题。
请注意,几乎所有上传文件的人都来自 iOS / Safari 浏览器。我不知道其他 OS 或浏览器是否会出现同样的问题...
我是一名前端 Web 开发人员,我必须承认我对这类问题感到不舒服。
感谢任何帮助!
故事的结尾:正如所怀疑的那样,这是我的托管服务提供商的问题(他们花了 1 个月的时间来解决...)
我没能得到更多的细节,除了它是一个 "Apache configuration problem",并且它有一个 link 和负载平衡...
我有一个很常见的问题,我花了几个小时阅读了一些相关内容,但我没能解决它,我快要疯了...
上下文
我有一个网站用户可以将图片上传到我的服务器(通常情况下来自iOS / Safari 浏览器)。上传表单的页面是 this one.
后端是用PHP制作的(无框架)。前端是 HTML / Javascript。这是我在 2010 年创建的一个非常古老的网站,所以这不是 "super sexy"! :-)
我做了日志来监控上传结果,我看到 大约 30% 的用户上传失败...我想这不常见!
这些错误来自 2 个来源(尝试多次上传的同一个用户可能混合了这 2 个来源):
$_FILES['myFormFieldName']
是 NULL$_FILES['myFormFieldName']
不是 NULL 但$_FILES['myFormFieldName']['error']
是 3 (UPLOAD_ERR_PARTIAL
) 与$_FILES['xxx']['tmp_name']
和$_FILES['xx']['type']
空并且$_FILES['xxx']['size']
是“0”
这些错误似乎不是确定性的...
- 当我自己测试时(使用与上传有问题的用户相同的图片)我没有问题
- 我在我的日志中看到一些用户总是抱怨上传有问题,但其他人则没有。
- 我还看到一些遇到问题的用户在多次重试后成功上传了他们的文件
- 我联系过一位遇到问题的用户,他说他在尝试上传图片时遇到来自 Safari 的
Safari cannot open the page because network connection was lost
错误页面(无论何时他处于 WiFi 或移动 3G/4G 数据中)
代码
HTML 格式上传文件 (限制用户从客户端上传到35M)
<ul class="pageitem">
<form name="empty-custom-native"
enctype="multipart/form-data"
action="/upload.php?method=nativeUpload"
method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="36700160" />
<li class="button" >
<input type="file" name="iosImageFILE" id="iosImageFILE"/>
</li>
</form>
<li class="button directUrlButton" onclick="javascript:onclickNativeUploadForm();">
<input type="button" value="Upload" />
</li>
</ul>
Javascript 被 HTML 调用 (用于提交表单前检查文件输入是否为空)
function onclickNativeUploadForm(){
if( document.getElementById('iosImageFILE').value=="" ){
alert("Please choose an image FIRST !");
} else{
showPleaseWait();
setTimeout(submitNativeUploadForm, 2000);
}
}
function submitNativeUploadForm(){
document.forms['empty-custom-native'].submit();
}
PHP 管理文件上传(提取)的代码
<?php
if( isset($_FILES['iosImageFILE']) && !empty($_FILES['iosImageFILE']) ){
$uploadStatus = $_FILES['iosImageFILE']['error'];
if( $uploadStatus==0 ){
// Copy source file to temp file
if( !move_uploaded_file($_FILES['iosImageFILE']['tmp_name'], $_SERVER['DOCUMENT_ROOT']."/".$userImageTemp) ) {
throw new Exception("fileUploadCopy");
}
} else{
if( $uploadStatus==1 ){ throw new Exception("fileUploadIniSize"); }
else if( $uploadStatus==2 ){ throw new Exception("fileUploadFormSize"); }
else if( $uploadStatus==3 ){ throw new Exception("fileUploadPartial"); } // THIS ERROR ...
else if( $uploadStatus==4 ){ throw new Exception("fileUploadNoFile"); }
else if( $uploadStatus==6 ){ throw new Exception("fileUploadNoTmpDir"); }
else if( $uploadStatus==7 ){ throw new Exception("fileUploadCantWrite"); }
else if( $uploadStatus==8 ){ throw new Exception("fileUploadExtension"); }
else{
throw new Exception("fileUploadSystem");
}
}
} else{
throw new Exception("fileUploadUpload"); // ... OR THIS ERROR
}
// If anything was OK, we continue here with the uploaded file copied in our working dir to do some stuff with it...
?>
所以在我的例子中,我有 fileUploadUpload
或 fileUploadPartial
个例外。
调查
服务器端(php.ini 配置)
我检查了处理文件上传的 PHP 环境变量(使用 ini_get
命令)以检查我没有超过最大文件大小或最大上传数量。
一切似乎都很好,我有相当大的限制,post_max_size
比 upload_max_filesize
大。 upload_tmp_dir
是空的 我猜这意味着我使用默认系统 /tmp
dir?
如果您发现问题或需要检查的其他事项,请告诉我。
注意:我无权访问 php.ini
,但这些值由我的托管服务提供商确定(我在共享托管上)。
file_uploads : '1'
upload_tmp_dir : ''
upload_max_filesize : '128M'
max_file_uploads : '20'
post_max_size : '130M'
max_execution_time : '300'
客户端(HTML/JS代码)
MAX_FILE_SIZE
小于我的 PHP 服务器允许的最大文件大小。
我按预期使用了 enctype="multipart/form-data"
和 method="post"
。
我不做AJAX文件上传,只是用Javascript在用JS提交表单之前检查输入文件是否为空。
服务器端(PHP代码)
当我调试 $_FILES['iosImageFILE']
的内容时,我得到了 fileUploadPartial
错误(对于 fileUploadUpload
错误,这是 null)。
iosImageFILE = {"name":"DD292A1C-9CBF-4843-9E1C-7C815593C67A.png","type":"","tmp_name":"","error":3,"size":0}
服务器端(文件系统)
我试图检查 /tmp
目录,上传的文件应该在该目录中,但我无权访问它。我想检查它不是 "full of old tmp files" 但我猜不是。
事实上,我制作了一个 PHP 脚本来使用 var_export(scandir('/tmp'))
扫描其内容,但我只看到一些 sess_xxxxx
会话文件(大约 7000 个文件)。
代码升级
我已经将我的网站升级并增强为 https(之前是不安全的 http)并将 PHP 版本从 5.6 升级到 7.0)。文件上传问题没有任何改变。
防火墙 ?!?
我可能怀疑我的托管服务提供商存在防火墙问题(我读到它可能会阻止有关文件上传的某些事情...)。 但是他们说我的主机上没有激活防火墙...
结论
我真的不知道接下来要检查什么来调查并找到这个问题。
请注意,几乎所有上传文件的人都来自 iOS / Safari 浏览器。我不知道其他 OS 或浏览器是否会出现同样的问题...
我是一名前端 Web 开发人员,我必须承认我对这类问题感到不舒服。
感谢任何帮助!
故事的结尾:正如所怀疑的那样,这是我的托管服务提供商的问题(他们花了 1 个月的时间来解决...)
我没能得到更多的细节,除了它是一个 "Apache configuration problem",并且它有一个 link 和负载平衡...