質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

87.91%

jsのpromptで入力された値を、AJAXを用いPHPの変数に格納したい

解決済

回答 1

投稿 編集

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

score 32

ある課題に取り組んでいて簡易掲示板を作っています。
テキスト保存のものを作った後、MySQL保存に変えたものを作っています。
php5.2.4(指定による)
mysqlのサーバー情報は伏せてあります。

jsでパスワードの入力を求め、その値をPHP側の check_password に格納したいです。
jsで変数check_password を作り、その変数内でpromptを書いています。(これが正しいのかどうかも判断出来ません)(107行目から)
動作としては、「本当に削除しますか」と表示し「yes」ならパスワードの入力を求めます。
そこまでは動作出来ています。(編集ではすぐパスワードを求めます)
その後パスワードをPHPに渡すところが出来ません。

jsから直接値を渡せないこと、AJAXを使えばなんとか出来そうと言うところまでは来ましたが、どの様に書けば望んだ動作がなされるのかわかりません。
色々探し回りましたが、まだ理解が追いついていません。
どの様に書けばよろしいでしょうか?

渡せたかどうかを見るためにcheck_passwordをvar_dumpしています。(154行目)

<?php
ini_set( "display_errors", 1 );
error_reporting( E_ALL );
//変数の定義
$name = filter_input( INPUT_POST, "name" ); //投稿者の名前
$comment = filter_input( INPUT_POST, "comment" ); //投稿したコメント
$delete_no = filter_input( INPUT_POST, "delete_no" ); //削除指定番号
$edit_no = filter_input( INPUT_POST, "edit_no" ); //編集指定番号
$edit_decision = filter_input( INPUT_POST, "edit_decision" ); //投稿と編集の判別用のhidden送信
$password = filter_input( INPUT_POST, "password" ); //送信するpassword
$check_password = filter_input( INPUT_POST, "check_password" ); //照合するパスワード
$date = date( "Y-m-d H:i:s" ); //投稿日時
$replace_search = array( "\r\n", "\r", "\n" ); //置き換えのための改行コードの検索
$replace = array( "<<改行win>>", "<<改行mac>>", "<<改行unix>>" ); //改行コードを置き換える文字
$replace_name = str_replace( $replace_search, $replace, $name ); //改行を置き換えた名前
$replace_comment = str_replace( $replace_search, $replace, $comment ); //改行を置き換えられたコメント
$nothing_message = "";//番号がない時のmessageの初期化 
//MySQL接続情報
$servername = "";
$username = "";
$serverpassword = "";
$dbname = "";
//編集時の表示用名前とコメントの初期化
$edit_name = "";
$edit_comment = "";
$edit_num = "";
$decision_no = "";
//messageの初期化
$edit_message = "";
$edit_nothing_message = "";
$num_message = "";
$delete_message = "";
//書き込み内容のsql文
$insert_sql = "INSERT INTO toko(
name, comment, date, password
) VALUES (
'$replace_name', '$replace_comment', '$date', '$password'
)";

