Mysqlを構築しphpで呼び出すプログラムの入門編として、シンプルなチャットを構築してみました。
今回の要件
一応チャットということで、以下のように要件定義してみました。
- 名前とメッセージを投稿できる
- 投稿が新しい順に上から表示する
- 削除できる
- メッセージ検索できる
すごくシンプルな要件です。入門編にはちょうどいいかなと…
Mysqlを構築する
まずは、Mysqlを構築します。
今回はサーバーのコンパネからDBを追加し、phpmyadminでテーブルを作成します。
DB名は「chatdb」とし作成するテーブルは「chattbl」とします。
phpmyadminのコンパネから「chattbl」を作成し、以下のような内容でテーブルの中身を構築します。
名前のデータの内容は以下です。
- number 投稿順にカウントされる数字
- name 投稿名
- mes メッセージ
- ymddate 投稿日時
numberに入る数字が大きいものから上から順に表示されます。
フォームを作成する
投稿用のフォームを作成します。
index.php
<form action="index.php" method="post" name="form"> 名前<input type="text" name="n"> メッセージ<textarea name="m"></textarea> <input type="submit" value="送信" name="submit"> </form>
DBに投稿されたデータを書き込む
フォームから投稿された内容をDBに書き込みます。
index.php
<?php if(isset($_POST['n'])) { $dsn= "mysql:host=localhost;dbname=chatdb;charset=utf8"; $user="DBのユーザー名"; $pass="DBのパスワード"; $my_nam=htmlspecialchars($_POST["n"], ENT_QUOTES); $my_mes=htmlspecialchars($_POST["m"], ENT_QUOTES); try{ $db = new PDO($dsn,$user,$pass); $db->query("INSERT INTO `chattbl` (number,name,mes,ymddate) VALUES (NULL,'$my_nam','$my_mes',NOW())");/ }catch (Exception $e) { echo $e->getMessage() . PHP_EOL; } header("Location: {$_SERVER['PHP_SELF']}"); exit; } ?>
フォームアクション後、DBに書き込むようにしています。WPを利用されている方なら見慣れてると思いますが、構築したDBへのアクセス設定をします。
$dsn= "mysql:host=localhost;dbname=chatdb;charset=utf8"; $user="DBのユーザー名"; $pass="DBのパスワード";
名前を$my_namに、メッセージを$my_mesに代入し、SQL文で’chat-tb’テーブルに番号・名前・メッセージ・日付の内容を取得して保存してます。
VALUES (NULL,'$my_nam','$my_mes',NOW())");
エラーが出たときの処理は以下です。
echo $e->getMessage() . PHP_EOL;
処理後もとのページに戻ります。
header("Location: {$_SERVER['PHP_SELF']}"); exit;
DBから情報を呼び出し投稿内容表示する
投稿内容を表示します。
index.php
<?php $dsn= "mysql:host=localhost;dbname=chatdb;charset=utf8"; $user="DBのユーザー名"; $pass="DBのパスワード"; $db = new PDO($dsn,$user,$pass); $ps = $db->query("SELECT * FROM `chattbl` ORDER BY number DESC"); define("SECMINUITE", 60); //1分(秒) define("SECHOUR", 60 * 60); //1時間(秒) define("SECDAY", 60 * 60 * 24); //1日(秒) define("SECWEEK", 60 * 60 * 24 * 7); //1週(秒) define("SECMONTH", 60 * 60 * 24 * 30); //1月(秒) define("SECYEAR", 60 * 60 * 24 * 365); //1年(秒) function niceTime($dest,$sour) { $sour = (func_num_args() == 1) ? time() : func_get_arg(1); $tt = $dest - $sour; if ($tt / SECYEAR < -1) return abs(round($tt / SECYEAR)) . '年前'; if ($tt / SECMONTH < -1) return abs(round($tt / SECMONTH)) . 'ヶ月前'; if ($tt / SECWEEK < -1) return abs(round($tt / SECWEEK)) . '週間前'; if ($tt / SECDAY < -1) return abs(round($tt / SECDAY)) . '日前'; if ($tt / SECHOUR < -1) return abs(round($tt / SECHOUR)) . '時間前'; if ($tt / SECMINUITE < -1) return abs(round($tt / SECMINUITE)) . '分前'; if ($tt < 0) return abs(round($tt)) . '秒前'; if ($tt / SECYEAR > +1) return abs(round($tt / SECYEAR)) . '年後'; if ($tt / SECMONTH > +1) return abs(round($tt / SECMONTH)) . 'ヶ月後'; if ($tt / SECWEEK > +1) return abs(round($tt / SECWEEK)) . '週間後'; if ($tt / SECDAY > +1) return abs(round($tt / SECDAY)) . '日後'; if ($tt / SECHOUR > +1) return abs(round($tt / SECHOUR)) . '時間後'; if ($tt / SECMINUITE > +1) return abs(round($tt / SECMINUITE)) . '分後'; if ($tt > 0) return abs(round($tt)) . '秒後'; return '現在'; } try{ while($r = $ps->fetch()){ $beforedest = $r['ymddate']; $dest = strtotime($beforedest); $sour = time(); //現在の時刻を$sourに代入 $outstr = nicetime($dest,$sour); $pattern = '/((?:https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/'; $replace = '<a href="$1" target="_blank">$1</a>'; $r['mes']=preg_replace( $pattern, $replace, $r['mes'] ); ?> <div> <?php print "{$r['number']}"; ?> <br> <?php print "{$r['name']}"; ?> <?php echo $outstr; ?> <?php print nl2br($r['mes']); ?> <a href="delete.php?number=<?php print "{$r['number']}";?>">削除</a> </div> <hr> <?php } }catch(Exception $e){ echo $e->getMessage() . PHP_EOL;//エラーが出たときの処理 } ?>
DBにアクセスし、テーブルから番号の降順に投稿内容を取得します。
$dsn= "mysql:host=localhost;dbname=chatdb;charset=utf8"; $user="DBのユーザー名"; $pass="DBのパスワード"; $db = new PDO($dsn,$user,$pass); $ps = $db->query("SELECT * FROM `chattbl` ORDER BY number DESC");
何分前の投稿か取得します。
define("SECMINUITE", 60); //1分(秒) define("SECHOUR", 60 * 60); //1時間(秒) define("SECDAY", 60 * 60 * 24); //1日(秒) define("SECWEEK", 60 * 60 * 24 * 7); //1週(秒) define("SECMONTH", 60 * 60 * 24 * 30); //1月(秒) define("SECYEAR", 60 * 60 * 24 * 365); //1年(秒) function niceTime($dest,$sour) { $sour = (func_num_args() == 1) ? time() : func_get_arg(1); $tt = $dest - $sour; if ($tt / SECYEAR < -1) return abs(round($tt / SECYEAR)) . '年前'; if ($tt / SECMONTH < -1) return abs(round($tt / SECMONTH)) . 'ヶ月前'; if ($tt / SECWEEK < -1) return abs(round($tt / SECWEEK)) . '週間前'; if ($tt / SECDAY < -1) return abs(round($tt / SECDAY)) . '日前'; if ($tt / SECHOUR < -1) return abs(round($tt / SECHOUR)) . '時間前'; if ($tt / SECMINUITE < -1) return abs(round($tt / SECMINUITE)) . '分前'; if ($tt < 0) return abs(round($tt)) . '秒前'; if ($tt / SECYEAR > +1) return abs(round($tt / SECYEAR)) . '年後'; if ($tt / SECMONTH > +1) return abs(round($tt / SECMONTH)) . 'ヶ月後'; if ($tt / SECWEEK > +1) return abs(round($tt / SECWEEK)) . '週間後'; if ($tt / SECDAY > +1) return abs(round($tt / SECDAY)) . '日後'; if ($tt / SECHOUR > +1) return abs(round($tt / SECHOUR)) . '時間後'; if ($tt / SECMINUITE > +1) return abs(round($tt / SECMINUITE)) . '分後'; if ($tt > 0) return abs(round($tt)) . '秒後'; return '現在'; }
それぞれの投稿内容(名前+メッセージ+番号+日時)を$rに代入しタイムスタンプに変換して、while文とfetch関数を使用して表示します。
while($r = $ps->fetch()){ $beforedest = $r['ymddate']; $dest = strtotime($beforedest); $sour = time(); //現在の時刻を$sourに代入 $outstr = nicetime($dest,$sour);
また、メッセージの内容にURLが入っていた場合、自動的にリンク設定します。
$pattern = '/((?:https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/'; $replace = '<a href="$1" target="_blank">$1</a>'; $r['mes']=preg_replace( $pattern, $replace, $r['mes'] );
あとはhtmlに変数設定するだけです。
ここまでで以下のように表示されます。
投稿を検索する
投稿されたメッセージ本文を検索します。
検索フォームを作成する
search.php
<form action="result.php" method="post"> 検索キーワード<input type="text" name="s"> <input type="submit" value="検索"> </form>
検索ページを構築する
検索結果を表示します。今回はヒットしない場合は単純にブランクなのでご勘弁を。
result.php
$my_sea=htmlspecialchars($_POST["s"], ENT_QUOTES); $dsn= "mysql:host=localhost;dbname=chatdb;charset=utf8"; $user="DBのユーザー名"; $pass="DBのパスワード"; $db = new PDO($dsn,$user,$pass); print "<p>「{$my_sea}」の検索結果</p>"; $ps=$db->query("SELECt * FROM `chattbl` WHERE mes like '%$my_sea%'"); while($r = $ps->fetch()){ $pattern = '/((?:https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/'; $replace = '<a href="$1" target="_blank">$1</a>'; $r['mes']=preg_replace( $pattern, $replace, $r['mes'] ); print "{$r['name']} {$r['ymddate']}<br>".nl2br($r['mes'])."<hr>"; } print "<p><a href='index.php'>一覧表示へ</a></p>";
パターンマッチングを行い、検索結果を表示します。
$ps=$db->query("SELECt * FROM `chattbl` WHERE mes like '%$my_sea%'"); while($r = $ps->fetch()){ print "{$r['name']} {$r['ymddate']}<br>".nl2br($r['mes'])."<hr>"; }
投稿を削除する
何かと発言が炎上する世の中です。まずい!と思ったら削除しましょう。
delete.php
<?php try { $user="DBのユーザー名"; $pass="DBのパスワード"; $dbh = new PDO("mysql:host=localhost;dbname=chatdb;charset=utf8", "$user", "$pass"); $stmt = $dbh->prepare('DELETE FROM chattbl WHERE number = :number'); $stmt->execute(array(':number' => $_GET["number"])); header('Location: index.php'); exit; } catch (Exception $e) { echo 'エラーが発生しました。:' . $e->getMessage(); } ?> <p><a href='index.php'>一覧表示へ</a></p>
<a href="delete.php?number=<?php print "{$r['number']}";?>">削除</a>
上記のリンクにnumberをクエリとして入れています。それをGETし削除し、投稿ページにリダイレクトします。
$stmt = $dbh->prepare('DELETE FROM chattbl WHERE number = :number'); $stmt->execute(array(':number' => $_GET["number"])); header('Location: index.php');
以上です。
Mysqlの入門編としては、ちょうどいいテーマではないでしょうか?
これをベースに(なるかどうかは不明ですが..)会員登録とユニーク投稿を実装など発展させたいと思います。