ドットインストールのレッスン、「PHPで作る投票システム (全13回)」の備忘録です。復習用にお使いください。
最後のGoogle Chart Toolsについては触れておりません。ドットインストールの方でレッスンが用意されています。覚えることでもないので、さっと確認して使えます。
デベロッパーサイトの英語が読めるようになったら、Google Chart Toolsに関しての記事を書きたいなと思っています。
USE文とユニークキー #02
GRANT文
GRANT文の基本書式は次の通り。
GRANT '権限' ON 'データベース名.テーブルト名' TO 'ユーザー名@ホスト名';
そして、今回のレッスンで使われていたもの。
grant all on dotinstall_poll_php.* to dbuser@localhost identified by '********';
これはdotinstall_poll_phpテーブルに対する、すべての権限(SELECT,UPDATEなど)dbuser@localhostに与えています。そして、このユーザーのパスワードを'********'に設定しています。
権限は、ONの次で4つの有効範囲をできます。
// グローバルレベル:
GRANT 権限 ON *.* TO user;
// データベースレベル:
GRANT 権限 ON db_name.* TO user;
// テーブルレベル:
GRANT 権限 ON db_name.table_name TO user;
// カラムレベル:
GRANT 権限 (カラム1, カラム2, ...) ON db_name.table_name TO user;
こちらによいサンプルが紹介されています。
また、この記事でもGRANT文は取り上げました。
USE文
「USE データベース名」でデータベースに接続します。一度接続すれば、FROMでテーブルだけ指定すればよくなります。データベース名を省略できるようになりますが、省略しなくてもよいです。
ユニークキー
ユニークキーは値が重複することはできません。プライマリキーとは違いNULLを格納できます。また、NULLの値だけ重複することができます。
ここで、今回のデータベースの全体図を把握しておきましょう。
カラム | 内容 | 補足 |
---|---|---|
id | 自動連番 | |
answer | 回答 | 将来的な拡張のため文字列 |
remote_addr | 回答者のIPアドレス | |
user_agent | ブラウザの情報 | |
answer_date | 回答日 | |
modified | 更新日 | |
unique_answer | IP * ブラウザ * 回答日 | 1日に1回という制限 |
セッションの有効範囲を理解する #03
PHPのデータベース操作についてですが、こちらで専用の記事を作っています。図を用意していますので、ご覧ください。
この章では1つの関数だけ確認しておきましょう。
session_set_cookie_params(有効期限(秒数), 動作するパス)
この関数の引数は最大5つです。詳しくはリンク先のPHPマニュアルを御覧ください。
session_set_cookie_params(0, '/poll_php/');
今回のレッスンでは有効期限は0、つまりブラウザが閉じられるまでで、有効範囲はpoll_phpというディレクトリ以下となっています。また、パスではなくドメインで有効範囲を指定する場合は3つ目の引数で指定します。
この関数の使用注意としてはsession_start()を呼び出す前にsession_set_cookie_paramsを呼び出しておく必要があります。
余談ですが、PHPマニュアルを見ると第1引数の有効期限が英語だとlifetimeという表現になっています。「命の時間」ですか。「生きている時間」、つまり「有効期限」となっているのですね。英語はこういうところが面白い表現だなと思います。
関数と設定のファイル分け #04
PHPのデータベース操作についてですが、こちらで専用の記事を作っています。図を用意していますので、ご覧ください。
関数定義についてですが、h()はPHPではおなじみのhtmlspecialchars()の省略形です。そして、もう1つのconnectDb()。これはPDOでデータベース接続してPDOオブジェクトを返します。
私はdb.phpというファイルにデータベースの接続を行うまでの処理をまとめていましたが、データベース接続だけ関数定義にして、定数は定数でファイルを分けた方がいいのかなと思いました。
<?php
/*** db.php ***/
define('DB_HOST', 'localhost');
define('DB_NAME', 'データベース名');
define('DB_USER', 'ユーザー名');
define('DB_PASSWORD', 'パスワード');
// 文字化け対策
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND=-->"SET CHARACTER SET 'utf8'");
error_reporting(E_ALL & ~E_NOTICE);
// データベースの接続
try {
$dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASSWORD, $options);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
exit;
}
?>
idで選択されものを判別 #05
画面を図解。
見栄えの変化はCSSで定義しておく #06
クリックイベントハンドラの中のthisはクリックされたものを指します。今回はクラスcandidateに対してクリックイベントを設定していますので、そのクラスが付けられている画像をthisの対象となります。
今回のクリックイベントの内容は以下の通りです。
- candidateクラスの付いてるものからselectedクラスを取り除く。
- クリックされたものにselectedクラスをつける。
- IDanswer、つまりテキストフィールドの値を画像のid値に書き換える。
なぜ、1についての処理ですが、何故candidateクラス全体にremoveClass()を行うのかと言うと、
画像がクリックする度に前にクリックされた画像にremoveClass()を行おうとすると、クリックされた履歴を管理しないといけないですし、すべての画像のクラスを取り除いたほうが安全だからです。保証ですね。
CSRFで他のサイトからのデータ送信を防ぐ #07
CSRFって何?という方がいると思いますので、以前の解説記事を貼っておきます。
今回はちゃんと自分の指定したformからの送信を受け付けるように設定しています。そのためにトークンを使っています。実際のサービスだと、ネット銀行やオンラインゲームとかのワンタイムパスワードみたいなものですね。
他の例をあげれば、サイトにログインするときに「画像に出ている英数字を入力してください」と出ますが、あれもCSRF対策の一種です。その場でランダムな値を発生させてそれをパスワードとしています。このパスワードがちゃんとこのサイトからデータを受診したという証明になります。CSRF対策がないと他のサイトからデータを送信され、それが悪意のあるプログラムなんかだったりしたら涙目です。例えば、リンクにプログラムを忍ばせておくとかですね。
in_arrayで回答と正解かを判定する #08
if (!in_array($_POST['answer'], array(1, 2, 3, 4))) {}
このコードは1~4にanswerが含まれているかを判定します。そして、その否定ですから、1~4にanswerが含まれていない、つまり答えが1~4ではない時にこのif文は実行されます。
excute()の戻り値で投票制限を判断 #09-10
insert文で「:~」が使われていますが、これはパラメータマーカを指定しています。変数みたいなもんです。:(コロン)を使って、先に宣言だけしておいて、後から代入できるという便利なものです。
SQL文を実行する時にパラメータマーカを指定する場合は、query()ではなくprepareを使います。そして、bindParam()パラメータマーカに値をセットしてexcute()でSQLを実行します。excute()の引数でパラメータマーカを指定もできます。
excute()はパラメータマーカが異常であると、失敗したとしてfalseを返します。成功した場合はtrueを返します。なので、これを利用して1日1回の投稿制限をかけています。パラメータマーカにユニークキーが含まれているので、値が重複できません。(この場合の値とはユーザーを識別する情報)
if ($stmt->execute($params)) {
$msg = "投票ありがとうございました!";
} else {
$err = "投票は1日1回までです!";
}