Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5応用編⑩】テストとデプロイ

A子

テスト仕様書を作って、その結果も入力してみたよ

こんな感じでどう?
(クリックすると別ウィンドウで開きます)

ちなみに、この中のテスト項目No.15については修正済みだよ
(下記の通り)


B美

ふむ…

まぁまぁかな?

C菜

なにか足りないものでもあるんでしょうか~?

B美

もっと、細かいところもテストしておきべきね

そうねぇ
例えば、こんな感じ
(クリックすると別ウィンドウで開きます)

A子

うっ、確かに細かいな(苦笑)

そんなとこまでやらなきゃダメ?

B美

このWebアプリの利用者がやりそうなことは、(考え得る限り)一通りは試しておくべきね
(どこで不具合が発生するか分からないし…)

C菜

というか、最後のテスト項目No.32については、多分何も対策してないです~

A子

だねー

それはともかく、B美の提示したテスト項目(No.27~No.32)をやってみよう



A子

テストデータとなる画像ファイルを作るのが、めっちゃ面倒くさかった…(苦笑)
(なにしろ、3種類の画像フォーマットごとに4通りのサイズの画像を作ったからね…全12個)

んで、結果はこうだったよ
(クリックすると別ウィンドウで開きます)



C菜

予想通り、No.32はダメでした~

これって何か対策を考えないと…ですね~

A子

No.27も問題だね

画像サイズが小さいときは、拡大表示せずにオリジナルサイズで表示したいところ…

B美

No.27については簡単よ

CSSの「object-fit」の値を「contain」から「scale-down」に変えるだけね

C菜

あっ、ほんとです~

簡単に修正できました~

B美

んじゃ、最後の問題よ

削除した投稿に画像が存在した場合、その画像へのアクセスを禁止する」には?

A子

その画像を削除しちゃダメなの?

C菜

データベースのレコードを物理削除するのなら、それで良いと思うです~

でも「削除フラグを立てる」方法では、あとで復活させる可能性もありますよ~?

A子

うーん、だったらファイルの拡張子を変更する?

今は「投稿番号.拡張子」だけど、「投稿番号.拡張子.bak」って感じで…

B美

それって、URLとしてその変更したファイル名を指定した場合、ダウンロードが実行されることになるわよ
(ダウンロード後にファイル末尾の「.bak」を削除すれば、画像ファイルとして復活することになるわね)

A子

むむ、んじゃそのファイルを別のディレクトリへ移動させる?

一般ユーザがアクセスできない場所へ…

B美

それも一つの方法ね

隔離領域となるそのディレクトリのパーミッション設定とか、ちょっと面倒くさい作業が必要になるけど…(苦笑)

C菜

以前、画像のファイル名をどうするか…って考えたことがあったじゃないですか~
それを応用して、20文字くらいのランダムな文字列をファイル名の前半にくっつけるというのはどうでしょう~?

元のファイル名が「29.jpg」だったら「xxxxxxxxxxxxxxxxxxxx_____29.jpg」って感じにするんです~
(「xxxxxxxxxxxxxxxxxxxx」の部分はランダムな感じで…)

A子

お、それ良いんじゃない?

ランダム文字列を簡単に作れるのかどうか知らんけど…

B美

ふむ、まとめると

候補概要メリットデメリット
「A子」案画像ファイルを一般ユーザがアクセスできないディレクトリへ移動するセキュリティは完璧ディレクトリのオーナーやパーミッションを設定するのが面倒くさい
「C菜」案ファイル名に推測されにくいランダム文字列を付加する処理は簡単絶対にアクセスされないという保証はない

…って感じかな

A子

C菜の案に一票!

簡単に実現できるほうが良いからね

B美

OK、わかったわ
だったらChatGPTを使っても良いから、あなたたちで「やってみなはれ」

A子

あんたはサントリー創業者の鳥井信治郎か!

C菜

ナイスつっこみです~(笑)



A子

やってみたよ

まずはランダム文字列を生成するメソッドだね
(「PostsController.php」の中に記述)

private function generateRandomString($length = 20) {
    return substr(bin2hex(random_bytes($length)), 0, $length);
}

ChatGPTに教えてもらった関数の先頭に「private」を付けただけなんだけどね

C菜

で、「PostsController.php」の「delete」メソッドをこう書き換えました~
(赤字の部分が追加した箇所です~)

