FuelPHPをやってみる (20) - ファイルアップロード -

2012-11-26T00:00:00+00:00 FuelPHP PHP

タイトル通り。Uploadクラスを使えばサラっとできちゃう模様

fuel/app/config/upload.php

fuel/core/config/upload.phpからコピーするなりで作成

<?php

return array(
    "auto_process" => true,
    "max_size" => 0,
    "ext_whitelist" => array(),
    "ext_blacklist" => array(),
    "type_whitelist" => array(),
    "type_blacklist" => array(),
    "mime_whitelist" => array(),
    "mime_blacklist" => array(),
    "prefix" => "",
    "suffix" => "",
    "extension" => "",
    "path" => DOCROOT."uploads",
    "create_path" => true,
    "path_chmod" => 0777,
    "file_chmod" => 0666,
    "auto_rename" => true,
    "overwrite" => false,
    "randomize" => true,
    "normalize" => false,
    "change_case" => false,
    "max_length" => 0
);

デフォルトからはpathとrandomizeを変更。アップロード先を指定するのに毎回指定するのもどうかと思うので、設定に記述してそれを再利用する形式を使う。今回DB等は使わない(そもそもModelクラス等にblobサポートが無いかも)

fuel/app/classes/controller/home.php

<?php

class Controller_Home extends Controller {

    public function before() {
        parent::before();

        // fuel/app/config/upload.phpをロード。無かった場合はcoreな方の設定がロードされる模様
        Config::load("upload", true);
    }

    public function get_index() {
        $files = array();

        try {
            // アップロードディレクトリからファイルを列挙
            $files = File::read_dir(Config::get("upload.path"));
        } catch (InvalidPathException $e) {
            // アップロードディレクトリが無い場合とかにスローされるのでログっておく。場合によればエラー出しても良いとは思う
            Log::warning($e);
        }

        return View::forge("home", array("files" => $files));
    }

    public function post_upload() {
        Upload::process(array("path" => Config::get("upload.path")));

        if (Upload::is_valid()) {
            // 指定したアップロードディレクトリにアップロード
            Upload::save();

            /*
            アップロードされたファイル等の情報を取得できる模様
            $files = Upload::get_files();
            */
        }

        return Response::redirect("/");
    }
}

fuel/app/views/home.php

<html>
  <body>
    <form action="/upload" method="post" enctype="multipart/form-data">
      <input type="file" name="upload[]" multiple="true" />
      <input type="submit" />
    </form>

    <?php foreach ($files as $file) { ?>
      <!-- アップロードディレクトリを走査した結果、ディレクトリな場合は再帰的で処理される模様なので、配列である場合かファイルで無い場合はcontinueする -->
      <?php if (is_array($file) or !is_file(Config::get("upload.path").DS.$file)) continue; ?>
      <img src="/uploads/<?php echo $file; ?>" />
    <?php } ?>
  </body>
</html>

な感じかなと。今回はDOCROOTのuploadsディレクトリに作ってるので普通に参照できる

DBとか使う場合にはUpload::get_files()なメソッドで返ってくる情報をDBに格納しておいて処理するとかで良いんじゃないかと

一応、これから普通にURLからアクセス出来ないところにアップロードした場合のケースをやるので検証次第追記します

追記 ファイルをURLから直接参照できない場合

publicなディレクトリ内にありゃ普通に参照できるけど、そうじゃない場合にはアクション作って読み取るような処理が必要になる訳ですが。で問題がFuelPHPのルーティング上で「拡張子は無視される」っていうのがあると思うのですが。今回はUpload::get_files等から情報をDBなどに格納したりしてないので、リクエストされたファイル名から拡張子抜いた値から推定しなきゃならんので、とりあえずは拡張子はjpgに限定

なのでfuel/app/config/upload.phpをちょっと修正

return array(
    "path" => DOCROOT."../uploads",
    "ext_whitelist" => array("jpg")
);

な設定しておく。でルーティングで

return array(
    "fetch/(:any)" => "home/fetch/$1"
);

な設定もやっとく。あとはこのアクションをビューで参照する。でそのアクション側が

<?php

class Controller_Home extends Controller {

    // 追加
    public function get_fetch($file) {
        $path = Config::get("upload.path").DS.$file.".jpg";

        if (file_exists($path)) {
            $data = null;

            try {
                $data = File::read($path);
            } catch (InvalidPathException $e) {
                Log::warning($e);
            }

            if (!is_null($data)) {
                $res = Response::forge($data);
                $res->set_header("Content-Type", "image/jpg");

                return $res;
            }
        }

        throw new HttpNotFoundException();
    }
}

な感じでFile::readを使って読み込んだデータをレスポンスで出す。Imageクラスとか使えばリサイズとかも出来る模様なので、状況に応じてそういう処理かましたらいいかと

FuelPHPをやってみる (21) - 認証機能 (1) - FuelPHPをやってみる (19) - Themeを使う -