//データベースに接続
try {
  $db = new PDO( "mysql:dbname=$dbname;host=$servername;charset=utf8mb4", $username, $serverpassword, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  ] );
  //投稿機能
  if ( !empty( $name ) && !empty( $comment ) && empty( $edit_decision ) ) {
    $insert = $db->query( $insert_sql ); //書き込みsql実行
    //リロードし二重書き込み防止
    header( 'Location: keijiban_mysql.php', true, 303 );
    exit;
  }
  //削除機能
  if ( !empty( $delete_no ) ) {
      //削除指定番号の行のデータ取得のsql文
      $delete_select = $db->prepare( "SELECT * FROM toko WHERE num = '$delete_no'" ); 
      $delete_select->execute(); //実行
      $delete_select = $delete_select->fetch( PDO::FETCH_ASSOC ); //データ取得
      $delete_num = $delete_select['num'];
      if( !empty( $delete_num ) ){
      $delete_sql = "DELETE FROM toko WHERE num='$delete_no'";  
      $delete = $db->query( $delete_sql );
      $delete_message = '削除されました';
      }else{
          $delete_message = "<span class='akaji'>".'該当する番号はありません'."</span>";
      }
    }
    //編集番号指定
  if ( !empty( $edit_no ) ) {
      $decision_no = $edit_no;//判定用の変数定義 //編集指定番号の行のデータ取得のsql文
      $edit_select = $db->prepare( "SELECT * FROM toko WHERE num = '$edit_no'" ); 
      $edit_select->execute(); //実行
      $edit_select = $edit_select->fetch( PDO::FETCH_ASSOC ); //データ取得
      $edit_name = $edit_select[ 'name' ]; //テーブル内の取り出したnameの定義
      $edit_comment = $edit_select[ 'comment' ]; //テーブル内の取り出したcommentの定義 
      $edit_num = $edit_select[ 'num' ];//テーブル内の取り出したnumの定義
      if ( !empty( $edit_num ) ){
          $edit_message = $edit_no . '番の投稿を編集します';
      } else {
          $edit_nothing_message = "<span class='akaji'>".'該当する番号はありません'."</span>";
      }
  } 


    //編集機能
  if ( !empty( $name ) && !empty( $comment ) && !empty( $edit_decision ) ) { //名前とコメントと編集判定が送信されたら    

    //編集のSQL文
$update = "UPDATE toko SET name = :name, comment = :comment WHERE num = :num";
    $update = $db->prepare($update);
    $params = array(':name' => $replace_name, ':comment' => $replace_comment, ':num' => $edit_decision);
    $update->execute($params);
  }
} catch ( PDOException $e ) {
  print( "エラー:" . $e->getmessage() );
  die();
  //リロードし二重書き込み防止
  header( 'Location: keijiban_mysql.php', true, 303 );
  exit;
}
?>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>簡易掲示板MySQL保存版</title>
<script>
  //削除時の確認    
  window.addEventListener('DOMContentLoaded', function(){
    document.querySelector('#delete_button').addEventListener('click',function(e){
      if(confirm("本当に削除しますか?")){//本当に削除しますか?と表示しyes,noの選択肢を出す
        var check_password = prompt("パスワードを入力してください");//yesならパスワード入力を求める
      }else{
      alert('キャンセルされました');//「キャンセルされました」 と表示
      e.preventDefault();//キャンセルの実行(defaultの動作を妨害)
      }
    });    
  });

//編集と削除時のパスワードの入力
  window.addEventListener('DOMContentLoaded', function(){
    document.querySelector('#edit_button').addEventListener('click',function(e){
      if(!prompt("パスワードを入力してください")){    
        alert('キャンセルされました'); 
        e.preventDefault();
      }
    });
  });

//PHPへ値を渡す
  $.ajax ( {
    type: 'POST',
    url: 'keijiban_mysql.php',
    data: {
      'check_password' : check_password,
    },
    success: function(data) {
    alert(data);
    }
  });
</script>
<style>
.akaji {
    color : red;
}
.komoji {
    font-size: 0.8em;
}
</style>
</head>
<body>
<?php
    var_dump($check_password);
  //XSS対策
  function h( $str ) {
    return nl2br( htmlspecialchars( $str, ENT_QUOTES, 'UTF-8' ) );
  }
//改行の置き換え
$replace_seach = array( "<<改行win>>", "<<改行mac>>", "<<改行unix>>" ); //改行の置き換え文字の検索
$replace = array( "\r\n", "\r", "\n" ); //改行コードへの置き換え

?>
<!--投稿フォーム-->
<form method="post" >
  <label for="name">お名前<span class="akaji">【必須】</span></label>
  <?php
    if ( !empty( $edit_no ) ) {
        echo $edit_message;
    }
  ?>
  <br>
  <input type="hidden" name="edit_decision" value="<?php
                                                   echo $decision_no;
                                                   ?>" >
  <input type="text" name="name" id="name" required="required" value="<?php
                                                                      echo $edit_name;
                                                                      ?>" >
  <br>
  <label for="comment">コメント<span class="akaji">【必須】</span></label><br>
    <textarea name="comment" cols="30" rows="3" id="comment" required="required">
      <?php
        echo $edit_comment;
      ?>
    </textarea><br>
  <label for="possword">パスワード<span class="akaji">【必須】</span></label><br>
  <input type="password" name="password" id="password" required="required">
  <br>
  <input type="submit" value=<?php
         if(!empty( $edit_no ) ){
             echo '編集';
         } else {
             echo '投稿';
         }
         ?> >
