非公開ディレクトリの画像を表示する
今回は、β版に向けての取り組みの1つとして、表示させる画像のアクセス先を非公開ディレクトリに変更します。
現在は公開ディレクトリ(Public)内のAssetsフォルダ内に配置していますが、これをルート直下においているStorageに移動させるのが目的となります。
gifのbase64化
URLによるAPI取得ではなく、今回はPHP関数でbase64に変換した画像を取得、imgタグのsrcに突っ込むという方式を取ります。
時間の測定
まず「速度」の問題についてです。gif画像を取得してbase64に変換する段階でそこそこの時間がかかることが懸念されましたが、思った以上に早く処理負荷自体もそこまで掛かりそうになかったので、今回はbase64での再現となりました。
以下別環境で試した処理時間の計測結果です。
思った以上の結果です。サイズは小さいとはいえ、大量に取得するとそこそこの秒数になってしまうことを懸念していましたが、これなら全く問題なさそうです。
表示方法
次にbase64の取得から表示までの流れを見ていきましょう。
srcには画像へのパスを指定して取りに行くのが一般的ですが、base64に変換すれば文字列になるので、以下のような形式で埋め込むことになります。
src="data: image/gif;base64,・・・・"
次に、画像データをbase64の形式に変換するには、file_get_contentsとbase_64_encodeを使用します。file_get_contentsでは非公開ディレクトリを指定することができるので、この段階で画像自体にはアクセス、変数へ格納することになります。
$base64 = base64_encode(@file_get_contents('../image/pikachu.gif'));
file_get_contents(PHPマニュアル)
base_64_encode(PHPマニュアル)
file_get_contentsではアクセス失敗時にエラーが返却されます。もし指定ファイルがみつかなければ問答無用でエラーが出てしまうため、これを無効化するためにもエラー制御演算子(@)をつけて、失敗時には空テキストを返しています。
※エラー制御演算子の採用理由については、後述します
取得後にはファイル情報を取得するために、getimagesizeを使い、src用の記述を追加してimgタグにセットすることで、表示することができます。
$info =getimagesize('data:application/octet-stream;base64,' . $base64);
$src = 'data: '.$info['mime'].';base64,'.$base64;
?>
<img src="<?=$src?>" alt="ピカチュウ">
getimagesize(PHPマニュアル)
以上が、画像取得から表示までの流れです。変換、srcの形式に変換しているだけなので、基本的には固定の流れを当てはめているだけになります。
ルートパスの取得
base64の変換速度、表示までには問題がないことがわかりましたが、1点解決しなければならない問題があります。それがパスの特定です。
非公開ディレクトリを使う構成上、様々な場所から比較的自由にパスを指定・アクセスできるようにしておきたいものです。
なのでフレームワークのように、ルートパスを取得するための標準関数を作成します。
__FILE__を使った環境対応
ルートパスの特定方法についてですが、ローカル、テスト、本番全環境に対応できるよう、環境変数(__FILE__)を使用します。
パス取得用のグローバル関数(/App/Globals/PathGlobal.php)
<?php
/**
* ルートパスの取得
* @param dot_path:string
* @return string
*/
function root_path(string $path='/')
{
// 引数で相対パスの指定があれば、前後にスラッシュを追加してpreg_replaceで置き換え
if($path !== '/'){
$path = preg_replace("/\./", '/', '.'.$path.'.');
}
return preg_replace("/\/App\/Globals\/PathGlobal\.php$/", '', __FILE__).$path;
}
root_pathという関数を作成、その関数が置かれているファイル自体を特定するために、__FILE__を使い、現在いるルートからのパスをpreg_replaceで取り除いて返却しています。
もし引数で相対指定された場合にも対応できるよう、ドット記法対応形式で相対で返すようにしました。
使用頻度の高いディレクトリを特定する際は以下のように追加していきます。
/**
* ストレージパスの取得
* @param dot_path:string
* @return string
*/
function storage_path(string $dot_path='')
{
return root_path('Storage.'.$dot_path);
}
これなら、同じ記述を繰り返し書かずとも、必要なディレクトリに合わせてパスを通すことができます。
ポケモンの判別
最後に、ポケモンの判別方法についてです。現在のポケモン画像を取得できるようにメソッドとして用意するものと、インスタンス化していなくても取得できるグローバルのものを分けて用意します。
まずはグローバルの画像取得用関数についてです。
<?php
/**
* ストレージパスの取得
* @param pokemon:string
* @param pause:string::front|back|mini
* @return string::data:base64
*/
function base64_pokemon(string $pokemon, string $pause='front')
{
// 画像の取得処理
$base64 = base64_encode(
@file_get_contents(storage_path('Images.Pokemon.'.$pokemon).$pause.'.gif')
);
if($base64){
$info = getimagesize('data:application/octet-stream;base64,' . $base64);
return 'data: '.$info['mime'].';base64,'.$base64;
}else{
return config('notfound.'.$pause) ?? config('notfound.mini');
}
}
引数に与えられたポケモンと、その向きに合わせて画像を探し出し、返却しています。もちろん、画像ファイル名が間違っていればエラーが出てしまうため、これを回避するためにも前述したエラー制御演算子を使って空判定をしています。
configには既にbase64に変換した宛先不明時の画像をテキスト形式で入れているので、失敗したとしても正常に画像は表示することが可能です。
本番環境でもし間違いがあれば、どんなポケモンが設定されているのかが確認できるので、どうしても見たい人はぜひデバックがてらいろんなポケモンと出会ってみてください。こちらは近日中に本番環境へ反映予定です。
※基本的には出さない方向ですので、もし見つかれば間違いなく「不具合」です
次に、インスタンス化したポケモンが自身の画像を取得するためのメソッドについてです。
/**
* 画像の取得
* @return string::data:base64
*/
public function base64(bool $transform=false)
{
if(
$transform &&
$this->isSc('ScTransform')
){
$pokemon = $this->getTransform()->pokemon;
}else{
$pokemon = get_class($this);
}
// base64画像を取得
return base64_pokemon($pokemon);
}
基本的には自身のクラスを、先程作成したbase_64へ突っ込んで取得するだけの流れになりますが、引数に合わせて「へんしん状態」を考慮しています。
クラスの定数化に伴い、へんしんの格納先を状態変化配列に変更したので、もしフラグが立っていれば、へんしん状態込みで画像を生成、返却してくれます。
初期画面での表示は以下の通りです。
デベロッパーツールで確認すると、正常にbase64の画像が表示されいていることがわかりました。
以降はこちらの画像取得方法を使って実装していきます。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「非公開ディレクトリの画像へのアクセス方法」についてご紹介しました。
システム構成を考えていけば、既存のフレームワークを真似ていくものが多くなります。なので、手っ取り早くイメージを掴みたい人は、ある程度の基礎が固まればフレームワークを使った業務に取り組んでみるのが良いでしょう。
現在プログラミング学習に取り組んでいる方や、ゲームづくりに興味がある人は、ぜひ参考にしてみてくださいね。