Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5実用編⑭】人物アイコン画像

B美

さて今回は、前回の続きよ
人物アイコン画像」関連ってこと

ただ、リファクタリングの続きとして、各Viewビューファイル内にあるCSS定義を別ファイルにまとめておきたいところね

C菜

あ~、たしかに~
ちょっと調べてみますね~

・・・

えっと、「templates/Top」の中の「index.php」と「templates/Chat」の中の「index.php」だけでした~
あと、「templates/layout」の中の「default.php」にもstyleタグがありますけど~

A子

ふむ、それじゃ「webroot/css」ディレクトリ内に新たなCSSファイルを作って、その中にCSS定義の箇所(styleタグの中身)を全部移動しちゃえばOKだね

ファイル名を「chat.css」にして作ってみたよ

C菜

では、それ(chat.css)をレイアウトファイルで読み込ませますね~

具体的には「templates/layout」の中にある「default.php」を書き換えるです~

A子

あれ?
うまくいかない…

なんで?

B美

「なんで」って、それは定数(の読み込み)をCSSファイル内に埋め込んでいるからよ
(「<?= SENT_COLOR ?>」及び「<?= RECEIVED_COLOR ?>」の箇所)

CSSファイルって、PHPファイルじゃないからね
当然「<?= (定数名) ?>」は効かないわよ

A子

んじゃ、どうすんのさ

B美

解決方法(の一つ)はこうね

1.「templates/layout/default.php」の中に「CSS変数」を定義する(styleタグ内)
2.「webroot/css/chat.css」内に存在するPHPコードの箇所を「CSS変数」を読み込むコードに変更する

上記1番の定義としては下記の通り

<style>
:root {
    --sent-color: <?= SENT_COLOR ?>;
    --received-color: <?= RECEIVED_COLOR ?>;
}
</style>

んで、2番はこんな感じね

.sent {
    background-color: var(--sent-color);
    align-self: flex-end;
    text-align: right;
}

.received {
    background-color: var(--received-color);
    align-self: flex-start;
    text-align: left;
}

.sent::after {
    content: "";
    position: absolute;
    right: -8px;
    top: 50%;
    transform: translateY(-50%);
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 8px 0 8px 10px;
    border-color: transparent transparent transparent var(--sent-color);
}

.received::after {
    content: "";
    position: absolute;
    left: -8px;
    top: 50%;
    transform: translateY(-50%);
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 8px 10px 8px 0;
    border-color: transparent var(--received-color) transparent transparent;
}







C菜

なるほど~
よくわかりました~

これって、色々なところに応用できそうなテクニックですよね~

B美

そうね

CSSファイルの中でPHPの定数が(「CSS変数」経由で)使えるというのは、知っておくと便利かも…

A子

さて、それじゃあらためて今回の主題である「人物アイコン画像」の変更機能を実装していこう

これって、普通に画像をアップロードするだけじゃダメなの?

C菜

PNGだったら良いですけど、JPEGやGIFの場合はPNGに変換する必要があるのでは~?
(だってファイル名を「(各ユーザのid).png」にするという仕様でしたし~)

A子

あ、そうだった…(汗)

でもまぁ、Viewビューファイルについては同じだよね
(画像投稿掲示板のViewビューを流用できそう)

てなわけで、「templates/Users」の中に「change_image.php」というファイルを新規作成してみたよ



C菜

あと、「templates/Top」の中にある「index.php」を変更して、メニューを追加してみました~



B美

Controllerコントローラーの処理ってちょっと難しいから、私のほうでやっておくわね

具体的には「src/Controller」の中にある「UsersController.php」に、「changeImage」メソッドを追加します

