2015.1.23
0からはじめるPHP#22【MySQLで作るコメントフォーム#1】
久しぶりのこのコーナーですね。旅行レポが終わり、再び熱が入ってきたので再開です。
前回の記事を覚えてる方はいるかどうかわかりませんが
「次回は"SQLインジェクション対策"の話をします!」とか言ってた癖に全然違う話をし始めます。(笑)
まぁSQLインジェクション対策として使う
プリペアドステートメントとプレースホルダに関してはこのコメントフォーム編ででてくるので省略します。(笑)
それはそうと、連載記事のタイトルコールの形式を変えてみました。どないでしょうこれ。ナンバリングだけだと何やってるのかさっぱり分からないので、タイトル枠を長く取れることを利用して上に移してしまいました。
もしかしたら目次が見難くなってるかも知れませんが、一応インデントしてますし大丈夫・・・・・・だと信じています・・・・・・。
まぁそもそも
ここ数年1日に2つ以上記事を書かない手抜きが続いてるので問題ないでしょう、ええ。
ログページのスマホ対応の話とかあるんですが、まぁそれはCSSの話ですし
やろう思えばすぐ着手できるので放置です。
大体
なんでこのサイトがスマホ対応しなきゃいけないんだっけという
本末転倒なこと考え始めてますしね。(何)
スマホで見るユーザーも居るんで、もーちょい見やすくしたいものなんですけどね・・・・・・。
インラインフレームさえ使わなかったらPCもスマホも両方同じデザインでいいんですけどね。っていうかインラインフレーム使うとスマホでバグる理由がいまひとつ分かりません・・・・・・(-ω-`;)
旅行レポの方ではインラインフレームを用いる必要はないのでその問題はクリアしてるんですが、左メニュー取っ払った方がいいんじゃないかとかいろいろ考えてしまうんですがどうなんでしょうね。
ちなみに現時点ではスマホでアクセスすると左メニューが表示されません。目次が消えてしまっているので大変使いにくくなっております。(笑)
予定では上か下のNext,Prevリンクを目次にする形で考えてますが、ややこしいこと考えずに普通に左メニューでもいいような気がしてきた・・・・・・。
まぁスマホでこんなサイト見るなんんて少数だと思うので、SQLの勉強が終わってから片手間にCSS学習のついでにやろうかと思います。
前置きが長くなりましたが、今最優先しなければいけないのはSQLです。MySQLです。
とりあえずMySQLの学習の今後の展望を書き並べてみますと・・・・・・
1.コメントフォーム(日記との連結)
2.掲示板(増殖機能付き)
3.音楽素材・写真素材のデータベース化
4.各種商業利用用データベースの作成
とりあえずこんな感じでやっていこうかなと思っています。
はっきりいってしまえば、コメントフォームに限っては別にMySQLを利用する必要もないのですが、データベース運用の練習として制作してみようと思います。
次に掲示板や素材のデータベース化は、これは言ってしまえば商用利用への布石ですね。
具体的な計画はあんまりべらべら喋る必要もないと思うのでここでは置いておきます。自分で運用して、必要な機能を考えてみたいなと思っているのですがそもそも当サイトにはそんなにアクセスがないで実験としての効果はあんまりないよーな気もします。辛いところですね。
とりあえずプロトタイプを作ることでスキルアップを図ります。
で、最後にマトモな製品を作ろう・・・・・・というプランです。
実際のところ、データベースってそんなに学習すること自体はないので、今からでも作ろうと思えば色々作れちゃうんですけどね。
ただデータベースの問題は
設計をしくじると最初からやり直しの可能性が存在するので、扱い方に慣れるという意味でもちゃんと段階を踏もうかなと思います。
で、今回はコメントフォームですね。
前々からコメントフォームに関しては自前のものに変えなければ、と思っていたんですが、今回のリニューアルに伴い、サイトの文字コードが変わった結果
コメントフォームで文字化けが発生するという問題がありましてね。
僕の環境では上手く行くのですが、上手く行かない環境もあるので
(ぶっちゃけ原因は分からないです)自前でUTF-8準拠のものを作ってしまいましょう、という話です。今使ってるコメントフォームはShift_JISでの使用を前提にしているようですが、UTF-8に無理矢理書き換えたところで、どっかで変換している可能性があるのか、それで微妙に変わってしまうらしい。人の書いたプログラムはよく分かりませんが、自分で作ったほうが早いので自分で作ります。
で、せっかくなので、一般的なブログ形式にしようと思い、記事の下部に
コメント欄をつけることも視野に入れて開発しましょう。
ただ
まずは現行デザインの移植をということで、今のと同じスタイルで、ちょこちょこっと機能を付け加える形で実装します。
この段階では特に管理画面とかは制作しないので、データベースの取り扱いとしては面白いものはないですね。
ということで、軽くPHPでコーディングしてみました。
MySQLとの接続方法はいろいろあるのですが、今回は
PDOと呼ばれる方式で接続してみます。
後はフォームから受け取ったデータをデータベースに格納するだけです。フォームに関しては多機能メールフォーム編で大体の雰囲気を伝えたので解説はしません。
今回はダミーデータを用いての実装です。
<?php
$config_db='mysql:dbname=comment;host=localhost;charset=utf8';
$config_user="pma";
$config_pass="******";
function h($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
try {
$pdo = new PDO($config_db,$config_user,$config_pass,
array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
header('Content-Type: text/html; charset=utf-8');
//全削除
$sql = 'delete from comment';
$stmt = $pdo->prepare($sql);
$stmt->execute();
$dummy['id']=1;
$dummy['date']=0;
$dummy['name']="テスト";
$dummy['name_allow']=0;
$dummy['time']=date_format(date_create(),'Y-m-d H:i:s');
$dummy['ip']=$_SERVER["REMOTE_ADDR"];
$dummy['host']=gethostbyaddr($_SERVER['REMOTE_ADDR']);
$dummy['comment_txt']='あああああああテストテストテスト';
$dummy['comment_allow']=0;
$stmt = $pdo->prepare('INSERT INTO comment (id,date,name,name_allow,time,ip,host,comment_txt,comment_allow) VALUES (?,?,?,?,?,?,?,?,?)');
$stmt->bindValue(1,$dummy['id'],PDO::PARAM_INT);
$stmt->bindValue(2,$dummy['date'],PDO::PARAM_INT);
$stmt->bindValue(3,$dummy['name'],PDO::PARAM_STR);
$stmt->bindValue(4,$dummy['name_allow'],PDO::PARAM_INT);
$stmt->bindValue(5,$dummy['time'],PDO::PARAM_STR);
$stmt->bindValue(6,$dummy['ip'],PDO::PARAM_STR);
$stmt->bindValue(7,$dummy['host'],PDO::PARAM_STR);
$stmt->bindValue(8,$dummy['comment_txt'],PDO::PARAM_STR);
$stmt->bindValue(9,$dummy['comment_allow'],PDO::PARAM_INT);
$stmt->execute();
//データ全取得(使ってない)//
$rows = $pdo->query('SELECT * FROM comment')->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$error = $e->getMessage();
}
?>
~HTML記述 中略~
<?php if (isset($error)){?>
<p><?=h($error);}?></p>
~~省略~~
ダミーデータを用いて実装するとこんな感じです。
あとは、このダミーデータをPOSTなりGETなりに置き換えれば
コメントフォームのできあがりです。(笑)
一応軽く解説します。
最初の3つの変数は、pdoクラスを用いてデータベースに接続するために必要な情報を書いています。
dbnameにデータベース名を、
hostにサーバー名を、
charsetに文字コードですね。ここで注意すべきは
UTF-8はutf8と指定することかなと思います。
文字コードを指定しなくても動くことは動くみたいですが、推奨されてないので指定した方がいいと思います。特に理由がなければutf-8でいいと思います・・・・・・。
ホームページのリニューアルの際にも文字コードをUTF-8に変えましたが、この時にShift__JISとかだとPHPで変換しようとした時にマルチバイト対応関数使っても、なんか上手く動かなかったりしてハマったんで、長い物には巻かれた方がいいかなと。(笑)
で、下2つはデータベースに接続するためのユーザー設定ですね。まぁこの辺はとりあえずルートとかでもいいと思います。僕は
何故かpmaに全権限を与えてしまっているのでpmaを使ってます。また後で運用する時に新しくユーザーを作ろうと思ってます・・・・・・(笑)
ユーザー定義関数hに関してはまぁご存知かと思われます。htmlspecialchars関数を簡略化してるだけです。
ぶっちゃけコピペなんですけどねこれ。
で、そこから下がデータベース接続の始まりです。
pdoクラスを生成するのは第三引数まであれば大丈夫です。第四引数はオプションですね。配列の形で記述します。
PDO::ATTR_EMULATE_PREPARESは
エミュレータという機能のTRUE/FALSE切り替えです。
僕は
よくわかんないのでとりあえずFALSEにしてます。TRUEにすると、データベースサーバーとの通信量が減るので
(あんまり理解してないのでぼかしてます)データベースの実行速度は早まりますが、一部の関数で変数型を明示的にキャストしないとバグるとか、そーいうとこでハマる可能性があるので切っときました。
PDO::ATTR_ERRMODEは
PDO::ERRMODE_EXCEPTIONを指定することで例外を投げてくれます。
例外って何やねんって方は、とりあえずtry-catchとかで調べてみてください。tryの中でエラーが出たらcatchしてもらえるという仕組みです。
これ以上はよく分かってません。←
ヘッダに関しては、単にHTML側に投げる文字コードを設定してるだけです。
で、具体的な実装はここからですね。
まずいきなりデータを全削除してますが、これは
DB上のデータはクエリを投げないと消せないのでいちいちクエリを投げて全部消してます。
何回もテストする関係で、似たようなデータが蓄積していくのもウザいですし、全く同じデータが生まれると主キー制約とかにも引っかかるので
(また機会があれば話します)要らんデータは逐一消してしまいましょう、ということでテスト段階では最初に全部消してから新しくデータを挿入しています。
phpMyAdminからデータの削除ってできないんですねえ・・・・・・。
で、ここからが重要なところです。
プリペアドステートメントの話ですね。
プリペアドステートメントというのはprepare関数を使って、こんな感じに実装します。
イコールではなく->である理由は
あんまりよくわかんないので省略しますが、たぶんpdoがオブジェクトだってとこが絡んでいると思います。
で、プリペアドステートメントですが、これは
先に命令を書いておき、値を後でバインドするという方式です。
別にこれは使う必要はないのですが
セキュリティを考える上では必須です。
参考文献はいくらでもあるので、こんなざっくりとした絵だけで説明を済ませます。
プリペアドステートメントを使いプレースホルダで処理する利点はこういったところにあります。よくわかんなかったら
とりあえずプリペアドステートメント使っとけって話です。
これでSQLインジェクション対策になります。
セカンドオーダーSQLインジェクションとかありますが、そちらに関してはまだ勉強不足なのでまたの機会に・・・・・・
プリペアドステートメントの使い方は、ほんと上のコード通りにやっときゃ動きます。あとはデータ型に応じてPARAM_INTとPARAM_STRを分けることで適切にキャストすればいい話です。
で、最後にexecute()で実行します。
するとこんなデータが生成されます。
これでコメント送信部分が9割方完成しました。(笑)
あとはフォームを書いて、ダミーデータの部分にフォームから受け取った値を入れれば、すぐにでも運用はできます。
さて、データベースということで、さまざまなデータを管理できるようにしなくては意味がないので、次回からは
管理画面の話に移っていきたいと思います。
こっからが本番で、コメントのコピペをしやすくしたりに始まり、不要なデータの削除やデータベース内検索・・・・・・といった機能と
GUIで実現したいと思います。
GUIって畑違いの人には通じない単語かもしれませんが、ようするにブラウザで出来るようにしましょうってことです。
ここからが本番です。ぼちぼちやっていきたいなーと思います。
ただ、自分の作ったシステムを全部公開してしまうってのはマズいかなぁと思うので、次回以降は要所要所かいつまんで記事にしていこうかなぁ・・・・・・なんて思っていたりします。
身内の方からコメントいただきましたが、一部文字化けしてるのでこっちでは返さないことにします。(笑)