</form>
<br>
<!--削除番号指定用フォーム-->
<form method="post" name="delete">
  <label for="delete_no">削除対象番号</label>
    <?php
    if( !empty( $delete_no ) ) {
        echo $delete_message;
    }
    ?>
  <br>
  <input type="number" name="delete_no" id="delete_no" required="required"><br>
  <input type="submit" value="削除" name="btn" id="delete_button">
</form>
 <br>
<!--編集番号指定用フォーム-->
<form method="post">
  <label for="edit_no">編集対象番号(半角)</label>
    <?php
    if ( !empty( $edit_no ) ) {
         echo $edit_nothing_message;
    }
    ?>
  <br>
  <input type="number" name="edit_no" id="edit_no" required="required"><br>
  <input type="submit" value="送信" id="edit_button">
</form>
<br>

<?php
//投稿内容の表示
  try {
    //テーブルの行数取得
    $sql = 'select count(*) from toko';
    $count = $db->query( $sql );
    $count = $count->fetchColumn();
    $select = "SELECT * FROM toko"; //テーブルデータの取得のクエリ
    $select = $db->query( $select ); //クエリの実行
//投稿がない場合「投稿はまだありません」と表示する
  if ( $count == 0 ) {//行数が0だったら
    echo "<p>投稿はまだありません</p>";//投稿はまだありませんと表示する
  } else {//その他の場合
    foreach ( $select as $row ) { //ループして表示
      echo "<span class='komoji'>No</span>:" . h( $row[ 'num' ] ) . "&emsp;&emsp;" .
           "<span class='komoji'>名前</span>: " . h( $row[ 'name' ] ) . "<br>" .
           h( $row[ 'comment' ] ) . "<br>" .
           "<span class='komoji'>".h( $row[ 'date' ] ) . "</span><br>";
    }
  }

  } catch ( PDOException $e ) {
    print( "表示エラー:" . $e->getmessage() );
    die();
  }

?>
</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2019/12/06 20:56

    インデントはきちんとつけましょう。
    申し訳ないですが読む気しません

    キャンセル

  • m.ts10806

    2019/12/06 20:57

    あともう少しコードを最低限再現できるくらいにされたほうが問題切り分けしやすくなるかと思います。

    キャンセル

  • MakotoIshizawa

    2019/12/07 08:20

    ありがとうございます。
    インデントをきちんとつけるところから始めようと思います。

    キャンセル

回答 1

checkベストアンサー

+4

passeordでいいんか?
posswordもあるけど?
タイプミスや文法エラーを検出できるエディタを活用することを強くおすすめしたい。
使えない場合は、気になる箇所を文字列検索してタイプミスを目視で発見できるよう頑張る。
どんなエディタがいいかは、色んな人がいろんなところで記事にしているから自分で探すこと。
(自分に合う合わないもあるから、いくつか並行して試してみるとヨサゲ)

そもそも、delete_noやedit_noを送信する削除/編集フォームに、
なぜpasswordを送信するinput要素を置かないのか。
かつ、
なぜpasswordだけajax利用で送信しようとしているけど、
phpでの処理待受できる構造になってないので、
この場面ならajaxをあやふやに使うんじゃなくて、
そもそも、delete_noやedit_noを送信するフォームに、
passwordを送信するinput要素を置いてみるのを試すこと。
ajaxは止める。

もしかして
delete_noやedit_noを送信する削除/編集フォーム送信後に、
確認画面を作ろうとしている?
だとするとそれをajax駆使して別途パスワード送信するのはピンとこない。
すべての処理を一つのphpに封じ込めて作ろうとして
処理の分岐や構造がわからなくなって破綻し始めているように見える。
一度、処理ごとにhtmlとphpを全部バラして作ってみて、
それがうまく機能するようになってからまとめ直すやり方を
おすすめしたい。
例えば、
▼投稿フォーム兼投稿データ表示画面
▼投稿結果表示画面(からリダイレクトして投稿フォーム兼投稿データ表示画面に戻るとか)
▼削除フォーム画面
▼削除確認画面
▼更新フォーム画面
▼更新確認画面
くらいに機能単位で分割して組み立てれば、他の処理に惑わされず作りたい機能に集中できるはず。