public function changeImage()
{
    if ($this->request->is('post')) {
        $upload = $this->request->getData('upload');

        //オリジナルのファイル名を取得
        $original_filename = $upload->getClientFilename();

        if ($original_filename != '') {
            $extension = mb_strtolower(pathinfo($original_filename, PATHINFO_EXTENSION));    //拡張子

            if ($extension == 'jpg' || $extension == 'jpeg' || $extension == 'gif' || $extension == 'png') {
                //一時ファイルのパス
                $temp_path = $upload->getStream()->getMetadata('uri');

                //画像形式に応じて画像作成
                switch ($extension) {
                    case 'jpg':
                    case 'jpeg':
                        $image = imagecreatefromjpeg($temp_path);
                        break;
                    case 'gif':
                        $image = imagecreatefromgif($temp_path);
                        break;
                    case 'png':
                        $image = imagecreatefrompng($temp_path);
                        break;
                }

                //PNG画像の作成
                $webroot = WWW_ROOT;
                $dst = $webroot.'personal'.DS.$this->identity->id.'.png';
                if (imagepng($image, $dst)) {
                    $this->Flash->success(__('人物アイコン画像を変更しました。'));
                } else {
                    $this->Flash->error(__('人物アイコン画像の変更に失敗しました。'));
                }

                //画像データの破棄
                imagedestroy($image);

                return $this->redirect(['controller' => 'Top', 'action' => 'index']);
            }
        }
    }
}

あ、アップロード画像の画像サイズ(縦横のドット数)チェックは、やってないからね


A子

ふーん、なるほどねぇ
拡張子チェックを通ったあとの処理って、こういう流れかな

1.アップロードした画像ファイルの、一時ファイルとしてのパスを取得する
2.1番を元にして、画像形式に応じた画像を作成する
3.2番を元にして、PNG画像を作成して保存する
4.2番の画像データを破棄する

てか、コード中に記述されているコメントを参考にしたんだけどさ(苦笑)

B美

それで合ってるわよ

ポイントは、(1番の)アップロードした画像ファイルの一時的な置き場所を取得するところね
(それが無いとイメージクリエイトできないのよ)

C菜

なるほどですねぇ~

それではさっそくテストしてみましょう~

A子

私のアイコン画像を変更してみたよ

んん?
おかしいな

変わらないよ?

B美

なにしろ同じファイル名だからねぇ(苦笑)

ブラウザとしては(わざわざWebサーバへリクエストせずに)自分の持つキャッシュデータを使うのが当然よね

C菜

あっ、強制更新が必要です~

つまりは[Ctrl]+[F5]キーの同時押しですね~

A子

なるほどね

てか、今見たら勝手に更新されてたよ
(更新処理してないのに…)

B美

あー、それはおそらく「ブラウザがキャッシュしている同名の画像ファイルに変更があったかどうかをWebサーバに問い合わせた」からだと思う
(これは一定時間経過すると行うみたい…よく知らんけど(苦笑))

まぁ、キャッシュデータを使わないようにする画像ファイルへのアクセス方法もあるけどね

うーん、そうねぇ
ヘッダ部分にログインユーザの名前とメールアドレスを表示しているけど、そこにアイコン画像も表示してみましょうか
(画像の強制更新付きで…)

C菜

それはぜひお願いします~

B美

それじゃ、「templates/layout」の中にある「default.php」を変更しましょう

こんな感じね

C菜

同じ修正を「templates/Users」の中にある「change_image.php」のほうにもやってみますね~

A子

なんか難しげなことをやってるけど、それって何なの?

B美

filemtime」関数で「ファイルの更新時間」を取得して、その値をクエリーパラメータとしてimgタグのファイル名の末尾にくっつけるの

そうすると、ブラウザはキャッシュを使わず、Webサーバへ画像データを取得しに行くってわけ
(だってURLが違うもの)

これを「Cacheキャッシュ Bustingバスティング」と呼んでいるわ

C菜

なるほどですねぇ~
名前がかっこいいテクニックです~

それでは私のアカウントでログインして、テストしてみますね~





A子

んじゃ、私も…

B美

それじゃ、私も変更してみましょう

C菜

私のアカウントで、A子社長とB美部長の会話を見てみたら、こうなりました~

完璧です~




A子

これは前回(【CakePHP5実用編⑬】)のときのテストデータだね

今は同じアイコン画像じゃないから、発言内容にちょっと違和感が…(苦笑)

C菜

それにしても、今回の内容は「CSS変数」「画像生成方法」「Cacheキャッシュ Bustingバスティング」と、結構盛りだくさんでした~

B美部長には感謝ですね~