public function delete($id = null)
{
    $post = $this->Posts->get($id);

    //画像があればリネームする
    if ($post->filepath != '' && file_exists($post->filepath)) {
        $filename = basename($post->filepath);
        $newfilepath = ".".DS."files".DS.$this->generateRandomString()."_____".$filename;
        rename($post->filepath, $newfilepath);
    }


    //削除フラグを立てる
    $post->delete_flag = 1;

    if ($this->Posts->save($post)) {
        $this->Flash->success('投稿の削除に成功しました。');
    } else {
        $this->Flash->error('投稿の削除に失敗しました。');
    }
    return $this->redirect(['action' => 'index']);
}

テストした結果もバッチリでしたよ~

A子

最初、$this->generateRandomString()の「$this->」を付け忘れたせいでエラーが出ちゃってさ
ちょっと焦ったよ(苦笑)

ま、とりあえずテスト仕様書のほうは対応済みに変更しといたから…
(クリックすると別ウィンドウで開きます)

B美

生成AIの力を借りたとはいえ、なかなかやるじゃん

さて、それじゃいよいよ最後の作業ね
本番環境(我が社のWebサーバ)にこのWebアプリを設置デプロイするよ

C菜

FTPでアップロードするのでしょうか~?

A子

えふてぃーぴー?
…って何なのさ

B美

Fileファイル Transferトランスファー Protocolプロトコルの頭文字を並べたもので、ファイルを転送するためのプロトコル名であり、サービス名でもあるわ

あ、でもうちのサーバって、FTPサーバは稼働させてないのよ

C菜

えっと、それじゃHTTPでアップロードですか~?

B美

HTTPってのは、Hyperハイパー Textテキスト Transferトランスファー Protocolプロトコルの頭文字を並べたもので、Webのプロトコルね

もちろんHTTP(またはHTTPS)でもファイルのアップロードはできるんだけど、一度にアップできるファイル数やファイルサイズに制限がかかるから、こういう作業には向いてないのよね

A子

もったいぶらないで、早く結論を言いなさいよ

B美

我が社のWebサーバ上ではSSHエスエスエイチサーバを動かしているから、それを使ってファイルをアップロードしましょう
(いわゆるSCPエスシーピーね)

A子

また謎用語が次々と…(苦笑)

いや、ちょっと待って
SSHってのはなんか聞き覚えがあるような?

C菜

一番最初、Linuxをインストールしたときに出てきました~
(開発環境構築編①を参照)

A子

あー、あったね
(無視してたけど…)

B美

SSHとはSecureセキュア Shellシェルの略で、サーバを安全にリモート操作するための仕組みよ
(CUI操作しかできないけどね)

SCPというのはSecureセキュア Copyコピー Protocolプロトコルの頭文字をとったもので、SSHを利用してファイルを転送するプロトコルのことよ

C菜

CUI操作ということは、「MATE端末」みたいな感じですか~?

B美

まさにその通り!

あ、SSHサーバって、この開発環境にはインストールしただけで、特に設定作業なんかはしなかったけどさー
(インターネット上に公開する)外部のサーバ上で使う場合は、必ず次の2点を設定するようにね

秘密鍵を設定すること
②ポート番号を22以外にすること

SSHってユーザ名とパスワードでログインするんだけど、総当たり攻撃ブルートフォースアタックなんかでパスワードを破られちゃう可能性もあるからね
(秘密鍵を設定しておけば、その鍵を盗まれない限り絶対にアクセスできないのよ)

あと、22番ポートを開いておくと、やたらめったら不正アクセスしようとする奴らがやってくるからね(特に海外から)
(それがめっちゃウザイ(笑))

C菜

難しそうです~

A子

いや、別に私たちがやる必要は無いよね?

あくまでもサーバ管理者に対する注意事項でしょ?

B美

もちろんよ
ただ、SSHコマンドやSCPコマンドを使用する際、秘密鍵を指定したり、ポート番号を指定しないといけないってことを言いたかっただけ…

というわけで、これが秘密鍵となるファイルよ
USBメモリにコピーしといたから、あなたたちのPCにコピーしておいてね

C菜

分かりました~

あ、でもコピーする先のディレクトリはどこでも良いんですか~?

B美

良い質問ね

あなたたちのユーザホームの中に隠しディレクトリである「.ssh」というのがあるから、その中にコピーしてね
(メニューの「表示」→「隠しファイルを表示する」を選択)

あと、コピーしたファイルのパーミッションを「600」に変更すること



A子

パーミッションってアクセス権のことだっけ?

それってコマンド操作で設定するの?

B美

そのほうが(多分)簡単よ
MATE端末」を開いて、こう入力してね

