PHPで管理ツールなどをつくっていると、管理用に画像を扱いたいことがあります。
この場合、画像はサーバに保存し、画像のパスをDBに入れることが多いと思いますが、この画像の管理、ちょっと面倒だと思いませんか?
自分が普段使いまわしている画像関連処理を、自分用メモとしてまとめてみました。
アップロードされた画像の処理などは、共通関数化していますので、最後の方でまとめてソースを置いています。
※自分が操作する用の処理なので、不正対策やバリデーションチェックなどは考慮していません
フォームから画像送信するための処理
フォームから画像などのファイルを送信する場合は、inputタグを使います。
<form method="post" action="<?php print basename( __FILE__ ); ?>" enctype="multipart/form-data"> <input type="file" name="image" accept="image/png,image/jpeg"> <input type="submit" value="送信"> </form>
この送信されたファイルを処理するため、PHPで以下の処理を追加します。
$fname = file_upload( $_FILES, 'image' );
file_uploadは自作共通関数です。後述しているファイルアップロード処理関数を参照してください。この関数から戻されたファイル名($fname)を、DBに保存します。
一連の処理をまとめると、以下のような感じ。
<?php try { $fname = file_upload( $_FILES, 'image' ); # DBに登録する処理 } catch( Exception $e ){ # エラー処理 } # DBから読み込み処理 ?> <form method="post" action="<?php print basename( __FILE__ ); ?>" enctype="multipart/form-data"> <input type="file" name="image" accept="image/png,image/jpeg"> <input type="submit" value="送信"> </form>
送信済みファイルを削除したい場合
画像ファイルが既に設定されていて、その画像ファイルを削除したい場合は、削除用のフラグを追加します。
上記処理で、imageに値がセットされていたら、削除用のチェックボックスを表示するように変更。
<?php $image_del = filter_input( INPUT_POST, 'image_del', FILTER_SANITIZE_STRING ); try { if( empty( $image_del ) || $image_del !== '1' ){ $fname = file_upload( $_FILES, 'image' ); # DBに画像パスを登録するSQLを作成 } else { # DBから画像パスを削除するSQLを作成 } # DBの更新処理 } catch( Exception $e ){ # エラー処理 } ?> <form method="post" action="<?php print basename( __FILE__ ); ?>" enctype="multipart/form-data"> <input type="file" name="image" accept="image/png,image/jpeg"> <?php if( strlen( $fname ) > 0 ){ ?> <input type="checkbox" name="image_del" value="1">登録済画像を削除する</input> <?php } ?> <input type="submit" value="送信"> </form>
ちなみに、type="file"では、valueに画像ファイルを指定しても、指定した値は反映されません。JavaScriptを使っても設定できません。
これは、ユーザーが意図しないファイルを、勝手にサーバ側で指定して送信してしまう、という状況を防ぐためのものなので、セキュリティ上不可能です。
送信済みファイルがある場合にサムネイルを表示
画像ファイルが既に設定されていて、その画像ファイルをサムネイル表示したい場合は、imgタグを追加します。
上記処理にさらに追加します。
<?php $image_del = filter_input( INPUT_POST, 'image_del', FILTER_SANITIZE_STRING ); try { if( empty( $image_del ) || $image_del !== '1' ){ $fname = file_upload( $_FILES, 'image' ); # DBに画像パスを登録するSQLを作成 } else { # DBから画像パスを削除するSQLを作成 } # DBの更新処理 } catch( Exception $e ){ # エラー処理 } ?> <form method="post" action="<?php print basename( __FILE__ ); ?>" enctype="multipart/form-data"> <input type="file" name="image" accept="image/png,image/jpeg"> <?php if( strlen( $fname ) > 0 ){ ?> <input type="checkbox" name="image_del" value="1">登録済画像を削除する</input> <img src="<?php print $fname; ?>" style="width: 100px; height: auto;"> <?php } ?> <input type="submit" value="送信"> </form>
ファイルアップロード処理関数
上記処理で使用しているファイルアップロード処理関数です。
ひとつめのパラメータは、$_FILESをそのまま渡してください。
ふたつめのパラメータは、POSTされてくるname属性の値を渡してください。
戻り値として、ファイルへのパスが設定されます。
function file_upload( $argFile, $argColum ){ // ファイル情報が取得できていない場合は処理を抜ける if( !isset( $argFile[$argColum] ) ) return ''; $finfo = $argFile[$argColum]; // ファイルが送信されていない場合は処理を抜ける if( empty( $finfo['tmp_name'] ) ) return ''; // ファイルアップロード時のエラーチェック if( strlen( $finfo['tmp_name'] ) > 0 && $finfo['error'] !== UPLOAD_ERR_OK ){ $reason = ''; switch( $finfo['error'] ){ case UPLOAD_ERR_INI_SIZE: $reason = "php.iniのupload_max_filesizeディレクティブの値を超えています"; break; case UPLOAD_ERR_FORM_SIZE: $reason = "HTMLフォームで指定されたMAX_FILE_SIZEを超えています"; break; case UPLOAD_ERR_PARTIAL: $reason = "一部のみしかアップロードされていません"; break; case UPLOAD_ERR_NO_FILE: $reason = "ファイルはアップロードされませんでした"; break; case UPLOAD_ERR_NO_TMP_DIR: $reason = "テンポラリフォルダがありません"; break; case UPLOAD_ERR_CANT_WRITE: $reason = "ディスクへの書き込みに失敗しました"; break; case UPLOAD_ERR_EXTENSION: $reason = "PHPの拡張モジュールがファイルのアップロードを中止しました"; break; } throw new Exception( $reason ); } $tmpname = $finfo['tmp_name']; // 指定されたファイルがアップロードされたものかチェック if( !is_uploaded_file( $tmpname ) ){ $reason = '指定されたファイルはPOSTでアップロードされたファイルではありません'; throw new Exception( $reason ); } // アップロードされたファイルの画像形式チェック $ext = ''; if( @exif_imagetype( $tmpname ) === IMAGETYPE_JPEG ){ $ext = '.jpg'; } else if( @exif_imagetype( $tmpname ) === IMAGETYPE_PNG ){ $ext = '.png'; } else { $reason = '画像形式が未対応です'; throw new Exception( $reason ); } // アップロードされた画像の移動処理 $fname = './images/'.date( 'YmdHis ).$ext; if( !move_uploaded_file( $tmpname, $fname ) ){ $reason = 'ファイル保存時にエラーが発生しました'; throw new Exception( $reason ); } return $fname; }
さいごに
だいぶ簡略化しているので、実際に使っていくには処理部分を作り込んだり、レイアウトを整える必要があります。以下はレイアウト例。
自分だけが使うシステムになるので、利便性などは特に考慮していません。
file_upload関数に関しては、実際に使っているものは少し違います。実際は、処理ごとにデバッグ出力用の処理があったり、例外処理ももうちょっと作り込んでいます。でも、ほぼこのままで使い回せるんじゃないかな。
ご参考までにどうぞ。
初稿:2019年2月6日
コメント