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

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

新規登録して質問してみよう
ただいま回答率
85.44%
SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

1回答

190閲覧

同一ページの二重送信・リロード

krnkn6

総合スコア4

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2024/05/24 01:54

編集2024/05/24 03:05

実現したいこと

php・sqlで簡易的ないいねボタン付きの掲示板の作成についてです。
(セキュリティ関係は今回省略します)

簡易的ないいねボタン・掲示板の仕様・テーブル情報は以下となります。
●いいねボタンの仕様
・各投稿内容ごとにいいねボタンを押された回数を表示
・DBにいいね用のカラムを作成し回数を保存
・いいね用formを作成し、押されたときに同一ページ内へリクエスト
・いいねボタンのからのリクエストがあった場合、同一ページ内でカウントアップの処理を実行
・ユーザーを識別して、回数制限を設ける機能は今回なし

●掲示板の仕様
・入力項目は「名前」と「投稿内容」のみ
・掲示板用formでのPOST送信時、作成されたレコードに日付を自動で登録
・名前が無記入の場合「名無し」と表示

●テーブル情報
id : 番号
name : 投稿者名
message : 投稿内容
created_at : 日付

発生している問題・分からないこと

いいねボタン付きの掲示板は既に実装してありますが、下記2つの問題点が発生しています。

・同一ページ内へPOST送信をする場合の二重送信対策
・いいねボタンが押されると毎回ページがリロードされる

●二重送信について
POST送信は別ページへリクエストしていたので、入力ページでトークンを生成してSESSION・$_POSTに格納し、送信先ページで値が同じかif文で確認してから処理を実行していました。
(処理を実行後、SESSIONを削除し二重送信は発生しないようにしていました。)
しかし、同一ページ内でPOST送信をする場合、二重送信はどのように対策すればよいのでしょうか。

また、いいねボタンが押されるとPOST送信され、毎回ページが更新されてしまうのですが、twitterのいいねボタンのように、ページが更新されずいいね数だけが増えるようにするにはどうすればよいのでしょうか。

該当のソースコード

index.php

