PHP DBへのデータ追加

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 389

YutaNkai

score 59

$staff_name = $_POST['name'];
    $staff_pass = $_POST['pass'];

    $staff_name = htmlspecialchars($staff_name, ENT_QUOTES, 'UTF-8');
    $staff_pass = htmlspecialchars($staff_pass, ENT_QUOTES, 'UTF-8');

    $dsn = 'mysql:host=localhost:8889;dbname=shop;charest=utf8';
    $user = 'tennisuser';
    $password = 'password';

    $db = new PDO($dsn, $user, $password);
    $db ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $sql = 'INSERT INTO mst_staff(name, password) VALUES(?, ?)';
    $stmt = $db ->prepare($sql);
    $stmt ->bindParam(1, $staff_name, PDO::PARAM_STR);
    $stmt ->bindParam(2, $staff_pass, PDO::PARAM_STR);
    $stmt ->execute($data);
    $db = null;

    print $staff_name;
    print 'さんを追加しました<br />';
$staff_name = $_POST['name'];
    $staff_pass = $_POST['pass'];

    $staff_name = htmlspecialchars($staff_name, ENT_QUOTES, 'UTF-8');
    $staff_pass = htmlspecialchars($staff_pass, ENT_QUOTES, 'UTF-8');

    $dsn = 'mysql:host=localhost:8889;dbname=shop;charest=utf8';
    $user = 'tennisuser';
    $password = 'password';

    $db = new PDO($dsn, $user, $password);
    $db ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $sql = 'INSERT INTO mst_staff(name, password) VALUES(?, ?)';
    $stmt = $db ->prepare($sql);
    $data[] = $staff_name;
    $data[] = $satff_pass;
    $stmt ->execute($data);


    $db = null;

    print $staff_name;
    print 'さんを追加しました<br />';

両方ともtry文の中です。上は問題なく機能するのですが下のように配列を使って挿入しようとすると
NULLは挿入できないという旨のエラーが出ます。原因はなんでしょうか。MYSQLとマンプを使用しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2018/12/23 17:34

    エラーは要約したりせず原則そのまま提示してくださいね

    キャンセル

  • m6u

    2018/12/24 10:07

    データベースにhtmlspecialchars()で加工した文字列を保存するとハマるよ。htmlとしてデータベースに保存してある文字列を正しく表示するための関数がhtmlspecialchars()なのであって。使い方が逆。

    キャンセル

回答 2

+2

NULLは挿入できない

$data[] = $satff_pass;

typoあり。

それと、
htmlspecialchars()の使い所がおかしいです。
htmlコード上に正しく文字列を表示するためにエスケープするための関数ですので、
データベースに記録する際はエスケープしたものではなく
正しいデータを記録します。
(もちろん、データベース登録用にエスケープする処理も必要になるのですが、
それはhtml用とは別の考えです。)

以下、机上のみ。

    function h($s) {
        return htmlspecialchars($s, ENT_QUOTES, "UTF-8");
    }

    $staff_name = filter_input(INPUT_POST, 'name');
    $staff_pass = filter_input(INPUT_POST, 'pass');

    //$staff_name = htmlspecialchars($staff_name, ENT_QUOTES, 'UTF-8');
    //$staff_pass = htmlspecialchars($staff_pass, ENT_QUOTES, 'UTF-8');

    $dsn = 'mysql:host=localhost:8889;dbname=shop;charest=utf8';
    $user = 'tennisuser';
    $password = 'password';

    $db = new PDO($dsn, $user, $password);
    $db ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    // SQL実行前に、POSTデータの検証処理を実行しておく必要がある
    // 少なくとも、未入力かどうか、文字数、変な記号くらいはチェック。
    $err_msgs = array();
    if ($staff_name === '') {
        $err_msgs[] = 'nameの入力がない。';
    }
    if ($staff_pass === '') {
        $err_msgs[] = 'passwordの入力がない。';
    }
    if (strlen($staff_pass) < 8) {
        $err_msgs[] = 'passwordの文字数が少ない。';
    }
    if (strpos($staff_pass, ' ;!"$&()\?') !== FALSE) {
        $err_msgs[] = 'passwordに使用できない文字を含んでいる。';
    }

    if (count($err_msgs) == 0) {
        $sql = 'INSERT INTO mst_staff(name, password) VALUES(?, ?)';
        $stmt = $db ->prepare($sql);
        $data = array($staff_name, $staff_pass);
        $stmt ->execute($data);

        echo h($staff_name) . 'さんを追加しました<br />';
    }
    else {
        echo implode('<br />', $err_msgs);
    }

とか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/24 12:25 編集

    入力可能な文字種の判定は絶対やること。
    その理由は、「SQLインジェクション」攻撃のことを調べて見つけてね。
    それと、実業務で使う前提なら、二重登録チェック(おなじnameがすでに登録されていたら拒否)や同じアドレスからの大量登録への防御なども検討するべき。

    キャンセル

checkベストアンサー

-1

質問者さんが下の配列を使って記述されたPHPはPOSTで受けたパラメータが
バインドされていませんので当然NULLになります。
ユーザー名・パスワード・DB名は当方のものになりますので
適宜変更してください。

function h($str) {
  return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

    $staff_name = h($_POST['name']);
    $staff_pass = h($_POST['pass']);

    $dsn = 'mysql:host=localhost:8889;dbname=testphp;charest=utf8';
    $user = 'root';
    $password = 'root';

    $db = new PDO($dsn, $user, $password);
    $db ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $sql = 'INSERT INTO shop(name, pass) VALUES(?, ?)';

    $stmt = $db ->prepare($sql);
    $stmt ->bindParam(1, $staff_name, PDO::PARAM_STR);
    $stmt ->bindParam(2, $staff_pass, PDO::PARAM_STR);

    $stmt ->execute($data);
    $db = null;

    print $staff_name;
    print 'さんを追加しました<br />';

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/23 22:16

    ありがとうございます。やはりそうですよね
    配列で入れる方法なんてのは存在するのですか。

    キャンセル

  • 2018/12/23 22:51 編集

    カラム数が増えてくると、1行づつ記述するのは、骨が折れますので、
    foreachで$sqlに使用するパラメータ名やbindParamメソッドを
    ループさせて処理すれば可能です。

    キャンセル

  • 2018/12/24 10:29

    しつもん、INSERT INTO文の実行のあとに、なぜにfetch()? SELECT文でもないのに。

    キャンセル

  • 2018/12/24 10:55

    失礼しました。テスト環境で値を取得が出来たか確認した時の消し忘れです。修正いたします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る