php+mySQL+jQueryで、コメントフォームのajax化を試す
jQueryの簡易ajax通信関数、POST()を使った処理を色々試してみたくて最近やったことを放出します。
php+mySQL+jQueryで、コメント投稿をajaxで表示するのを作ってみた。
ネタ元はNETTUTS。ってか、ほぼそのまんまやっただけw
Learn how to AJAXify Comment Forms
http://net.tutsplus.com/articles/news/learn-how-to-ajaxify-comment-forms/
懇切丁寧な作り方、考え方のscreencast(英語)がPodCastでも配信されているのでそっちを見ながら勉強がてら作ってみた。
海外サイトのチュートリアルだから、とーぜんマルチバイト言語のことは考慮なし。自分なりにエスケープ処理等細かい部分の改善は一応行なって毛を生やした感じ。
作った結果のソースは以下。
config.php
<?php $server = 'localhost'; $username = 'root'; $password = 'root';//macでMAMPを使用している場合。 $db = 'ajaxComments';//DB側に予め作っておく。 $charset = 'UTF-8'; define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']));//ajax通信を判定する定数「IS_AJAX」を定義
index.php
<?php <?php if(isset($_POST['submit'])) {//ここはJS無効時に動くスクリプト $post = array(); foreach ($_POST as $key => $value) { if(isset($_POST[$key]) && strlen(trim($value)) >= 3) {//簡易チェック $value = htmlspecialchars($value, 3, $charset);//htmlタグなどをエスケープ $post[$key] = $value; } else $error = true; if($key === 'email') { if(!filter_var($value, FILTER_VALIDATE_EMAIL)) $error = true;//emailチェック用関数を使用 } } if(!$error) { require 'leaveComment.php';//エラーがなかったらコメントを出力するファイルを呼ぶ } } ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8" /> <title>ajaxComments</title> <link rel="stylesheet" type="text/css" href="style.css" media="screen" /> </head> <body> <div id="container"> <ul id="comments"><?php include 'getItemsFromDatabase.php'; ?></ul> <h2 id="leaveAComment">Leave a Comment</h2> <div id="addComment"> <form action="index.php" method="post"> <p><input type="text" id="name" name="name" value="vname" /></p> <p><input type="text" id="email" name="email" value="ve-mail" /></p> <p><textarea name="comment" id="comment" rows="8" cols="40">vcomment</textarea> <p><input type="submit" name="submit" id="submit" value="コメント投稿" /></p> </form> <!-- //#addComment --></div> <!-- //#container --></div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js" charset="utf-8"></script> <script type="text/javascript" charset="utf-8"> var tgAddComment = $("#addComment"), tgComments = $("#comments"), tgName = $("#name"), tgEmail = $("#email"), tgComment = $("#comment"), tgSubmit = $("#submit"); tgSubmit.click(function(e){ var name = tgName.val(), email = tgEmail.val().match(/^[A-Za-z0-9]+[\w-]+@[\w\.-]+\.\w{2,}$/) ? $("#email").val() : null, comment = tgComment.val(); if(name.length < 2 || comment.length < 3 || email === null) { if($('.error').length === 0) { tgAddComment.find("form").append('<p class="error">入力内容が正しくありません</p>'); } return false } $.post( 'leaveComment.php',{ 'name' : name, 'email' : email, 'comment' : comment }, function(res) { $(".error").fadeOut(200); $('<div class="overlay"></div>') .appendTo('#addComment') .fadeIn(1000, function(){ tgComments .append('<li>' + res + '</li>') .children(':last') .height(tgComments.find('li:last').height()) .hide() .slideDown(800, function(){ var bodyHeight = $('html').height(); $('#leaveAComment').fadeOut(200, function(){ $('html').height(bodyHeight); $(this).text('コメントが投稿されました。').fadeIn(200); tgAddComment.hide(200); }); }); }); } ); return false; }); </script> </body> </html>
※ネタ元のnettutsでは、"name"のvalidateにvar name = $("#name").val().replace(/[^\w\d ]+/ig, '')ってのを使用してたけど、これは完全に欧米仕様で、日本語が見事に考慮されてない。。。
nettuts使用で突き進むと、すべて日本語の名前を入力した場合、ぜんぶ""(空白)にreplaceされ、何も入力していないとみなされて、「入力内容が正しくありません」とか事務的に言われるので、nameに関してはJavaScriptでのvalidationは行わない。そのかわりpostしたleaveComment.php側で、phpにて行うことにした。
leaveComment.php
<?php require 'config.php'; if(IS_AJAX) { $post = array(); foreach ($_POST as $key => $value) { $value = htmlspecialchars($value, 3, $charset);//JavaScriptから渡された値は、最低限エスケープくらいはやっておく。 $post[$key] = $value; } } $mysqli = new mysqli($server, $username, $password, $db) or die('There was a problem connecting.'); if($stmt = $mysqli->prepare("INSERT INTO comments VALUES(NULL, ?,?,?)")) { $stmt->bind_param('sss', $post['name'], $post['email'], $post['comment']); if(!$stmt->execute()) die($mysqli->error); $stmt->close(); if(IS_AJAX) { echo "<h3>" . $post['name'] . "</h3>"; echo "<p>" . $post['comment'] . "</p>"; } else { header('Location: index.php'); } } else { echo 'There was an error!'; }
※NETTUTSでは、JavaScriptからのPOSTを受けて、渡された値をそのまま出力しているけど、最低限htmlのエスケープはやるべき。
getItemsFromDatabase.php
<?php //error log出力用。公開時には取る。すでにphp.iniで指定してある場合は必要なし。 error_reporting(E_ALL); ini_set('display_errors', 1); ini_set('log_errors', 1); require 'config.php'; $mysqli = new mysqli($server, $username, $password, $db) or die('データベース接続でエラーが発生しました。'); $stmt = $mysqli->prepare('SELECT id, name, email, comment FROM comments ORDER BY id') or die($mysqli->error); $stmt->execute(); $stmt->bind_result($id, $name, $email, $comment); while($row = $stmt->fetch()) : ?> <li> <h3><?php echo $name; ?></h3> <p><?php echo $comment; ?></p> </li> <?php endwhile; ?>
style.css
@charset 'UTF-8'; body { font-family: helvetica, arial; line-height: 1.4em; } #container { width: 700px; margin: 10px auto 150px; color: #454545; } ul { margin: 0; padding: 0; list-style: none; } h3 { margin: 0; padding: 0; color: black; } h2 { color: #292929; font-size: 40px; margin-top: 40px; } p { font-size: 14px; } #addComment { margin-top: 40px; position: relative; } input, textarea { padding: .4em; } #comments li { border-top: 1px solid white; border-bottom: 1px solid #bcbbbb; padding: 20px 0 14px; } #comments li:last-child { border-bottom: none; } #comments li:first-child { border-top: none; padding-top: 0; } #comments, #addComment { background: #e3e3e3; border: 1px solid #bcbbbb; padding: 2em; -moz-border-radius: 2px; -webkit-border-radius: 2px; } input[type=text] { width: 70%; } textarea { width: 100%; } .error {font-style: italic; color: red;} .overlay { width: 100%; height: 100%; background: black url(loader.gif) no-repeat 50% 50%; position: absolute; left: 0; top: 0; display: none; opacity: .9; }
※DBには予め"ajaxComments"というデータベーススペース、
"comments"テーブル、そして"id","name","email","comment"フィールドを作成しておく必要があります。もちろん文字コードは"utf8_general_ci"。
※あくまで練習用なので、適切なエスケープ処理が行われていない箇所があります。使用する場合はあくまでも自己責任で。。。