PSR7のHttp/Messageを使ったファイルアップロード処理

  • 29
    いいね
  • 4
    コメント
この記事は最終更新日から1年以上が経過しています。

とうとう策定された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で便利になった点の一つだと思ったので書いてみました。