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日
コメント