LoginSignup
2
4

More than 5 years have passed since last update.

【ドットインストール】PHPで作る投票システムの解説

Posted at

完成図:投票システム

ドットインストールのレッスン、「PHPで作る投票システム (全13回)」の備忘録です。復習用にお使いください。

最後のGoogle Chart Toolsについては触れておりません。ドットインストールの方でレッスンが用意されています。覚えることでもないので、さっと確認して使えます。

Google Chart Tools入門 (全12回)

デベロッパーサイトの英語が読めるようになったら、Google Chart Toolsに関しての記事を書きたいなと思っています。

USE文とユニークキー #02

#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;

こちらによいサンプルが紹介されています。

Mysqlのユーザ/権限管理

また、この記事でもGRANT文は取り上げました。

【ドットインストール】ページング機能の解説

USE文

「USE データベース名」でデータベースに接続します。一度接続すれば、FROMでテーブルだけ指定すればよくなります。データベース名を省略できるようになりますが、省略しなくてもよいです。

ユニークキー

ユニークキーは値が重複することはできません。プライマリキーとは違いNULLを格納できます。また、NULLの値だけ重複することができます。

ここで、今回のデータベースの全体図を把握しておきましょう。

カラム 内容 補足
id 自動連番
answer 回答 将来的な拡張のため文字列
remote_addr 回答者のIPアドレス
user_agent ブラウザの情報
answer_date 回答日
modified 更新日
unique_answer IP * ブラウザ * 回答日 1日に1回という制限

セッションの有効範囲を理解する #03

#03 設定ファイルを作ろう

PHPのデータベース操作についてですが、こちらで専用の記事を作っています。図を用意していますので、ご覧ください。

PDOを使った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

#04 よく使う関数を登録しておこう

PHPのデータベース操作についてですが、こちらで専用の記事を作っています。図を用意していますので、ご覧ください。

PDOを使った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

\#05 投票画面を作ってみよう

画面を図解。

図:投票システムのデザイン

見栄えの変化はCSSで定義しておく #06

#06 投票結果を取得してみよう

クリックイベントハンドラの中のthisはクリックされたものを指します。今回はクラスcandidateに対してクリックイベントを設定していますので、そのクラスが付けられている画像をthisの対象となります。

今回のクリックイベントの内容は以下の通りです。

  1. candidateクラスの付いてるものからselectedクラスを取り除く。
  2. クリックされたものにselectedクラスをつける。
  3. IDanswer、つまりテキストフィールドの値を画像のid値に書き換える。

なぜ、1についての処理ですが、何故candidateクラス全体にremoveClass()を行うのかと言うと、

画像がクリックする度に前にクリックされた画像にremoveClass()を行おうとすると、クリックされた履歴を管理しないといけないですし、すべての画像のクラスを取り除いたほうが安全だからです。保証ですね。

CSRFで他のサイトからのデータ送信を防ぐ #07

#07 CSRF対策を施そう

CSRFって何?という方がいると思いますので、以前の解説記事を貼っておきます。

【ドットインストール】PHPで作る「簡易掲示版」の解説

今回はちゃんと自分の指定したformからの送信を受け付けるように設定しています。そのためにトークンを使っています。実際のサービスだと、ネット銀行やオンラインゲームとかのワンタイムパスワードみたいなものですね。

他の例をあげれば、サイトにログインするときに「画像に出ている英数字を入力してください」と出ますが、あれもCSRF対策の一種です。その場でランダムな値を発生させてそれをパスワードとしています。このパスワードがちゃんとこのサイトからデータを受診したという証明になります。CSRF対策がないと他のサイトからデータを送信され、それが悪意のあるプログラムなんかだったりしたら涙目です。例えば、リンクにプログラムを忍ばせておくとかですね。

図:CSRFの例

in_arrayで回答と正解かを判定する #08

#08 エラーチェックをしてみよう

in_array(探す値, 検索する配列)

if (!in_array($_POST['answer'], array(1, 2, 3, 4))) {}

このコードは1~4にanswerが含まれているかを判定します。そして、その否定ですから、1~4にanswerが含まれていない、つまり答えが1~4ではない時にこのif文は実行されます。

excute()の戻り値で投票制限を判断 #09-10

#09 投票結果を格納しよう (1)

#10 投票結果を格納しよう (2)

insert文で「:~」が使われていますが、これはパラメータマーカを指定しています。変数みたいなもんです。:(コロン)を使って、先に宣言だけしておいて、後から代入できるという便利なものです。

SQL文を実行する時にパラメータマーカを指定する場合は、query()ではなくprepareを使います。そして、bindParam()パラメータマーカに値をセットしてexcute()でSQLを実行します。excute()の引数でパラメータマーカを指定もできます。

excute()はパラメータマーカが異常であると、失敗したとしてfalseを返します。成功した場合はtrueを返します。なので、これを利用して1日1回の投稿制限をかけています。パラメータマーカにユニークキーが含まれているので、値が重複できません。(この場合の値とはユーザーを識別する情報)

if ($stmt->execute($params)) {
    $msg = "投票ありがとうございました!";
} else {
    $err = "投票は1日1回までです!";
}
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4