とうとう策定されたPSR-7(Http/Message)を使った場合、ファイルアップロードの処理がどうなるか書いてみました。
PSR-7の策定にまで持っていった「Matthew Weier O'Phinney」さんという方が作ったPSR-7実装「zendframework/zend-diactoros」を参考にしてます。他の実装では構築方法などが微妙に違うかもしれませんが、APIは同じになります。
サンプルコード
アップロードフォーム
次のようなアップロードフォームを想定します。
<form method="post" enctype="multipart/form-data">
<input type="file" name="up[0]" />
<input type="submit" />
</form>
名前が配列になってます。従来のPHPだと、この場合の処理がメチャクチャ面倒でした。
サーバー側の処理
まずはリクエストオブジェクトを生成します。
use Psr\Http\Message\UploadedFileInterface;
use Zend\Diactoros\ServerRequestFactory;
$request = ServerRequestFactory::fromGlobals();
if ($request->getMethod()!=='POST') {
exit;
}
// UploadedFileInterfaceの配列を読み込む
$uploaded_files = $request->getUploadedFiles();
if (!isset($uploaded_files['up'][0]) || !$uploaded_files['up'][0] instanceof UploadedFileInterface) {
exit;
}
/** @var UploadedFileInterface $upload */
$upload = $uploaded_files['up'][0];
一応、メソッドがPOSTであること、目的のファイルがアップロードされたことぐらいはチェックしてみました。
これで、アップロードされたフィアルについてのUploadedFileInterface
のオブジェクトが取得出来ました。ここからは、この$upload
オブジェクトを操作します。
UploadedFileInterface
オブジェクト
エラーチェック
ファイルのアップロードエラーをチェックします。例えば…
if ($upload->getError()===UPLOAD_ERR_NO_FILE) {
die('ファイルをアップロードして下さい');
}
if ($upload->getError()===UPLOAD_ERR_FORM_SIZE) {
die('サイズが大きすぎます');
}
if ($upload->getError()!==UPLOAD_ERR_OK) {
die('OKじゃないです。エラーです');
}
// エラー無し
エラーチェックも簡単、というか迷わない感じです。
ファイルの操作
ストリームを取得して、中身を読み取ります。
$stream = $upload->getStream();
// streamを使って書きだす。
$stream->rewind();
while (! $stream->eof()) {
echo $stream->read(4096);
}
// ファイルポインターを抜き出して、書きだす。
$fp = $stream->detach();
rewind($fp);
fpassthru($fp);
あるいは別ファイルへ移動します。
$upload->moveTo('/path/to/new/file');
アップロードエラーがある状態で、getStream
あるいはmoveTo
を使うと例外を投げます。またmoveTo
は一度しか使えません。もちろん移動する際にはmove_uploaded_file
を使ってアップロードされたファイルしか移動しません。
最後に
説明しなくても使えぐらい簡単なAPIと思いますが、PSR-7で便利になった点の一つだと思ったので書いてみました。