cd .ssh[Enter]
chmod 600 sakura.pem[Enter]

あ、鍵ファイルのファイル名が「sakura.pem」の場合であって、ファイル名を変更しているならそのファイル名を指定するようにしてね

C菜

できました~

確認は

ls -l[Enter]

で良いですか~?

B美

その通り!
鍵ファイルの左端の表示が「-rw-------」となっていたらOKよ

B美

それじゃ我が社のVPSサーバにリモート接続してみましょうか

あ、パスワード(パスフレーズ)を聞かれたら「xxxxxxxx」と入力してね
(「xxxxxxxx」はもちろん伏字です)

cd[Enter]
ssh -i .ssh/sakura.pem -p nnnn xxxx@friction-river.jp[Enter]

「-i」オプションは秘密鍵指定、「-p」オプションはポート番号指定よ(指定しなければ、デフォルトの22番ポートとなります)
(「nnnn」の箇所については本来数字ですが、当然秘密です)

あ、接続先については「ユーザ名@ドメイン名」という形で指定するからね
(上記の「xxxx」の部分はユーザ名ですが、伏字にしています)

A子

こんなに簡単に接続できちゃうんだ…

なんか怖いね

C菜

これまで「MATE端末」を使って、CUI操作をある程度やってきた意味が分かりました~

SSH接続のためだったんですね~?

B美

そのあたりの意図があったことについては否定しないわ

コマンド操作(CUI操作)というのは、Web系プログラマにとっては必須知識だからね
(データベースを作ったり、操作したりもCUIで行うしね)

おっと、接続確認できたら

exit[Enter]

を叩いて、すぐにログアウトしておいてね
(使わないのに、接続しっぱなしはダメよ)

A子

んじゃ、次はファイルのアップロードね

やっぱりコマンドでやるの?

B美

その方法(scpコマンド)もあるんだけど、ここではGUIツールをインストールしてみましょう
MATE端末」を開いて、rootになったあと、aptでインストールしてね

su -[Enter]
apt install -y gftp[Enter]



C菜

メニューの中に「アプリケーション」→「インターネット」→「gFTP」というのが追加されました~

B美

gFTP」を起動すると、以下の画面になるわ

ちなみに「このランチャをデスクトップへ追加」を選んで、デスクトップ上にショートカットを作っておいても良いかもね
(今後よく使うことになるから…)

A子

くっ、メニューが全部英語だよ

B美

それは仕方ないって…(苦笑)

で、まずは下準備だけど、上にあるメニューの「gFTP」→「Preferences...」を選択します
タブの右端「SSH」をクリックしてから二ヶ所の入力欄を埋めてね

SSHプログラム名:ssh
SSH引数:-i .ssh/sakura.pem



C菜

ここに入力する値って、さっきSSH接続したときに指定したパラメータなんですね~

んで、最後に「OK」ボタンを押せば良いんですよね~?

A子

みたいだねー

あとはメイン画面の上にある「Host」「ポート番号」「User」「Pass」の欄に入力していけば良いのかな?

B美

正解よ

Host:friction-river.jp(ドメイン名またはIPアドレスを入力)
ポート番号:nnnn(伏字です)
User:xxxx(ユーザ名…伏字です)
Pass:xxxxxxxx(パスワード…伏字です)
Passの右側:SSH2(FTPではありません)

を入力した後、Hostの左側にあるアイコンをクリックしてね
(このアイコンによって接続・切断を行います)

C菜

右側に一覧が出ました~

これって、左側がこのPC内の一覧で、右側がVPSサーバ内の一覧なんですよね~?

B美

そういうこと

接続確認できたら、Hostの左側にあるアイコンをもう一度クリックしてね
(接続が切れるから…)

A子

んじゃ、さっそくアップロードしますかー

B美

いいえ、まだよ
ちょっと準備してからね

MATE端末」を開いて、次のコマンドを実行します

mysqldump -u root -p bbsdb > bbsdb_backup.sql[Enter]

これはデータベースをバックアップするためのコマンドよ

A子

どうでもいいテストデータしか入ってないのに、バックアップなんて必要ないんじゃ?

B美

欲しいのはテーブル作成のSQL文なのよ

同じディレクトリ内に「bbsdb_backup.sql」というファイルができてるはずだから、それをエディターで開いてね

B美

このファイルの中にある「CREATE TABLE」文以外を全て削除します
で、そのあと、一番上に次の二行を追加してね

create database bbsdb;

use bbsdb;

