こんにちは!
今回は、PHPで『月5万円』稼ぐためのロードマップ第12弾ということで、2つ目の課題である「クーポン機能の実装」のパート3です!
前回の第11弾ではPHPで「クーポン機能」を実装するための、見た目・枠組みなどの部分を作成していきました。
今回は「クーポン機能」の実装のパート3となっていますので、まだこれまでの記事を読んでないと言う方は先に第10弾のほうから見てもらった方がいいと思います!
- クーポン機能を実装してみたい
- セキュリティ対策も少し興味ある!
- 第11弾まで見てくれた人
さて、「クーポン機能」の実装を通じた、PHPでの「セキュリティ対策」について勉強していきましょう!
Contents
なぜセキュリティ対策が必要なの?
まず、そもそもセキュリティ対策がなぜ必要なのかを知るところから始めましょう。
または、
と思われた方もいるんじゃないでしょうか?
ですが、そのWebアプリにも以下のような危険性が潜んでいることも知っていますか?
- 個人情報の漏洩
- 重要情報の紛失・破損
- ユーザ端末にマルウェアが仕込まれる
- なりすましによってサービスが悪用される
- 開発・運営者のイメージ・信用の損失、訴訟のリスク
マルウェア … 不正で有害な動作をする悪意を持って作られたソフトウェア。
もちろんこれらのリスクに対して、月5万円を稼ぐことを目標にPHPを勉強し出した皆さんが、全面的に責任を負うことはありません。
しかし、PHPでプログラミングを勉強していく上で、「当たり前」レベルのセキュリティ対策だけでもできるだけで大きな効果があるので、しておいて損はありませんし、エンジニアとしての評価もグンッと上がります!
セキュリティ対策って言われても何したらいいの?
急に「セキュリティ対策」なんて言われても、「え?家をアル〇ックに警備してもらうの!?」って感じですよね笑
ここでは、Webアプリ開発をする上で、セキュリティ対策をどうすればいいかというイメージを掴んでもらいたいと思います。
まず、「脆弱性」という単語を知ることが大切になってきます。
脆弱性とは、以下のような意味があります。
脆弱性(ぜいじゃくせい)とは、コンピュータのOSやソフトウェアにおいて、プログラムの不具合や設計上のミスが原因となって発生した情報セキュリティ上の欠陥のことを言います。脆弱性は、セキュリティホールとも呼ばれます。脆弱性が残された状態でコンピュータを利用していると、不正アクセスに利用されたり、ウイルスに感染したりする危険性があります。
なんとなくてもイメージ出来ましたでしょうか。
例えると、家の鍵が壊れていたり、どんな鍵でも開いてしまう鍵なら、簡単に侵入されてしまいますよね。
そんなイメージです!
では、私たちが行っているWebアプリ開発においては、どんな脆弱性を突いた攻撃が考えられるのでしょうか?
以下に数ある攻撃手段のうち、被害の大きい2つの攻撃手法を挙げます。
- XSS(クロスサイトスクリプティング)
- SQLインジェクション
この後、実際にセキュリティ対策を行っていくのですが、この2つの単語は何回も登場することとなります。
以下のページで、解説しているので、読み進める前に一度確認しておいてください!
【近日公開】
ここから、前回「クーポン機能」を実装するために、作ったファイルに実際にセキュリティ対策を施していきましょう!
セキュリティ対策のために脆弱性を少なくすることが大切!
「クーポン機能」にセキュリティ対策を施そう!
今回、PHPでセキュリティ対策を施していくファイルは、この2つです!
- data.php
- util.php
という風に思われている方がいるかもしれませんが、ここで施していくセキュリティ対策とは、PHPのプログラムの書き方を少し工夫するだけで、大丈夫であるようなモノなので安心してください!
しかも、「クーポン機能」だけに有効なセキュリティ対策ではなく、今後様々なWebアプリ開発をしていく中で、汎用的に使えるものなので一度しっかりと習得しておきましょう!
data.phpでのセキュリティ対策
data.phpの役割を解説
重要な値を直接送らない。
って感じですよね、失礼しました。
上記の「重要な値を直接送らない」というのは、ここで行っていくセキュリティ対策のテーマです!
具体的にどういうことか、図を使って説明します。今回、クーポン機能の実装ということで、重要な値として「価格」と「割引率」を考えます!
左のファイルにある「商品の価格」や、入力したクーポンコードに対応する「割引率」などの情報を、右のファイルに渡すという形です。
この時、画像内の「悪魔みたいな人」目線で、どうすれば脆弱性を突けるか、つまり悪さができるか考えてみましょう。
- 左ファイルに情報が入力される
- その値が渡される
- 右ファイルが情報を受け取る
- 情報を表示する
実はここで、②と③の間が脆弱性となってきます。
②と③の間は、POSTと呼ばれる処理が行われていることは、第1弾から「PHPで5万円稼ぐためのロードマップ」を勉強してきた人ならすんなり理解できると思います。
このPOST中に、悪魔みたいな人は悪さを仕掛けてきます。
数値を改ざんしようとするのです。
画像を見ると、改ざんされた金額と割引率が右ファイルに渡り、10,000円だったものが、たったの100円で購入されていることが分かりますね。
これでは困ります…。
そこで、「重要な値を直接送らない」という対策を取ります。

