質問: $pdo->query($sql1); foreach( $stmt as $value ) { echo $value['task']; } }catch (Exception $e){ echo 'エラーがありました'; echo $e->getMessage(); exit; } ?> ```
回答: 「Web上で入力された情報をデーターベースに保存し、その情報をWeb上に反映させる」 というシステムの中で、どう機能を分割して作っていくかをしっかり考える必要があります。 例えば、 1.フォーム入力用のページを表示する。 2.フォーム入力によって送信されてきたデータをデータベースに反映する。 3.データベースからデータを引き出して表示する。 の3つがあるように見えます。 これらを、一つのphpファイルで実現するのか、それぞれ独立したhtmlファイルやphpファイルで実現させるか、 を検討します。 ここでは、一つのphpファイルで実現するとしましょう。 一つの中に3つの処理を破綻せず詰め込むためには、処理の順番が肝心です。 ・フォーム入力を受信してた場合に、データを検証してOKならデータベースに反映する。 ・フォーム入力枠表示する。フォーム入力を受信してた場合に、NGだった場合にはフォーム入力欄にデータを表示しつつエラーメッセージも表示する。 ・(フォーム入力があろうともなかろうとも)データベースからデータを引き出して表示する。 みたいな流れが妥当でしょうか。 冒頭でデータベースへのコネクションを確立しさえすれば、 データベースに反映する場面と データを引き出す場面とで共通してコネクションを使い回せます。 この流れでphpファイル上の処理を見直しをしてみてください。 それとは別に、 データベースにアクセスできているかを簡単にテストしてください。 いきなり上に掲げた処理を作っても、多数の問題を抱えていてはどこから手を付けていいかわからなくなります。 確実に動く、使える処理を揃えてから、組み合わせていきます。 下記は、データベース接続だけを試すコードです。 ``` PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false ]); } catch (PDOException $e) { header('Content-Type: text/plain; charset=UTF-8', true, 500); exit($e->getMessage()); } ?> タスク 接続成功. ``` ポイントは、データベース接続で例外が発生した場合に すでにhtml出力してしまうと正しく情報を出力する妨げになりうるため、 データベース処理部分のあとにHTMLのヘッダーやら本体やらを置いていることです。 フォーム入力をデータベースに反映する場合にも この組み方を真似すると良いでしょう。 次に、データベースにデータを格納できるかどうかをテストします。 ``` PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false ]); $stmt = $pdo->prepare('INSERT INTO tasks("name", "registered_date") VALUES (:name, now());'); $pdo->beginTransaction(); try { $stmt->bindValue(':name', 'sample text', PDO::PARAM_STR); $stmt->execute(); $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); throw $e; } } catch (PDOException $e) { header('Content-Type: text/plain; charset=UTF-8', true, 500); exit($e->getMessage()); } ?> タスク データ格納成功. ``` みたいな。 丁寧にbeginTransaction()とか書く習慣を身に着けておくと良いです。 たまたま今回は一つのテーブルにデータを保存するだけかもしれませんが、 規模が大きくなってくると複数のテーブルにデータを書き込むことになり、 書き込んでいる途中でエラーが生じた場合に、 書き込む前の状態まで巻き戻す(rollback()する)必要があります。 その練習だと思って書きました。 データベース処理のその先については PHPでデータベースに接続するときのまとめ - Qiita を折りに触れて読み返すことをおすすめします。 フォーム入力の検証については、 流行り(?)のfilter_input()を使うとよいかと。 `$name = $_POST['text'];` を `$name = filter_input(INPUT_POST, 'text');` とすることで、POST受信していなければ文字列長ゼロの文字列になりますし。 もちろん、そのあと`$name`にふさわしくない文字が含まれているかどうかを検証する処理は必要です。 (へんな記号は使いたくないとか、そこは自分で仕様を決める部分ですが。) ここでは伝えきれないことも多々あるので、 細かな場面毎の使える技術の積み重ねを心がけてください。 老婆心ながら、 フォーム上ではtext、 php上の変数名がnameとなるのは、 規模が大きくなってくるといちいち場面毎に どこになんのデータが入っているかを対照表を作らなきゃならなくなるので、 なるべくフォーム上も変数名もテーブル上のカラム名も同じ名称を使うようにするべきかと。 使えない場合でも簡単に類推できるようでないと、 後々自分の首を絞めます。 (数カ月後にテコ入れしようとした場合とか忘れてる。) さらに老婆心ながら、 日付らしきデータを `$Registered_Date = data("yyyy/mm/dd");` で作っているようですが、 日付時刻データを文字列で処理するのはナンセンスです。 具体例としては、 ・日付や時刻の足し算引き算、 ・2つの日付や時刻の差を求めるとき、 など大変なので、 php上ではDateTimeクラスなど、 データベース上ではDATE型TIMESTAMP型を使います。 php内で特に処理しなくても、 データベース上で使えるnow()関数があります。 一度ご自身で調べてみてください。