あ、各テーブル定義の末尾にある「AUTO_INCREMENT=○○」という箇所は削除してちょうだい
全て終わったら「保存」(上書きでOK)してね


C菜

作ったテーブルは二つ(「posts」と「logs」)だけだったはずですけど~?

B美

CAPTCHAキャプチャ機構を導入する際、migrationsコマンドを実行したのを憶えてる?

あれによってテーブルが二つほど自動作成されたってわけ
(本番環境で同じことをやっても良いんだけど、面倒くさいからここに全部まとめちゃえ…って意図です)

A子

なるほど、そういうことか

さて、これでもう準備はOK?

B美

いいえ、もう一つあるわ
MATE端末」上で以下のコマンドを実行してね

cd html/bbsapp[Enter]
bin/cake cache clear_all[Enter]

これにより「bbsapp/tmp」ディレクトリ内に作られたキャッシュファイルが全て削除されるの

C菜

なぜわざわざ削除するのでしょうか~?

B美

それはキャッシュファイルの所有者オーナーWebサーバ(www-data)だからよ

削除せずにアップロードした場合、本番環境側でわざわざchownチェンジオーナーコマンドを実行して、所有者オーナーをWebサーバ(www-data)にしなきゃいけなくなるからね
(ただ単に面倒くさい…ってだけ(苦笑))

さて、これで準備完了よ

A子

よし!
アップロードしよう!

B美

あ、我が社のVPSサーバのドキュメントルートは「/home/xxxx/html」だから、そこに「bbsapp」ディレクトリを丸ごとアップロードしてね
(ユーザ名である「xxxx」の箇所は伏字です)

①右側では「html」ディレクトリをダブルクリックして、カレントを「/home/xxxx/html」にする
②左側で「bbsapp」ディレクトリを選択してから、真ん中にある「→」アイコンをクリックする

という手順よ

C菜

結構時間がかかりましたけど、できました~

あ、さっき作った「bbsdb_backup.sql」もアップロードするんですよね~?

B美

もちろん!

ただし「/home/xxxx/html」ではなく、一階層上の「/home/xxxx」ディレクトリにアップしてね
(ユーザ名である「xxxx」の箇所は伏字です)

おっと、ディレクトリ階層を一段上がるには、「..」をダブルクリックすれば良いから…

B美

アップロードが全て終われば、いったん接続を切って(切断して)おいてちょうだい

んじゃ次は、SSH接続でコマンド操作をやります
さっきやったから覚えてるわよね?

C菜

MATE端末」を開いてから

ssh -i .ssh/sakura.pem -p nnnn xxxx@friction-river.jp[Enter]

でしたよね~?
(「nnnn」と「xxxx」の箇所は伏字です~)

A子

よ、よく覚えてるわね…(汗)

C菜

実はキーボードの上矢印キー「↑」を複数回押すと、過去に入力したコマンドが順番に出るんですよ~

何気に便利です~

A子

えっ?
まじか…

…って、ほんとだ
まじで便利じゃん

B美

教えていないのに、よく気付いたわね

これはシェルの履歴機能ってやつで、知っておくとめっちゃ便利なのよね
(まぁ、コマンドを打ち込むこと自体が練習になるから、あえて教えなかったんだけど…(苦笑))

ま、それはともかく…
次はデータベースの作成よ

mysql -u root -p < bbsdb_backup.sql[Enter]

を実行してね

あ、VPSサーバ上で動いているデータベース(MariaDB)のrootパスワードは「xxxxxxxx」よ
(「xxxxxxxx」の箇所は伏字です)

C菜

えっと~

データベースのrootパスワードがそれってことは、「bbsapp/config/app_local.php」についても書き換えなきゃいけないんじゃ~?

B美

当然!

ほかには「bbsapp/config/const.php」の中の管理者パスワードについても、複雑で推測されにくいものに変更したほうが良いかもね
(別に強制じゃないけど…)

あ、ファイルの編集については「nano」でも「vi」でも好きなエディターソフトを使ってね
(「vi」の説明をやってないけど…)

A子

これで完了?

もうブラウザからアクセスしても良いの?

B美

いいえ、まだよ
最も重要なパーミッション設定が残ってるわ

…と言いたいところなんだけど、実はパーミッション設定は不要なの
なぜならアップロード時にパーミッション設定ごと、VPSサーバ側にコピーしたからね
(これがLinux環境で開発して、そのままLinuxサーバへアップロードするときのメリットね)

ただし、これだけはやっておいて

