PHP初心者です。
PHP,MySQLにて簡易掲示板を作成しています。
ファイルは
index.php(投稿一覧表示、新規投稿フォーム)
confirm.php(投稿内容確認画面)
complete.php(書き込み完了画面)
(DB接続、エスケープ処理はそれぞれ外部ファイル(db_info.php,encode.php)を作成)
という構成です。
現在の問題としてはcomplete.phpにて「書き込みが完了しました」と表示されますが、index.phpに戻ると投稿が表示されないことです。
ソースは下記です。
index.php
<?php require_once('db_info.php'); require_once('encode.php'); try { $pdo = new PDO($dsn, $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOExeption $e){ $error = 'Unable to connect to the database server: ' . $e->getMessage(); include 'error.php'; exit(); } try { $sql = "select * from bbsdata order by day desc"; $result = $pdo->query($sql); } catch (PDOExeption $e) { $error = 'Error fetching threads:' . $e->getMessage(); include 'error.php'; exit(); } echo <<<eot1 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>簡易掲示板</title> <style type="text/css"> body { background-color: #E1EDFF; line-height: 1.5rem; } </style> </head> <body> <h1>簡易掲示板</h1> <form action="confirm.php" method="post"> 名前:<input type="text" name="name"><br> タイトル:<input type="text" name="title"><br> メッセージ:<br> <textarea name="msg" rows="10" cols="30"></textarea><br> <input type="submit" value="確認画面へ"> </form> <hr> eot1; $i = 1; foreach($result as $row) { $s = "<p>($i)タイトル: <strong>%s</strong><br>投稿者: %s 投稿日 %s<br>内容:<br>%s</p>"; printf ($s,h($row['title']), h($row['name']), h($row['day']), h($row['msg'])); $i++; } echo <<<eot2 </body> </html> eot2;
confirm.php
<?php session_start(); $token = sha1(uniqid(mt_rand(), true)); $_SESSION['token'] = $token; require_once('db_info.php'); require_once('encode.php'); try { $pdo = new PDO($dsn, $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOExeption $e){ $error = 'Unable to connect to the database server: ' . $e->getMessage(); include 'error.php'; exit(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>確認画面</title> </head> <body> <h1>確認画面</h1> タイトル: <?php print h($_POST['title']); ?> 投稿者: <?php print h($_POST['name']); ?><br> 内容:<?php print h($_POST['msg']); ?> <form action="complete.php" method="post"> <input type="hidden" name="name" value="<?php echo $_POST['name'];?>"> <input type="hidden" name="title" value="<?php echo $_POST['title'];?>"> <input type="hidden" name="msg" value="<?php echo $_POST['msg'];?>"> <input type="hidden" name="token" value="<?php $token ?>"> <input type="submit" value="送信する" name="regist"> </form> </body> </html>
complete.php
<?php session_start(); if (isset($_POST['regist'], $token, $_POST['token']) && $token === $_POST['token']) { unset($_SESSION['token']); require_once('db_info.php'); try { $pdo = new PDO($dsn, $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOExeption $e){ $error = 'Unable to connect to the database server: ' . $e->getMessage(); include 'error.php'; exit(); } //書き込み try { $sql = "insert into bbsdata (name, day, title, msg) values (:name, now(), :title, :msg)"; $s = $pdo->prepare($sql); $s->bindValue(':name', $_POST['name']); $s->bindValue(':title', $_POST['title']); $s->bindValue(':msg', $_POST['msg']); $s->execute(); } catch(PDOExeption $e) { $error = 'Error writing message: ' . $e->getMessage(); include 'error.php'; exit(); } header("Location: http://{$_SERVER['HTTP_HOST']}/practice/bbs/complete.php/", true, 303); } else { echo <<<eot1 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>完了画面</title> </head> <body> <h1>書き込みが完了しました</h1> <a href="http://{$_SERVER['HTTP_HOST']}/practice/bbs/index.php">トップページへ戻る</a> </body> </html> eot1; }
complete.phpはリロードでの二重送信防止目的にPRGパターンを使っているため、ブラウザに表示された時にはGETになるべきだと思うのですが、POSTとして表示されます。
したがってif (isset($_POST['regist'], $token, $_POST['token']) && $token === $_POST['token'])で弾かれてしまい、DBにinsertすることなく「書き込みが完了しました」と表示されているのではと思います。
また、私のcomplete.phpの設定では不正な値、値が空といった場合でも「書き込みが完了しました」と表示されてしまうのではと思います。
下記の点についてご回答お願い致します。
- 投稿をinsertするためにはどうしたいいか
- 不正な値・値が空の場合の処理をどうすべきか
- セキュリティの方向性が現在の設定(エスケープ処理、PDO、トークンの使用)で間違いはないか
- 二重送信への対策はこれで十分か(リロード、戻るボタン使用時など)
- 現在の処理で不要な箇所などはないか
2017.4.29追記
構成など少し変更しとりあえず自分の思っていた形に実装できました。
フィードバックを頂きたく思い、ここでは記述が長くなり見にくくなるため新たにこちらに投稿させて頂きました。
アドバイス頂けると幸いです。
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/04/21 19:45
2017/04/29 15:04