PHP图片上传异常:文件路径无效但文件实际存在
解决「文件名/路径无效」与「Invalid file format」问题
先看你的错误栈,核心问题是finfo::file()调用时传入了空的临时文件路径,这才导致后续抛出「Invalid file format」异常——不是真的文件格式有问题,而是上传流程中出现了未被捕获的错误,导致代码错误地走到了格式校验步骤。我们一步步来修复:
1. 补全上传错误的判断逻辑
你的switch语句只处理了3种上传错误,但PHP的文件上传错误码还有其他场景(比如文件超过表单设定大小、临时目录不可写等)。当这些未被处理的错误发生时,代码会继续往下执行,但此时$_FILES['fileToUpload']['tmp_name']是空的,直接触发finfo->file()的警告。
把switch部分修改成下面这样,覆盖所有上传错误场景:
switch ($_FILES['fileToUpload']['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_NO_FILE: throw new RuntimeException('No file sent.'); case UPLOAD_ERR_INI_SIZE: throw new RuntimeException('File exceeds upload_max_filesize directive in php.ini.'); case UPLOAD_ERR_FORM_SIZE: throw new RuntimeException('File exceeds MAX_FILE_SIZE directive that was specified in the HTML form.'); case UPLOAD_ERR_PARTIAL: throw new RuntimeException('File was only partially uploaded.'); case UPLOAD_ERR_NO_TMP_DIR: throw new RuntimeException('Missing a temporary folder.'); case UPLOAD_ERR_CANT_WRITE: throw new RuntimeException('Failed to write file to disk.'); case UPLOAD_ERR_EXTENSION: throw new RuntimeException('File upload stopped by extension.'); default: throw new RuntimeException('Unknown upload error.'); }
这样只要上传过程中出现任何错误,都会提前抛出对应异常,不会走到后面的格式校验步骤。
2. 新增临时文件存在性校验
保险起见,在调用finfo->file()之前,先确认临时文件确实存在,避免意外情况导致路径无效:
$tmpFilePath = $_FILES['fileToUpload']['tmp_name']; if (!file_exists($tmpFilePath) || !is_file($tmpFilePath)) { throw new RuntimeException('Temporary upload file is missing.'); } $finfo = new finfo(FILEINFO_MIME_TYPE); if (false === $ext = array_search( $finfo->file($tmpFilePath), array( 'jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', ), true )) { throw new RuntimeException('Invalid file format.'); }
3. 确认uploads目录权限
虽然当前错误不是移动文件导致,但提前确保./uploads目录存在且PHP有写入权限:
- 在项目根目录手动创建
uploads文件夹 - 给它设置755权限(WAMP环境下确保Apache进程能写入)
修改后的完整PHP代码示例
<?php header('Content-Type: text/plain; charset=utf-8'); function StartPy(){ $command_exec = escapeshellcmd('A:\OCR EXPERIMENT\main.py'); $str_output = shell_exec($command_exec); echo $str_output; } try { // Undefined | Multiple Files | $_FILES Corruption Attack // If this request falls under any of them, treat it invalid. if ( !isset($_FILES['fileToUpload']['error']) || is_array($_FILES['fileToUpload']['error']) ) { throw new RuntimeException('Invalid parameters.'); } // Check $_FILES['fileToUpload']['error'] value. switch ($_FILES['fileToUpload']['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_NO_FILE: throw new RuntimeException('No file sent.'); case UPLOAD_ERR_INI_SIZE: throw new RuntimeException('File exceeds upload_max_filesize directive in php.ini.'); case UPLOAD_ERR_FORM_SIZE: throw new RuntimeException('File exceeds MAX_FILE_SIZE directive that was specified in the HTML form.'); case UPLOAD_ERR_PARTIAL: throw new RuntimeException('File was only partially uploaded.'); case UPLOAD_ERR_NO_TMP_DIR: throw new RuntimeException('Missing a temporary folder.'); case UPLOAD_ERR_CANT_WRITE: throw new RuntimeException('Failed to write file to disk.'); case UPLOAD_ERR_EXTENSION: throw new RuntimeException('File upload stopped by extension.'); default: throw new RuntimeException('Unknown upload error.'); } // DO NOT TRUST $_FILES['fileToUpload']['mime'] VALUE !! // Check MIME Type by yourself. $tmpFilePath = $_FILES['fileToUpload']['tmp_name']; if (!file_exists($tmpFilePath) || !is_file($tmpFilePath)) { throw new RuntimeException('Temporary upload file is missing.'); } $finfo = new finfo(FILEINFO_MIME_TYPE); if (false === $ext = array_search( $finfo->file($tmpFilePath), array( 'jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', ), true )) { throw new RuntimeException('Invalid file format.'); } // You should name it uniquely. // DO NOT USE $_FILES['fileToUpload']['name'] WITHOUT ANY VALIDATION !! // On this example, obtain safe unique name from its binary data. $targetPath = sprintf('./uploads/%s.%s', sha1_file($tmpFilePath), $ext); if (!move_uploaded_file($tmpFilePath, $targetPath)) { throw new RuntimeException('Failed to move uploaded file.'); } echo "File is uploaded successfully. \n"; echo "Running Python Backend now!"; StartPy(); } catch (RuntimeException $e) { echo $e->getMessage(); } ?>
额外排查点
- 检查php.ini中的
upload_max_filesize和post_max_size设置,确保上传文件大小不超过限制 - 确认WAMP的Apache进程对系统临时目录有读写权限
内容的提问来源于stack exchange,提问作者GhostDog98
相关产品推荐
相关产品推荐