何やら、真ん中に3つ目のファイルが用意されましたね。
実はこれが今回実装するファイルの「data.php」なのです!
では、ひとまず画像内の矢印の番号と以下の説明を照らし合わせて、処理の内容を理解してください!
- 左ファイルに入力された商品ID(2a9E)と割引コード(R4K)を、右ファイルに渡す。
- 商品IDと割引コードに対応する値を、「data.php」から探す。
- 見つけた値を右ファイルが表示する。
ここでこう思った人はいませんか?
実は、そうではないのです!
この後一緒にプログラムを書いていくときに説明するので、今は対応表作ってそこから値取り出せばいいんだというイメージで大丈夫です!
data.phpの実装
さて、実際にプログラムを書いていきましょう!
第10弾から「クーポンコードの実装」を始めてきたわけですが、現時点では「data.php」は空の状態だと思います。
ここで、もしこの第12弾から見てくれている人がいれば、以下の第10弾に戻って、ファイルの作成であったりといった下準備を終わらせておきましょう。

まず、「クーポンコードと割引率との対応表」を作るために、以下のようにリストを定義しましょう。
1 2 3 4 5 6 |
<?php //クーポンコードと割引率との対応 $couponList = ["5Q32i" => 0.80, "gA22a "=>0.85, "k0ja2"=>0.90, "gjl4a"=>0.95, "gr1m9"=>0.95]; ?> |
$couponListという配列を定義し、その配列の中身がクーポンコードと割引率の対応表となっています。(「5Q32i 」が入力されたら「0.80」を返すなど)
また、クーポンコードは私のテキトーな感覚で設定しているだけなので、好きな名前で好きな個数用意してもらっても大丈夫です。
ここで、配列に「A => B」という表記を用いたことがないかもしれませんが、これは「$couponList[A]がBとなる」というような意味になります。例えば「echo $couponList[“5Q32i”]; と入力すると0.80が表示されるといった感じです。
次に、「クーポンコードに対応する割引率を返す」関数を作成していきます。この関数を使うことで、先ほどの図の②と③の矢印の機能を実現します。
関数名は「getCouponRate」としていますが、もちろん名前は何でも構いません。
ただし、他の箇所でも同じ名前を使うことに注意。
1 2 3 4 5 6 7 8 9 10 |
<?php //クーポンコードと割引率との対応 $couponList = ["5Q32i" => 0.80, "gA22a "=>0.85, "k0ja2"=>0.90, "gjl4a"=>0.95, "gr1m9"=>0.95]; //クーポンコードで割引率を調べて値を返す function getCouponRate($code){ } ?> |
関数が定義できたので、以下の手順で関数を作成していきます。
- $couponListをグローバル変数として関数内で定義する
- array_key_exists関数を使って、クーポンコードが対応表の中にあるかチェック(無ければNULLを返す)
- クーポンコードが対応表に記載されていればその割引率を、記載されていなければ、NULLを最終的に返す。
- (補足:この関数を使った側は、返された値がNULLならエラー文を表示するようにする → 第13弾)
以上の手順を関数内に記述していくと、以下のようになると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php //クーポンコードと割引率との対応 $couponList = ["5Q32i" => 0.80, "gA22a "=>0.85, "k0ja2"=>0.90, "gjl4a"=>0.95, "gr1m9"=>0.95]; //クーポンコードで割引率を調べて値を返す function getCouponRate($code){ //該当するクーポンコードがあるかどうかチェックする global $couponList; //array_key_exist(a,b)はaがbにあるかどうかを判別する関数(TRUE or False) $isCouponCode = array_key_exists($code, $couponList); if($isCouponCode){ return $couponList[$code]; //割引率を返す } else{ //見つからなかったらNULLを返す return NULL; } } ?> |
上記の手順の中で分からなかったところはありましたか?
「グローバル変数」だったり、「array_key_exists関数」などが分からなくなるポイントでしょうか。そういうときはどうするのか第3弾で、勉強しましたよね!
手元にある書籍を辞書代わりに、調べてみましょう!
って方がいたら、お問い合わせください!
PHPの世界では「$」マークが付いているモノは、関数・変数などと呼ばれる。
これらは自由に名前を付けることができるので、例と同じ名前にする必要はない。
ただし、他の箇所でその関数・変数を使うときも、付けた名前を使うこと。
これで、「data.php」の実装は終了です!
実際にこの「data.php」を経由して、値を得るのかについては次弾から解説していきますので、ひとまず「data.php」の構造が分かれば、大丈夫です!
util.phpでのセキュリティ対策
util.phpの役割を解説
「util.php」の役割は、「XSSとSQLインジェクションを防ぐ」ことです。
この2つの攻撃から、ファイルを守るために、以下の2つを実装していきます!
- HTMLエスケープ
- 文字エンコードの一致
本当に申し訳ありません笑
簡単に言えば、HTMLエスケープとは、入力フォームに「<, &, “」といったHTMLで使う半角記号を打たれることで、開発者が意図しない表示をアプリにさせてしまうことです。
また、文字エンコードの一致とは、これまた簡単に言うと、文字コード(UTF-8など)が別の文字コードに変換されると、意図しない意味に変化してしまうことを防ぐために行います。
具体的な例も含めて以下のページで、XSSなどと共に説明しているので、そこで理解を深めてほしいと思います!
【近日公開】
という方は、今回はひとまず「HTMLエスケープと文字エンコードの一致のやり方と、使用シーン」だけを覚えておくという風にしましょう!
理論を理解して使えるのが理想ですが、理論を理解せずとも使えるだけでも効果は少なからずあります!
util.phpを実装する
それでは、「util.php」にHTMLエスケープと文字エンコードの一致のためのプログラムを「util.php」に実装していきましょう!
まず、「util.php」では2つの関数を実装していきます。
何のための関数か分かりますか?
- HTMLエスケープのための関数
- 文字エンコードを一致させる関数
この2つです。そりゃそうだろうよって感じですね笑
ここではその2つの関数にそれぞれ「es」、「cken」という関数名を付けます。
まずは、関数「es」から実装していきましょう。
関数「es」の実装
HTMLエスケープを行う関数は「echo」のようにPHPに元からある関数である「htmlspecialchars」を使用します!
そう思われた方、たぶんいらっしゃいますよね。
どういうことかと言いますと、基本的にHTMLエスケープは「htmlspecialchars」で行うことが可能なのですが、「htmlspecialchars」は、配列を一気にHTMLエスケープすることはできないのです。
そのため、配列の形でいろいろな値が渡されたときでも、一気にHTMLエスケープできたら便利ですよね?
その機能を持つのが関数「es」なのです!
まずは、以下のようにソースコードを記述してください。説明は後述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php function es($data){ //$dataが配列のとき if(is_array($data)){ //再帰呼出し return array_map(__METHOD__, $data); } else{ //HTMLエスケープを行う return htmlspecialchars($data, ENT_QUOTES, 'utf-8'); } } ?> |
どういう処理が行われているか説明していきますね。あくまで「この関数ってなんの関数だっけ?」といった、調べられるところの説明は省略させてもらっているので、その都度調べてください!
3行目で、関数「es」を定義し、その後この関数に渡された引数の$dataが配列かどうかによって条件分岐をさせています。このとき配列かどうかを判断するために関数「is_array」を使用しています。
そして、$dataが配列であれば、関数「array_map」を呼び出し、そうでなければ関数「htmlspecialchars」を実行してHTMLエスケープをしていくという処理になります。
という人も多いと思うので、そこだけ補足しておきます。
array_map()はarray_map(関数A, 配列A)の形で使用され、意味としては、配列の各要素に1つ目の引数「関数A」に、2つ目の引数である「配列A」の各要素(ここ重要)を、ひとつずつ渡して、関数Aによって処理された各要素の配列を戻り値として返します。

詳しくは、第3弾で紹介した「詳細!PHP 7+MySQL 入門ノート」の204ページに詳しく書かれていますので、参考にしてください。
また、ここでもう一つ厄介なモノとして「__METHOD__」があると思います!上記の書籍でも取り上げられているため、もう習得済って方は読み飛ばしてください!
「__METHOD__」は再帰呼出しをするために使用される特殊な定数です。ここでは、es()の実行中に再び、es()を呼び出すということをしていますね?(array_mapの説明画像で言うところの、「関数A」がes()にあたるため)このように、ある関数が自分を呼び出すことを、再帰呼出しといい、「__METHOD__」は、今回のような使い方をすることで再帰呼出しをすることができます。
関数「cken」の実装
関数「es」が、関数「htmlspacialchars」をうまく使うことで、HTMLエスケープを行っていたように、関数「cken」では関数「mb_check_encode」を使って文字エンコードの一致をさせていきます。
この関数「mb_check_encode」は値を渡すことで、文字エンコードをチェックしてくれる関数です。
関数「cken」は次のような処理手順で実装していきます。
- 関数ckenに、文字エンコードをチェックしたいデータを渡す
- 値を$valueという変数に格納していく
- このときデータが配列の場合、空白を削除して1つの文字列として変数$valueに格納する
- $valueをmb_check_encodeで文字エンコードをチェックする
- 文字エンコードが一致しない場合falseを返す。(一致はtrue)
それでは「util.php」にソースコードを記述していきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php function cken(array $data){ $result = true; foreach($data as $key => $value){ if(is_array($value)){ //含まれている値が配列のとき文字列に連結する $value = implode("", $value); } if(!mb_check_encoding($value)){ //文字エンコードが一致しないとき $result = false; //foreachでの査定を終わらせる break; } } return $result; } ?> |
まず、2行目で関数「cken」に、変数$dataを渡します。
その後、3行目で変数$resultを定義し、その値をtrueとしています。この関数の最後までこの$resultがtrueのままで居続けることができれば、文字エンコードは一致しているというような判断をするために、定義しています。
その後、繰り返しのforeach文で配列から、値を順々に取り出して、変数$valueに格納していっているわけですが、格納するときに、何やら「implode」という関数を使っていますね!
この関数「implode」が手順3で太字にしている「空白を削除して」の処理にあたります。
そして、文字エンコードが一致しているかどうかを確認したい値が格納された変数$valueを「mb_check_encode」でチェックして、文字エンコードが一致していれば、元々定義していた$resultはtrueのまま、一致していなければ、falseになる。
そういった処理内容となっています。
実装したセキュリティ対策のテスト
ここまでで作成した2つのファイル「data.php」と「util.php」ですが、実際にセキュリティ対策になってるの?とイメージし辛いところではありますよね。
特に「util.php」に関しては、
となっている人も多いと思います。
ここでは、その「util.php」がどういう機能を果たしてくれているのかテストしたいと思います。
関数es()のテスト
「util.php」内で実装した、関数esをテストするファイルを作成しました。作ってみたいという方は、以下のソースコードを参考に作ってみてください!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>「util.php」のテスト</title> </head> <body> <?php //-------------------------------- //関数esのテスト //-------------------------------- //util.phpの読み込み require_once("util.php"); //本来は入慮億フォームから入力されたものと仮定 $input1 = "<h1>フォームから入力された文字</h1>"; $input2 = es("<h1>フォームから入力された文字</h1>"); echo $input1; //処理なしで表示 echo $input2; //処理をしてから表示 ?> </body> </html> |
どういうテストかを説明しますね!
XSSについて解説しているページを見てくれた方なら、分かると思うのですが、セキュリティ対策として、入力フォームなどで、HTMLで使う記号(「<, “, ‘」など)を入力したときに、そのHTML記号に機能を持たせてはいけなくて、そのHTMLエスケープを行ってくれるのが関数「es」でしたね!
上のソースコードを見てほしいのですが、$input1、$input2はそれぞれ、入力フォームから打たれた文字を想定しています!
(テスト用に入力フォームとかを作るのが面倒だったことは内緒です…笑)
そして、$input1はそのまま表示、$input2はHTMLエスケープをして表示をしてみましょう!
この表示結果から分かる通り、そのまま表示した方は、HTMLの<h1>タグがそのまま機能してしまっていますよね。これが危険でXSSに繋がる脆弱性です。
一方、下の方は<h1>がそのまま文字として表示されていて、<h1>タグとしての機能を果たしていませんよね?つまり、関数esによってHTMLエスケープが行われたということです!
関数cken()のテスト
「util.php」内で実装した、関数esをテストするファイルを作成しました。作ってみたいという方は、以下のソースコードを参考に作ってみてください!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>「util.php」のテスト</title> </head> <body> <?php //-------------------------------- //関数ckenのテスト //-------------------------------- //util.phpの読み込み require_once("util.php"); $encoding = mb_internal_encoding(); echo "現在の利用環境のエンコードは", $encoding, "です。"; $string = "チェックする文字列"; $changed_string = mb_convert_encoding($string, 'Shift-JIS'); //$stringをShift-JISという文字コードに変換 if(cken([$changed_string])){ echo "文字エンコードは一致しました。"; } else { echo "文字エンコードが一致しません。"; } ?> </body> </html> |
文字エンコードというもの自体があまり馴染みのない言葉であるため、こちらの関数のほうが何をしているか分かりにくい面もあると思いますが、頑張って理解してください!
まず、新しく使用した関数から軽く説明しておきます。
mb_internal_encoding | 現在の利用環境課でのエンコードを表示 |
---|---|
mb_convert_encoding | 指定した文字列(1つ目の引数)を指定した文字コード(2つ目の引数)に変換 |
このテスト用のファイルの処理の流れとしては、以下のようになっています。
- 現在の利用環境でのエンコードを表示
- ある文字列($string)のエンコードを”Shift-JIS”というエンコードに変換
- 関数ckenを使って、$stringが利用環境でのエンコードと一致するかを確認
- もちろん②で違う文字コードに変換しているので、エンコードが一致しませんと表示される、はず。
PHPのバージョンによって、上手く表示されない場合があるため、コチラのサイトでテストしてみるがいい場合があります。
手順④の通り、「文字エンコードが一致しません。」と表示されれば、関数ckenは上手く実装されているということになります!
まとめ
今回は、「util.php」「data.php」を通して、PHPプログラミングで必須のセキュリティ対策を勉強しました!
もちろん、セキュリティ対策はセキュリティのプロがいるくらいですから、もっともっと専門的な深い内容のセキュリティ対策も数多くあります。
しかし、ここで学んだセキュリティ対策をするだけでも十分効果があるので、是非Webアプリ開発の際は実践してください!
ちなみに、今回作った「util.php」は、入力フォームを実装するときはだいたい必要になってくるので、使い回ししてくださいね!
次回の第13弾では、「クーポン機能」にPHPで機能を実装して完成に近づけていきましょう!
https://rural-blog.com/php-road13/
今回は、以上になります!質問や疑問点などございましたら、ぜひぜひ「お問い合わせ」の方からご連絡ください!Twitterも是非フォローよろしくお願いします!
その他、勉強法や就活、プログラミングに関する相談なども受け付けています!