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

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

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

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

Q&A

2回答

193閲覧

会員情報編集機能にて、自身のメールアドレスのみ重複エラーから除外させたい

ryotaro1226

総合スコア2

PHP

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

0グッド

0クリップ

投稿2024/04/19 06:25

実現したいこと

会員情報リストページの会員編集ページで、会員情報(苗字、名前、email)を編集して更新内容を
会員情報リストページに反映させたいです。
苗字、名前は重複可。 emailのみ重複不可としたい。

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

編集ページに飛んで、そのまま「変更」を押すと、「すでに登録されているメールアドレスです。」と表示され変更できません。(データベースに1つ以上存在することになっているため)
他の登録済のアドレスは重複エラーを出して、自分のアドレスだけ重複に該当しないよう(スルー)にしたい。
重複チェックはするが、DB上のIDに紐づいているアドレスは除外する、みたいなやり方でしょうか?

該当のソースコード

PHP

1※DB接続完了 2ーーーーーーーーーーーーーーー 3$id= $_GET['id']; 4 5 try{ 6 //$sql = "SELECT * FROM users WHERE id = :id"; 7 $sql= 'SELECT * FROM users WHERE id = :id'; 8 $stmt = $dbh->prepare($sql); 9 $stmt->bindParam(':id', $id); 10 $stmt->execute(); 11 12 } catch (PDOException $e){ 13 echo $e->getMessage(); 14 exit; 15 } 16 17 $row = $stmt->fetch(PDO::FETCH_ASSOC); 18 19 $id = $row['id']; 20 $last_name = $row['last_name']; 21 $first_name = $row['first_name']; 22 $email = $row['email']; 23 24 25 if (!empty($_POST) ){ 26 if ($_POST['email'] == "") { 27 28 $error['email'] = 'blank'; 29 30 }else{ 31 $member = $dbh->prepare('SELECT COUNT(*) AS cnt FROM users WHERE email=?'); 32 $member->execute(array($_POST['email'])); 33 $record = $member->fetch(); 34 35 if ($record['cnt'] > 0 ) { 36 37 $error['email'] = 'duplicate'; 38 } 39 } 40 41 if (!isset($error)){ 42 43 $id = $_POST['id']; 44 $last_name = $_POST['last_name']; 45 $first_name = $_POST['first_name']; 46 $email = $_POST['email']; 47 48 $sql = "UPDATE users SET id=:id, last_name=:last_name, first_name=:first_name, email=:email WHERE id = :id"; 49 $stmt = $dbh->prepare($sql); 50 $stmt->bindParam(':id', $id); 51 $stmt->bindParam(':last_name', $last_name); 52 $stmt->bindParam(':first_name', $first_name); 53 $stmt->bindParam(':email', $email); 54 $stmt->execute(); 55 header('Location: user_list.php'); 56 exit; 57 } 58} 59 60 61 62?> 63<!DOCTYPE html> 64<html lang="ja"> 65 <head> 66 <meta charset="UTF=8"> 67 <link rel="stylesheet" href="henshu_page.css"> 68 <title>編集画面</title> 69 <style> 70 .error { color: red;font-size:0.8em; } 71 </style> 72 73 </head> 74 <body> 75 76 <form action="" method="POST"> 77 78 <h3>ユーザー編集</h3> 79 <a href="user_list.php" class="modoru">[戻る]</a> 80 81 <input type="hidden" id="id" name="id" value="<?php echo $id; ?>"> 82 83 <table style="width: 950px; margin: auto;" valign="middle"> 84 <tr> 85 <th bgcolor="#D3EDFB" height="45" width="180">ID</th> 86 <td> 87 <?php echo $id;?> 88 </td> 89 </tr> 90 <tr> 91 <th bgcolor="#D3EDFB" height="45" width="180" >苗字</th> 92 <td><input type="text" class="txt" name="last_name" value="<?php echo $last_name;?>"></td> 93 </tr> 94 <tr> 95 <th bgcolor="#D3EDFB" height="45" width="180">名前</th> 96 <td><input type="text" class="txt" name= "first_name" value="<?php echo $first_name;?>"></td> 97 </tr> 98 <tr> 99 <th bgcolor="#D3EDFB" height="45" width="180">メールアドレス</th> 100 <td> 101 <input type="email" class="txt" name="email" value="<?php echo $email;?>"> 102 103 <?php if (isset($error['email']) && ($error['email'] == "blank")): ?> 104 <p class="error">メールアドレスを入力してください。</p> 105 <?php endif; ?> 106 107 <?php if (isset($error['email']) && ($error['email'] == "duplicate")): ?> 108 <p class="error">すでに登録されているメールアドレスのため、変更できません。</p> 109 <?php endif;?> 110 111 </td> 112 </tr> 113 114 <tr> 115 <td colspan="2" height="45"><input type="submit" style="width:150px" value="変更する" class="touroku"></td> 116 </tr> 117 118 </table> 119 </form> 120 </body> 121</html> 122

試したこと・調べたこと

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

参考となる記事やサイトが出てきませんでした。

補足

初学者で、いろんなサイトを参考にしてここまで書きました。コピペ部分もあるので理解していないまま動いている箇所もあります。
よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

PHP

1$member = $dbh->prepare('SELECT COUNT(*) AS cnt FROM users WHERE email=?'); 2$member->execute(array($_POST['email']));

別の質問サイトで回答した様に、ポストされたデータで単純にDB内に存在するかをチェックしているから起きている現象でしょう。
登録済みのユーザならば、確実に同じデータが存在するのですから。
変更後が、他ユーザと同じでない事を担保したいのでしょ?

既存ユーザの変更であるなら、自分以外に同じデータが存在しない様にするとか

SQL

1WHERE email=? AND id<>?

既存データと比較して、変更がある時だけチェックするロジックに変えるとか
__現状だと、変更前の値を取得済みだけど上書きしてしまっている...

対応方法は色々あると思います。

良く見かけるけれど、19~22行、43~46行の様に、単に別の変数に置き換えるだけってのは殆ど意味が無いと思います。
特に43~46行は、!empty($_POST)が真だからといって必ず保証されるモノでも無いですよね?
外部から取得するのは filter_input()とかで安全に取得するのが「お作法」だと思います。
__簡単なバリデーションを掛ける事も可能ですし

マルチポストを完全に否定はしませんけど、後始末はキチンとしてくださいね。

投稿2024/04/19 09:30

tezcello

総合スコア176

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

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

ryotaro1226

2024/04/22 10:08

回答ありがとうございます。解決できませんでした。 35行目を下記のように変えてみました。『 if ($record['cnt'] > 0 && $id !== $_GET['id'] ) {』 同じemailが0個以上かつデータベースのidとゲットされたidが同じではないときのみエラーを出すようにしたく書いてみましたがうまくいきませんでした。同じアドレスでも登録できてしまいます。おかしいでしょうか? }else{ $member = $dbh->prepare('SELECT COUNT(*) AS cnt FROM users WHERE email=?'); $member->execute(array($_POST['email'])); $record = $member->fetch(); if ($record['cnt'] > 0 && $id !== $_GET['id'] ) {      $error['email'] = 'duplicate'; } }
tezcello

2024/04/22 11:07

> $id !== $_GET['id'] > うまくいきません POSTじゃないんですか? わざわざ取得してから PHPでチェックするんじゃなく、僕だったらSQLでやりますね。 (回答で書いた通り)
ryotaro1226

2024/04/23 00:27 編集

回答ありがとうございます。 下記にしてみましたがダメでした。 tezcello様でしたらどのように記述されますでしょうか?     $member = $dbh->prepare('SELECT COUNT(*) AS cnt FROM users WHERE email=? AND id<>?'); $member->execute(array($_POST['email'])); $record = $member->fetch(); if ($record['cnt'] > 0 && $id !== $_GET['id'] ) { $error['email'] = 'duplicate'; } }
tezcello

