如何解决Laravel上传CSV文件时报stream_copy_to_stream errno=21目录错误
错误根因分析
你遇到的报错和上传大小、内存限制配置无关,错误代码errno=21 Is a directory的含义是PHP尝试将目录当成普通文件执行读取操作,核心问题出在路径逻辑和目录权限配置上:
stream_copy_to_stream(): read of 8192 bytes failed with errno=21 Is a directory
代码存在的问题及修复方案
- 上传目录不存在或无权限
你使用public磁盘存储文件时,默认存储根目录为storage/app/public,需要先确认storage/app/public/uploads目录存在,且PHP运行用户(常见为www-data、apache、nginx)对该目录有读写权限。可在代码中提前调用目录创建方法避免目录不存在的问题:
- 上传目录不存在或无权限
\Storage::disk('public')->makeDirectory('uploads');
- 上传文件实例获取逻辑错误
原代码中$req->file->getClientOriginalName()的写法不规范,$req->file()是方法,需要传入上传控件的字段名才能拿到正确的文件实例,规范写法为:
- 上传文件实例获取逻辑错误
$uploadFile = $req->file('file'); $fileName = time().'_'.$uploadFile->getClientOriginalName();
- 文件读取路径拼接错误
storeAs返回的路径是相对于public磁盘根目录的相对路径,直接用public_path($filePath)拼接得到的路径是错误的,会指向项目public目录下的文件,而实际文件存储在storage/app/public目录下,正确的路径获取方式为:
- 文件读取路径拼接错误
// 直接通过Storage类获取文件绝对路径 $realPath = \Storage::disk('public')->path($filePath);
修复后完整代码
public function parseImport(Request $req) { // 明确判断file字段是否存在有效上传文件 if ($req->hasFile('file')) { // 自动创建上传目录,避免目录不存在报错 \Storage::disk('public')->makeDirectory('uploads'); $fileModel = new File(); $uploadFile = $req->file('file'); $fileName = time().'_'.$uploadFile->getClientOriginalName(); $filePath = $uploadFile->storeAs('uploads', $fileName, 'public'); // 传入正确的文件绝对路径解析CSV $realPath = \Storage::disk('public')->path($filePath); $this->data = ImportHelpers::parseCsv($realPath); $fileModel->name = $fileName; $fileModel->file_path = $filePath; $fileModel->save(); return back() ->with('success','文件上传成功。') ->with('file', $fileName); } }
额外排查项
如果修改后仍有报错,检查ImportHelpers::parseCsv方法的内部逻辑,确认没有将传入的文件路径误处理为目录,或者尝试读取路径的上级目录。
内容的提问来源于stack exchange,提问作者Abdo Rabah
相关产品推荐
相关产品推荐