1try { 2 $pdo = 'DB接続の記述'; 3   4 //いいねカウントアップ用のSQL 5 if($_POST) { 6 $sql = " 7 UPDATE net 8 SET good = good + 1 9 WHERE id = :id" 10 ; 11 12 $stmt = $pdo->prepare($sql); 13 $stmt->bindValue(':id' , $_POST['id'] , PDO::PARAM_INT); 14 $stmt->execute(); 15 } 16 17 //投稿一覧表示用のSQL 18 $sql = "SELECT * FROM net"; 19 $stmt = $pdo->prepare($sql); 20 $stmt->execute(); 21 22}catch (PDOException $e) { 23 $msg = '接続失敗'; 24} 25 26//投稿内容一覧表示 27foreach($stmt as $row) { 28 echo '<p>ID:' . $row['id'] . '-' . $row['name'] . '-' . $row['created_at'] . '</p>'; 29 echo '<p>' . $row['message'] . '</p>'; 30 31 //いいね用form 32 echo '<form method="post" action="">'; 33 echo '<input type="hidden" name="id" value="' . $row['id'] . '">' . $row['good']; 34 echo '<input type="submit" name="good" value="いいね">'; 35 echo '</form>'; 36} 37 38//投稿用form 39<form action="insert.php" method="post"> 40 お名前<input type="text" name="name"><br> 41 投稿内容<textarea name="message"></textarea> 42 43 <input type="submit" name="insert" value="投稿"> 44</form>

insert.php

1//登録処理のみの記述(表示の記述は省略) 2 3$pdo = 'DB接続の記述'; 4 5if(empty($_POST['name'])) { 6 $_POST['name'] = '名無し'; 7} 8 9$sql = "INSERT INTO net(name , message) 10 VALUES(:name , :message)"; 11 12$stmt = $pdo->prepare($sql); 13 14$stmt->bindValue(':name' , $_POST['name'] , PDO::PARAM_STR); 15$stmt->bindValue(':message' , $_POST['message'] , PDO::PARAM_STR); 16 17$stmt->execute();

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

同一ページ内POST送信時の二重送信対策については、調べてみても別ページにPOST送信する場合の対策しか見つからず分かりませんでした。

いいねが押されたときに毎回ページが更新されてしまう問題点については、jsでイベントキャンセルをしてみましたが、POST送信自体?がキャンセルされてしまいうまく対応できませんでした。

補足

特になし

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自ページであってもセッションを使って遷移し完了状態にします

PHP

1<?PHP 2session_start(); 3 4if($_POST){ 5 $_SESSION["hoge"]=$_POST["hoge"]??null; 6 header("Location:{$_SERVER["SCRIPT_NAME"]}"); 7 exit; 8}else{ 9 print_r($_SESSION); 10 session_destroy(); 11} 12?> 13<form method="post"> 14<input name="hoge" value="123"> 15<input type="submit" > 16</form>

参考

便宜的にgoodをセッションに保持しておきます。実際にはDBで管理してください

php

1<?PHP 2session_start(); 3if(filter_input(INPUT_POST,"reset")){ 4 session_destroy(); 5} 6if(filter_input(INPUT_GET,"load")){ 7 print json_encode($_SESSION["ids"]??[]); 8 exit; 9} 10if($id=filter_input(INPUT_GET,"good")){ 11 $ids=$_SESSION["ids"]??[]; 12 $ids[$id]=($ids[$id]??0)+1; 13 $_SESSION["ids"]=$ids; 14 print json_encode(["id"=>$id,"count"=>$ids[$id]]); 15 exit; 16} 17 18if($_POST){ 19 $_SESSION["hoge"]=$_POST["hoge"]??null; 20 header("Location:{$_SERVER["SCRIPT_NAME"]}"); 21 exit; 22}else{ 23 print_r($_SESSION); 24 unset($_SESSION["hoge"]); 25} 26?> 27<script> 28window.addEventListener('DOMContentLoaded', ()=>{ 29 fetch(`?load=1`).then(res=>res.json()).then(res=>{ 30 Object.entries(res).forEach(data=>Object.assign(document.querySelector(`[data-good="${data[0]}"] span`)??{},{textContent:data[1]})); 31 }); 32}); 33document.addEventListener('click',({target})=>{ 34 if(target.matches('[type=button]') && target.closest('[data-good]')){ 35 const usp= new URLSearchParams(); 36 usp.append("good",target.closest('[data-good]').dataset.good); 37 fetch(`?${usp}`).then(res=>res.json()).then(data=>{ 38 document.querySelector(`[data-good="${data.id}"] span`).textContent=data.count; 39 }); 40 } 41}); 42</script> 43<form method="post"> 44<input name="hoge" value="123"> 45<input type="submit" > 46<input type="submit" name="reset" value="reset" > 47</form> 48 49<div data-good="1"> 50<span></span> 51<input type="button" value="いいね"> 52</div> 53<div data-good="2"> 54<span></span> 55<input type="button" value="いいね"> 56</div> 57<div data-good="3"> 58<span></span> 59<input type="button" value="いいね"> 60</div>

投稿2024/05/24 02:04

編集2024/05/24 04:10
yambejp

総合スコア115241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

krnkn6

2024/05/24 03:15

ご回答ありがとうございます。 おかげさまで二重送信については解決いたしました! 2つ目の問題点である、いいねを押したときにカウントアップだけが行われてページの更新が行われないようにするにはどうしたらよいでしょうか。 いいねを押すと毎回更新が入って、トップ画像に戻されてしまうのですが。。。
yambejp

2024/05/24 03:25 編集

いいねはサブミットせずに非同期で処理してください ただgoodをインクリメントする仕組みだとそれこそ多重にいいねが押せてしまうので 文書idとユーザーidの組み合わせで1投稿しかできないDBの構造にした方が良いと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問