2024/04/23 01:34

> ダメでした 何がどの様にダメなのかを考えないと先に進めません。 エラーメッセージとかはありませんか? > WHERE email=? AND id<>? > execute(array($_POST['email'])) プレースホルダと、パラメータ数が一致しませんけど? > $id !== $_GET['id'] $idって、スクリプトの最初の方で > $id= $_GET['id'] って書いているから...と思ったら、完全に見落としていました。 これ、全然ダメです。 先頭で > $id= $_GET['id'] として、$idでユーザデータを取得するSQLを実行するまでが try句に入っていますが、それ以降のデータベース操作はなぜ try句に含まれていないのでしょうか? このスクリプトが実行される際は、id=○○というクエリが付加された URLでアクセスされているのでしょう。 後半の HTML部からアクセスされる際に > <form action="" method="POST"> としているので、ここでも id=○○というクエリ付きでアクセスされます。 では、これは何の為? > <input type="hidden" id="id" name="id" value="<?php echo $id; ?>"> __これを止めると、$_POST['id']も無くなり、プログラム内で使用できません __しかし、$_GET['id']が存在するはずです $_GET['id']を使ってユーザデータ取得しようとしていますが、それは必ず有効な idが与えられるとは限らないのでは? 該当する idが存在しない場合 > $id = $row['id']; で不具合が起きませんか? __全てのエラーを表示する様にしていれば、そういうのに素早く気付けるはず で、不具合をスルーしていると、$id等は nullだろうから、それ以降のロジックが狂ってしまいます。
ryotaro1226