cd[Enter]

cd html/bbsapp/logs[Enter]
ls[Enter]
rm -f error.log[Enter]

cd ../webroot/files[Enter]
ls[Enter]
rm -f *[Enter]

もともと「error.log」の所有者オーナーはWebサーバ(www-data)なんだけど、アップロード時には一般ユーザに変更されちゃうの
(ファイルを削除しちゃえば、新たに「error.log」が作られるときの所有者オーナーは自動的にWebサーバになるからね)

あと、開発環境でテスト投稿した画像ファイルについても、全て削除しておかないといけないわ
(「rm」はリムーブの略で、ファイルを削除するコマンドよ)

A子

わざわざ「ls」でファイル一覧を表示してるのは何でよ?

B美

「rm」コマンドって、めっちゃ危険だからね

特に「rm -f *」を叩くと、問答無用でそのディレクトリ内の全てのファイルを削除するわよ
(しかもゴミ箱行きじゃなく、完全に削除されちゃう)

だから「rm」するときは必ず「ls」で事前確認するように!

C菜

Linux to Linuxの場合は分かりましたけど~

もしもWindowsからアップロードするときは、どうやるんですか~?

B美

もしもSCPでアップロードするのなら、Windowsアプリとしては「WinSCP」がお勧めね

ただし、パーミッション設定については、別途手動で行わないといけなくなるの
その場合、どこを変更するのかを一応書いておくわね
(右側の数値がパーミッションの値)

①bbsapp/bin/cake → 755
②bbsapp/logs → 757
③bbsapp/tmp → 757
④bbsapp/tmp/cache → 757
⑤bbsapp/tmp/cache/models → 757
⑥bbsapp/tmp/cache/persistent → 757
⑦bbsapp/tmp/cache/views → 757
⑧bbsapp/tmp/sessions → 757
⑨bbsapp/tmp/test → 757
⑩bbsapp/webroot/files → 757

A子

うへぇー

面倒くさそう…(苦笑)

B美

一回やれば終わりだし、別にそれほど面倒でもないけどね

さて、それじゃブラウザからアクセスしてみましょうか
URLは「https://friction-river.jp/bbsapp」よ
(クリックすると別ウィンドウで開きます)

C菜

新規に投稿してみるです~



A子

うん、バッチリじゃん

画像をクリックすると、別ウィンドウにオリジナルサイズで表示できるのも確認したよ

C菜

もう一度(この本番環境で)システムテストをやり直したほうが良いでしょうか~?

B美

もちろんよ!
それを「運用テスト」と呼びます

データベースやパーミッション設定関連で不具合が出る可能性もあるからね
設置デプロイ後は、必ず「運用テスト」を実施するように!



A子

こんな感じで「運用テスト」のテスト仕様書を作ってみたよ
(クリックすると別ウィンドウで開きます)

あ、No.33~No.35のテスト項目を追加したからね

てかさぁ
テストのために投稿や削除を繰り返すと、データベースがなんか汚くなっていくんだけど…(苦笑)

特に「投稿番号」がどんどん大きくなっていっちゃうのは、なんとかならないの?

B美

これまで学んだ知識の応用でできるから、あなたたちで考えてみなさい

ヒントとしては「データベースの削除」は、「drop database (データベース名);[Enter]」よ

C菜

テストで汚くなったデータベースをまっさらの新品にするには、一度削除してから新規作成すれば良いんじゃないでしょうか~?

A子

あ、そうか!
だとしたら、本番環境にSSH接続してから

mysql -u root -p[Enter]
のあと

drop database bbsdb;[Enter]
quit;[Enter]
を実行して

mysql -u root -p < bbsdb_backup.sql[Enter]
をもう一度実行すれば良いんじゃない?

C菜

あと、投稿した画像ファイルを削除するために、VPSサーバにSSH接続した状態で

cd html/bbsapp/webroot/files[Enter]
ls[Enter]
rm -f *[Enter]

で、どうでしょう~?

B美

二人とも正解よ!

もちろんほかのやり方もあるんだけど、その手順が一番シンプルでしょうね



B美

さて、これで一通りの知識は伝授したつもりよ
あとは経験を積み重ねていくだけだから、積極的に色々なWebアプリケーションを作っていきなさいね
経験こそがプログラマにとっての財産だから…)

C菜

了解です~

A子

うん、まぁまぁ面白かったよ

「こういうアプリが欲しいな」と思ったときに、(無ければ)自分で作れる…ってのは良いよね

C菜

ですです~