PHP は外部からアップロードされたファイルを web サーバを介して受け取れます。そしてこのファイルはグローバル変数の$_FILES
の中に格納されます。そして$_FILES
の中にはエラー内容も格納されます。
エラー内容は次のドキュメントの通りの定数で渡されます。
PHP: エラーメッセージの説明 – Manual
定数で渡されるのみで PHP のプログラム内で何かしらエラーに応じた操作をしなければ、何事もなかったかの様に処理が進みます。そして PHP フレームワークの一つである Laravel の素の状態ではエラーハンドリングがありません。自前で $_FILES 相当の中をエラーをハンドリングするミドルウェアが欲しくなります。これは次のコードの様に作れます。
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; /** * PHP の $_FILES 内のエラーを Laravel を介して読み取って例外として投げる * Class ThrowFileError * @package App\Http\Middleware */ class ThrowFileError { public function handle(Request $request, Closure $next) { $errors = []; // リクエストの中から送られてきたファイルを総ざらい foreach ($request->allFiles() as $file) { /** @var UploadedFile $file */ if ($file->getError() !== UPLOAD_ERR_OK) {// UPLOAD_ERR_OK は PHP 組み込み定数 // もしエラーが存在するのであれば、エラーメッセージをエラーリストの中に格納。 // ここは用いるプロジェクトのレスポンス形式に応じて変わりやすいです。 $errors[] = $file->getErrorMessage(); // webサーバ(nginx, apache等)のエラーと紛らわしくなるデメリットもありますが // エラー内容によって HTTP ステータスを分けるのであればここでエラー発見時に適したステータスの例外を投げるのもありです。 // 一例が↓のコメントアウト部です。 /* $errorMsgMap = [ UPLOAD_ERR_INI_SIZE => Response::HTTP_REQUEST_ENTITY_TOO_LARGE, UPLOAD_ERR_FORM_SIZE => Response::HTTP_REQUEST_ENTITY_TOO_LARGE, UPLOAD_ERR_PARTIAL => Response::HTTP_BAD_REQUEST, // アップロードしている途中でリクエストを中断した時に起こるのがほとんど UPLOAD_ERR_NO_FILE => Response::HTTP_BAD_REQUEST, UPLOAD_ERR_NO_TMP_DIR => Response::HTTP_INTERNAL_SERVER_ERROR, UPLOAD_ERR_CANT_WRITE => Response::HTTP_INTERNAL_SERVER_ERROR, UPLOAD_ERR_EXTENSION => Response::HTTP_INTERNAL_SERVER_ERROR, ]; throw new HttpException($errorMsgMap[$file->getError()], $file->getErrorMessage()); */ } } if (! empty($errors)) { // もしエラーが存在するならばステータス 400 で HTTP レスポンスを返す例外を投げます。 throw new HttpException(Response::HTTP_BAD_REQUEST, implode("\n", $errors)); } // 何事もなければ次の処理へ移動 return $next($request); } }
このミドルウェアは大体常時使用で問題ないでしょう。app/Http/Kernel.php の middleware プロパティに追加すれば、どのリクエスト常にファイルエラーのハンドリングが実行されます。
class Kernel extends HttpKernel { /** * The application's global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array */ protected $middleware = [ ThrowFileError::class,// ←ここに追加 TrustProxies::class, CheckForMaintenanceMode::class, ValidatePostSize::class, TrimStrings::class, ConvertEmptyStringsToNull::class, ]; //
これでアップロードされたファイルにエラーがあった場合、自動でエラーレスポンスが投げられる様になります。