2024/04/25 08:48

初学者なものですみませんがおっしゃっている内容が理解できません 申し訳ございません
tezcello

2024/04/25 09:59

> 内容が理解できません ではもう少し詳しく。 > WHERE email=? AND id<>? > execute(array($_POST['email'])) プリペアドステートメントを発行する際に与えるSQLで、プレースホルダ ? を2カ所書いています。 このプレースホルダのところに、execute()で渡す配列を一つずつセットしてSQLを実行してくれるのですが、execute()に渡している値は一つだけです。 なので、このまま実行すると、数が合わなくてエラーになると思います。 > それ以降のデータベース操作はなぜ try句に含まれていないのでしょうか? 現行バージョンのPHPでは、エラー時に例外を投げるのがデフォルトだったはずです。 try { ~ } catch( ){ ~ } の後のPDOでの操作( prepare()、execute()、fetch()がいくつかありますよね?)の時に例外が投げられる可能性があるのではありませんか? __基本的にそれらはプログラムミスだけど 普通は、 try { // PDOの接続 // 更新系のSQLが走るなら、トランザクション開始 // 諸々の操作 // コミット } catch (\PDOException $e) { // (トランザクション中なら)ロールバック // エラー処理 } 的な流れのはずです。 > では、これは何の為? <form action="" となっているので、他のページからこのページにアクセスする際にURLに付加されているはずの「id=○○」が、フォームからアクセスの際も付いてくるはずです。 ですが、type="hidden"なフィールドで id をポストデータとしても取得しようとしています。 idの値が、$_GET['id']と $_POST['id']の両方に存在させようとした理由は何故でしょうか? 意味が無い、または、混乱の素になるとは思いませんか? > 必ず有効な idが与えられるとは限らないのでは? ご提示のスクリプト 17行目で $rowを取得していますが、$rowが期待している値が取得できていますか? スクリプトではノーチェックですが? 何らかの手違いで、指定した idが存在しないと、$rowは nullでしょうから、それ以降がエラーだらけになりませんか?
guest

0

unique条件がついているDBに同じデータは存在できません
ただし2カラムで復号ユニーク属性にすればもう片方のカラムに1を入れておいて
複数存在させたい場合2など別の値を入れれば共存できます
ただしnullはユニークを担保できないので指定してはいけません

投稿2024/04/19 07:22

yambejp

総合スコア114878

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

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

ryotaro1226

2024/04/24 01:57

ご回答ありがとうございます。 参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問