teratailにいろんな回答者が居て、
これまで質問者さんが掲げた質問を表層的に捉えて簡単に回答して、
それを全部取り入れると「船頭多くして船山に登る」になってしまっているのかもしれない。
取り入れるかどうか、組み込むかどうか、設計書レベルから見直しすることを勧めたい。


$insert_sql = "INSERT INTO toko(
name, comment, date, password
) VALUES (
'$replace_name', '$replace_comment', '$date', '$password'
)";


外部から与えられる値を格納した変数を、
直接SQL文内で展開するのは、
SQLインジェクションの問題を孕むから止めような。
そして、複数行に渡るSQLを記述するなら、
ヒアドキュメント構文使おうぜ。

$insert_sql = <<<EOT
INSERT INTO toko(
  name, comment, date, password
) VALUES (
  :replace_name, :replace_comment, :date, :password
);
EOT;
$edit_select = $db->prepare( "SELECT * FROM toko WHERE num = '$edit_no'" ); 


ここも、せっかくのprepareが台無し。

$edit_select = $db->prepare( "SELECT * FROM toko WHERE num = :edit_no" ); 


とかする。
もちろん、bindValue()でバインドしてからexecute()すること。


      $delete_select = $delete_select->fetch( PDO::FETCH_ASSOC ); //データ取得
      $delete_num = $delete_select['num'];
      if( !empty( $delete_num ) ){


この箇所、fetch()失敗していたら$delete_selectはFALSEになるよね。
$delete_selectがFALSEかどうかを判定し、その後に$delete_select['num']を判定するようにしたいところ。


SELECT文以外のSQLを実行する箇所、トランザクション処理していないの、こわい。
簡易掲示板だから、扱うテーブルが一つで、データ構造の主従関係とか想定しなくていいから、
この場では大した問題にならないかもしれないけど、
複数のテーブルを扱うような場面に遭遇したときにテーブルAに書き込んでテーブルBに書き込むときにエラーが出たりしたときは、
一連の処理を「なかったこと」にすることも必要になる。
そのための練習も兼ねてbeginTransaction()とか駆使してみるといいよ。

tryブロックの外で$insert_sqlだけ定義して、
他のSQL文はifブロック内の局所変数っていうあべこべさ。
そして、
後の処理で使うかどうかわからないけど冒頭で片っ端からPOST受信データを変数に突っ込んでるのも気になる。
処理の分岐判定に必要なパラメータだけ最初に解釈して、
更新処理なら更新処理に必要なもの、
削除処理なら削除処理に必要なものっていうふうに局所的にやったほうが
全体の見通し風通しが良くなる気がする。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/12/07 08:35

    凄くたくさんのアドバイスありがとうございます。
    質問文も悪かったなあと思いました。
    ある課題をやっているのですが、
    「編集削除の際に、パスワードの入力を求める。具体的にはパスワード入力ができるようにしたformを表示し、入力させる。」というのがありまして、jsかなと思いやって見て、せっかく手を付けたから出来したいと思って取り組んでしました。
    やはりinputを置くのが妥当なのでしょうか。
    同様の課題でテキスト保存版で同じことをしていますが、そちらではPHPでやってみました。
    受け渡し後の処理についてはまだ書いていない状態でした。
    エディターはDWを使っていますが、タイプミスをしてよく躓いてしまっています。
    諸々のアドバイスを参考に修正して、全体を見直してみたいと思います。
    まずは、インデントをちゃんと付けるところからスタートしようと思います。
    その後に、諸々のご指摘の箇所を修正していきます。
    bindValue()とかヒアドキュメント構文とかまだ未知の単語なので、調べて対処します。
    大変詳細に渡る御指摘頂きまして本当に助かります。ありがとうございます。

    キャンセル

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

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

関連した質問

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