ファイルサイズの上限
上限の設定をPHP側でするのかブラウザ側でするのかで作業内容が変わる。
PHP側で設定してもブラウザ側で何も設定していない場合、上限のチェックが入るのはサーバにファイルをアップロード処理をしてからとなってしまう。
よって、巨大なファイルを転送しようとして長時間待ち続け、 結局ファイルが大きすぎてアップロードできなかったという事態に陥る。
- PHP側で設定する場合
php.iniのupload_max_filesizeに設定する。
upload_max_filesizeは1ファイルあたりの上限サイズの設定
post_max_sizeはPOST全体のサイズ上限
post_max_sizeはupload_max_filesizeよりも常に大きくなければならない。
- ブラウザ側で設定する場合
"file"inputフィールドの前に"MAX_FILE_SIZE"hiddenフィールドを置く必要がある。
この値はバイト数で指定する。
例).1MBの場合は1024*1024= 1048576バイト
<input type="hidden" name="MAX_FILE_SIZE" value="1048576">
<input type="file" name="image">
ファイルをアップしようとして、MAX_FILE_SIZE の制限を超えている場合、
$_FILESの['type']['tmp_name']は空である。
参考記事
http://hensa40.cutegirl.jp/archives/930
ファイルの検証
- そもそもファイルがちゃんとPOSTされているか
if (!isset($_FILES['image']) || !isset($_FILES['image']['error'])) {
throw new \Exception('Upload Error!');
}
- エラーの内容によってエラーメッセージを出し分ける
switch($_FILES['image']['error']) {
case UPLOAD_ERR_OK:
return true;
case UPLOAD_ERR_INI_SIZE: //php.iniのupload_max_filesize超過
case UPLOAD_ERR_FORM_SIZE: //HTMLフォームで指定されたMAX_FILE_SIZE超過
throw new \Exception('File too large!');
default:
throw new \Exception('Err: ' . $_FILES['image']['error']);
}
参考記事
https://www.softel.co.jp/blogs/tech/archives/1824
画像ファイルの判別
exif_imagetype関数を使う
switch(exif_imagetype($_FILES['image']['tmp_name'])) {
case IMAGETYPE_GIF:
return 'gif';
case IMAGETYPE_JPEG:
return 'jpg';
case IMAGETYPE_PNG:
return 'png';
default:
throw new \Exception('PNG/JPEG/GIF only!');
}
実際にアップロードする
- ファイル名を決める
ファイル名は被らないように考慮する必要があるためuniqid関数を使うとよい。
これはマイクロ秒単位の現在時刻に基づいた13文字のIDが生成される。第二引数をtrueにするとさらに文字が長くなる。
- 格納ディレクトリ
予め定数で格納ディレクトリを決めておくとよい。
define('IMAGES_DIR', __DIR__ . '/images');
- 保存処理
move_uploaded_file関数を使う。引数にはファイル名を含むパスを指定する。
処理が失敗した場合はFALSEが返ってくるため、その場合は例外を投げるようにする。
$savePath = IMAGES_DIR . '/' . $this->_imageFileName;
$res = move_uploaded_file($_FILES['image']['tmp_name'], $savePath);
if ($res === false) {
throw new \Exception('Could not upload!');
}
サムネイルを作る
横幅が大きい場合、サムネイルを作るためまずは画像サイズのチェックをする
$imageSize = getimagesize($savePath);
$width = $imageSize[0];
$height = $imageSize[1];
if ($width > THUMBNAIL_WIDTH) {
$this->_createThumbnailMain($savePath, $width, $height);
}
}
サムネイルを作るには元画像の画像リソースを作り、それを元にサムネイルを作ってそれで保存をする。
(※gif,jpg,pngで、元画像を読み込むときと、サムネイルに加工後に出力する時の2つのポイントで関数が異なる。)
全体的な流れ
- 元画像のリソースを読み込む
- (imagecreatefromgif,imagecreatefromjpeg,imagecreatefrompng)
- サムネイルの型を作る
- (imagecreatetruecolor関数)
- 実際にサムネイルを作る
- (imagecopyresampled関数)
- サムネイル画像を出力する
- (imagegif,imagejpeg,imagepng)
関連記事
https://webkaru.net/php/image-thumbnail/
https://the-zombis.sakura.ne.jp/wp/blog/2012/01/03/post-1154/
https://00m.in/UBZ2n
画像一覧を表示する
基本的な流れとしては画像を取得してループ。
PHPで指定したディレクトリのファイル一覧にはテンプレがある。
$imageDir = opendir(IMAGES_DIR);
while (false !== ($file = readdir($imageDir))) {
if ($file === '.' || $file === '..') {
continue;
}
$files[] = $file;
アップロード成功時・失敗時のメッセージを出力する
メッセージを出力する関数には成功時・失敗時両方のメッセージを返すようにする
public function getResults() {
$success = null;
$error = null;
...処理
return [$success, $error];
}
一覧画面では両方を一度に受け取る(list関数)
list($success, $error) = $uploader->getResults();
アップロードボタンのスタイリング
画像ファイルを選択したらそのままアップロードされるようにする。
"submit"フィールドを消して、fileフィールドを透明にしつつボタン横いっぱいまで広げ、jQueryで要素が変わったらsubmitボタンが有効になるようにする
<div class="btn">
アップロードする
<form action="" method="post" enctype="multipart/form-data" id="my_form">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo h(MAX_FILE_SIZE); ?>">
<input type="file" name="image" id="my_file">
</form>
</div>
$(function() {
$('.msg').fadeOut(3000);
$('#my_file').on('change', function() {
$('#my_form').submit();
});
});
input[type="text"]{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}