Laravel開発、作成したアプリをデプロイして本番環境で動作させる【7】画像削除
デプロイして本番環境でアプリを動作させるシリーズの続きです。
S3へ画像アップロードする処理が完了したので、次はレコード削除時にS3から画像も削除できるようにします。
削除してないと、どんどんデータだけ蓄積されていくので、使わない物はきっちり削除して容量確保しましょう。
今回の目的
S3に追加している画像を削除できるようにしたい
なぜやるか
不要となった画像を削除することで、必要なデータのみをS3で登録管理するため
やりたいこと
レコード削除時にレコードに記載している画像URLを元に画像削除処理を追加する
やったこと
開発環境の画像削除処理を修正
S3アップロード処理を元に削除処理を書いてみる
S3オブジェクトキーを知る
正規表現でURLからキーを取得
重複コードをまとめる
本番環境で動作確認
実施内容
開発環境削除処理を修正
S3ファイルアップロードを対応させるようにしてから、開発環境でのファイルパスも変わっていました。
"image.jpg"→"/storage/bookimages/images.jpg"
このように変更されています。
まず、S3画像削除対応の前に開発環境のみの設定を修正することにしました。
# ~/app/Http/Controllers/BookController.php
$pathdelに削除パスを格納して削除ファイル指定を行っています。
$deletename = "image.jpg"の時は"storage_path() + /app/public/book_images/image.jpg"というパスを指定していました。
しかし、$deletenameの内容が変わってしまい次の様になっています。
"storage_path() + /app/public/book_images/storage/bookimages/images.jpg"
これを修正する為に、$deletenameから"/storage/book_images/"を削除することで"images.jpg"だけを取り出し、後は従来のコードを利用することにしました。
166行目になります。
/storage/book_images/ディレクトリ部分を削除することでファイル名を取り出し、あとは従来の手順で進めることで削除処理を実施。
もっと簡単な書き方がありそうな気がしますが…。一端これで進めます。
※このあと、画像登録処理もS3設定時にいろいろ変更していたので、開発環境での画像ファイル名に拡張子が2つある状態(〜.jpg.jpg)になっていたので修正しました。
S3画像削除処理
ここからいよいよレコード削除時にS3から画像を削除するコードを記載していきます。今までの工程と同様に、開発環境で一度S3画像削除処理を作成後、本番環境のみS3利用できるようにする形で作成していきます。
まず、S3画像アップロード時の処理"putObject"を参考に削除処理"deleteObject"を書いてみました。
また、こちらを参考にさせて頂きました、ありがとうございます。
これでまず削除を試すも削除されず。
S3で扱うオブジェクトキーを知る
削除するためのキー指定方法がいまいち分かっていなかったので、キーの指定について確認してみることにしました。
ブレークポイントで停止をかけて、画像アップロード時に指定したキーと現在の画像削除に指定しているキーの値を確認してみました。
アップロード時指定キー
book_images/private/〜中略〜/image.jpg
作成中:削除時指定キー
https://バケット名.s3.リージョン名.amazonaws.com/book_images/private/〜中略〜/image.jpg
削除時指定キーはDBに保存されている画像のURLを指定していました。一方のアップロード時に指定していたキーは画像保存しているフォルダ以下を指定していました。
また、このオブジェクトキーについては後から気がついたのですが、S3に実際にアップロードした画像ファイルの概要を確認すると記載がありました。
この事から、DB保存画像URLからS3ドメイン部分を削除すればオブジェクトキーとしてそのまま扱えそうです。
正規表現で画像URLからキーを取得
テキストから一部を抜き出す為に正規表現を利用しました。
正規表現の扱い方をまず確認、これにはこちらを参考にさせて頂きました、ありがとうございます。
そして、PHPで正規表現で変数を扱うにはこちらを参考にさせて頂きました、ありがとうございます。
その他、正規表現のデリミタ標記について"/"がうまく動作しないことが判明しましたので修正しました。修正にはこちらを参考にさせて頂きました、ありがとうございます。
以上の内容で画像削除時のS3に引き渡すキーを生成しました。
# ~/app/Helpers/picture_helpers.php
// 画像削除用キー生成
$book_pass = $book["picture"];// DB保存パス
$bucket = $s3["bucket"];//バケット名
$region = env('AWS_DEFAULT_REGION');//リージョン名
$delete_key = preg_replace("{.*".$bucket.".s3.".$region.".amazonaws.com/}", "", $book_pass);// DB保存パスから$delete_pass部を削除
preg_replaceを扱ってDB保存パスから先頭のhttps://〜.com/までを削除する記述としました。正規表現を利用して削除しています。
初めは変数を作って正規表現パスを記載していましたが、動作しなかった為に、replace内に直接記載しています。
この内容で$delete_keyが先程のS3でのオブジェクトキーと一致しているか確認し、同一であることを確認しました。
改めて、$delete_keyの内容を修正
# ~/app/Helpers/picture_helpers.php
修正前
$delete_key = preg_replace("{.*".$bucket.".s3.".$region.".amazonaws.com/}", "", $book_pass);// DB保存パスから$delete_pass部を削除
↓
修正後
$delete_pass = ".*".$bucket.".s3.".$region.".amazonaws.com/";//削除アドレス部生成
$delete_key = preg_replace("{$delete_pass}", "", $book_pass);// DB保存パスから$delete_pass部を削除
$delete_pass変数に正規表現を記載しました。
これで削除されるか確認するもエラー表示に。
正規表現について変数への入れ方を確認してみました、こちらを参考にさせて頂きました、ありがとうございます。
先程の正規表現はこう書いていました。
$delete_pass = ".*".$bucket.".s3.".$region.".amazonaws.com/";//削除アドレス部生成
$delete_key = preg_replace("{$delete_pass}", "", $book_pass);// DB保存パスから$delete_pass部を削除
"{$delete_pass}"→ここが変数でなくテキストでそのまま表現されていたようです。
修正
$delete_pass = "{.*".$bucket.".s3.".$region.".amazonaws.com/}";//削除アドレス部生成
$delete_key = preg_replace("$delete_pass", "", $book_pass);// DB保存パスから$delete_pass部を削除
正規表現変数にデリミタを含む内容を全て記載して、replaceでは変数を指定するだけにしました。
削除用のキー取得はこちらで完了しました。
重複コードをまとめる
S3リージョン情報について、"S3インスタンス生成時"と"画像削除時の正規表現"の中で重複して使っていましたので、S3インスタンス生成時に一度変数化することで環境変数からの読み出しを一箇所に集約しました。
上記、20行目の記述になります。
$regionに環境変数内容を入れておき、直後のS3インスタンス生成で利用。その他、正規表現でも扱いたいのでreturnにregionを追加しています。
これにより、正規表現利用時にS3インスタンス設定箇所で呼び出す形とし、コードの可読性が上がりました。
これでS3から画像削除の処理が完了しました。
本番環境で動作確認
ここまでで、開発環境からS3ファイル削除の検証完了しましたので、開発環境と本番環境の処理分岐を修正し、最後にHerokuにプッシュして実際に本番環境で動作するか確認です。
ここはすんなり動いてくれて、Heroku上での画像削除処理が完了しました。
これで新規作成時の画像追加、レコード削除時の画像削除まで完了しました。
後は、編集による画像変更や画像のみ削除のパターンに対応させます。