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

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

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

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

Q&A

解決済

1回答

1076閲覧

会員登録機能のDB存在チェック処理

jem32o

総合スコア79

PHP

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

0グッド

1クリップ

投稿2020/02/02 07:52

編集2020/02/02 13:02

前提・実現したいこと

$_POST['mail']に対してDB存在チェックを行いたい
ここに質問の内容を詳しく書いてください。
DBの存在チェックの処理がうまく動かない
$stmt = $customer->getDB()->prepare($sql);以降の処理をどのようにしたら$sqlで実行した結果を取れますか?

発生している問題・エラーメッセージ

$stmt > 0の条件の処理がうまくいかない

<?php require_once(__DIR__.'/config.php'); require_once(__DIR__ . '/Regist1.php'); try{ $customer = new \MyApp\Customer(); }catch(Exception $e){ $e->getMessage(); exit; } if($_SERVER['REQUEST_METHOD']=="POST"){ $mail = $_POST['mail']; $sql = "select count(mail) from customer where mail = '$mail"; $stmt = $customer->getDB()->prepare($sql); if(empty($_POST['mail'])){ $mail_err = "メールアドレスが未入力"; }else if(empty($_POST['pass'])){ $pass_err = "パスワードが未入力"; }else if($STMT >0){ $mail_err = $mail."は重複してます"; }else{ $pass = $_POST['pass']; $sex = $_POST['sex']; $year = $_POST['year']; $month = $_POST['month']; $day = $_POST['day']; $customer->post(); } } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Port forio</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/regist.css"> </head> <body> <header> <div class="header container"> <nav class="navbar navbar-expand-sm navbar-light"> <a href="/" class="navbar-brand">TOP</a> <button class="navbar-toggler" data-toggle="collapse" data-target="#menu"> <span class="navbar-toggler-icon"></span> </button> <div id="menu" class="collapse navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item"><a href="/regist.php" class="nav-link">新規登録</a></li> <li class="nav-item"><a href="#" class="nav-link">ログイン</a></li> <li class="nav-item"><a href="/profile.php" class="nav-link">プロフィール</a></li> <li class="nav-item"><a href="/check.php" class="nav-link">診断</a></li> <li class="nav-item"><a href="/task.php" class="nav-link">管理</a></li> </ul> </nav> </div> <form action="" class="form-inline m-4 search"> <input type="search" class="form-control mr-2" placeholder="検索"> <button class="btn btn-primary">検索</button> </div> </form> </header> <main> <h1>新規登録</h1> <form action="/customers.php" method="post"> <div> <?php if(isset($mail_err)):?> <?= $mail_err;?> <?php elseif(isset($pass_err)):?> <?= $pass_err;?> <?php else:?> <table> <tr> <td>1)メールアドレス</td> <td name="mail"><?= $mail;?></td> </tr> <tr> <td>2)パスワード</td> <td name="pass"><?= $pass;?></td> </tr> <tr> <td>3)性別</td> <td name="sex"><?= $sex;?></td> </tr> <tr> <td>4)生年月日</td> <td name="birthday"><?= $birthday;?></td> </tr> </tbody> </table> <?php endif;?> </div> </from> <button><a href="/regist.php">戻る</a></button> </main> <footer> <a href="/form.php" id="form">問い合わせ</a> </footer> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src = " https://code.jquery.com/jquery-3.0.0.js " ></script> <script src = " https://code.jquery.com/jquery-migrate-3.1.0.js " ></script> <script src="js/task.js"></script> </body> </html>
<?php namespace MyApp; class Customer{ private $_db; public function __construct(){ $this->_connectDB(); } public function post(){ try{ $this->_save(); header('Location: http://'.$_SERVER['HTTP_HOST'].'/customers.php'); }catch(\Exception $e){ $_SESSION['err'] = $e->getMessage(); header('Location: http://' . $_SERVER['HTTP_HOST'].'/regist.php'); } exit; } public function getError(){ $err = null; if(isset($_SESSION['err'])){ $err = $_SESSION['err']; unset($_SESSION['err']); } return $err; } private function _save(){ $sql = "insert into customer (mail,Password,sex,Birthday) values (:mail,:Password,:sex,:Birthday)"; $Birthday = $_POST['year']."/".$_POST['month']."/".$_POST['day']; $stmt = $this->_db->prepare($sql); $stmt->bindValue(':mail',$_POST['mail'],\PDO::PARAM_STR); $stmt->bindValue(':Password',$_POST['pass'],\PDO::PARAM_STR); $stmt->bindValue(':sex',$_POST['sex'],\PDO::PARAM_INT); $stmt->bindValue(':Birthday',$Birthday,\PDO::PARAM_STR); try{ $stmt->execute(); }catch(\PDOException $e){ throw new \Exception('No insert!'); } } public function getDB(){ return $this->_db; } private function _connectDB(){ try{ $this->_db = new \PDO(DSN,DB_USERNAME,DB_PASSWORD); $this->_db->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); }catch(\PDOException $e){ throw new \Exception('Failed to connect DB'); } } }

該当のソースコード

試したこと

var_dump($stmt)で中身を確認した。
ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2020/02/02 07:59

sqlシンタックスエラーとかでてないなら、エラーの表示設定をしましょう。
退会済みユーザー

退会済みユーザー

2020/02/02 07:59

また、インジェクション可能なコードですね。
m.ts10806

2020/02/02 08:12

SQL直実行で正しいデータがとれるかどうかは確認済みですよね? また、$customer->getDB()->prepare($sql) が他者にはどんな機能か分からないので答えようがないですし、 ロジック見ると入力されててもされてなくても重複チェックしようとしてませんか? そもそも作りかけ過ぎてどういう風にしたいのか見えません。
jem32o

2020/02/02 08:14

lintを使って静的にチェックしたところ以下の内容でエラーは出てないです。 $ php -l lint_test.php No syntax errors detected in lint_test.php エラーの表示設定とはどのように行えばいいのでしょうか?
jem32o

2020/02/02 08:15

また今回実行結果が全て以下の条件に当てはまってしまうのは何故なのでしょうか else if($stmt > 0 ){ $mail_err = $mail."は重複してます"; }
m.ts10806

2020/02/02 08:17 編集

提示されたコードだけだと確実にPHPでシンタックスエラーでますよ。 >エラーの表示設定 「PHP エラー表示」で確認してください。
m.ts10806

2020/02/02 08:17

asahina1979さんの仰っているのは「SQLの」ですけどね。
m.ts10806

2020/02/02 08:18

>また今回実行結果が全て以下の条件に当てはまってしまうのは何故なのでしょうか ですから、$customer->getDB()->prepare($sql) が他者にはどんな機能か分からないので答えようがないです。 実装のコードも提示してください。
jem32o

2020/02/02 08:19

$customer->getDB()->prepare($sql) で$sqlを実行し、 $_POST['mail']の重複チェックを行いたいのですが、$stmt > 0の処理でcountの結果で判定できないのは何故なのでしょうか
m.ts10806

2020/02/02 08:21 編集

>$stmt > 0の処理でcountの結果で判定できないのは何故なのでしょうか ですから、$customer->getDB()->prepare($sql) が他者にはどんな機能か分からないので答えようがないです。 実装のコードも提示してください。 標準のPHPにある機能ではないので、作った人しか知りません。 他者には提示されたコードが全てです。 $customerという未定義の変数が何もなのかあなたしか知りません。
jem32o

2020/02/02 08:22

```<?php require_once(__DIR__.'/config.php'); require_once(__DIR__ . '/Regist1.php'); try{ $customer = new \MyApp\Customer(); }catch(Exception $e){ $e->getMessage(); exit; } if($_SERVER['REQUEST_METHOD']=="POST"){ $mail = $_POST['mail']; $sql = "select count(mail) from customer where mail = '$mail"; $stmt = $customer->getDB()->prepare($sql); if(empty($_POST['mail'])){ $mail_err = "メールアドレスが未入力"; }else if(empty($_POST['pass'])){ $pass_err = "パスワードが未入力"; }else if($STMT >0){ $mail_err = $mail."は重複してます"; }else{ $pass = $_POST['pass']; $sex = $_POST['sex']; $year = $_POST['year']; $month = $_POST['month']; $day = $_POST['day']; $customer->post(); } } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Port forio</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/regist.css"> </head> <body> <header> <div class="header container"> <nav class="navbar navbar-expand-sm navbar-light"> <a href="/" class="navbar-brand">TOP</a> <button class="navbar-toggler" data-toggle="collapse" data-target="#menu"> <span class="navbar-toggler-icon"></span> </button> <div id="menu" class="collapse navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item"><a href="/regist.php" class="nav-link">新規登録</a></li> <li class="nav-item"><a href="#" class="nav-link">ログイン</a></li> <li class="nav-item"><a href="/profile.php" class="nav-link">プロフィール</a></li> <li class="nav-item"><a href="/check.php" class="nav-link">診断</a></li> <li class="nav-item"><a href="/task.php" class="nav-link">管理</a></li> </ul> </nav> </div> <form action="" class="form-inline m-4 search"> <input type="search" class="form-control mr-2" placeholder="検索"> <button class="btn btn-primary">検索</button> </div> </form> </header> <main> <h1>新規登録</h1> <form action="/customers.php" method="post"> <div> <?php if(isset($mail_err)):?> <?= $mail_err;?> <?php elseif(isset($pass_err)):?> <?= $pass_err;?> <?php else:?> <table> <tr> <td>1)メールアドレス</td> <td name="mail"><?= $mail;?></td> </tr> <tr> <td>2)パスワード</td> <td name="pass"><?= $pass;?></td> </tr> <tr> <td>3)性別</td> <td name="sex"><?= $sex;?></td> </tr> <tr> <td>4)生年月日</td> <td name="birthday"><?= $birthday;?></td> </tr> </tbody> </table> <?php endif;?> </div> </from> <button><a href="/regist.php">戻る</a></button> </main> <footer> <a href="/form.php" id="form">問い合わせ</a> </footer> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src = " https://code.jquery.com/jquery-3.0.0.js " ></script> <script src = " https://code.jquery.com/jquery-migrate-3.1.0.js " ></script> <script src="js/task.js"></script> </body> </html> コード ```<?php namespace MyApp; class Customer{ private $_db; public function __construct(){ $this->_connectDB(); } public function post(){ try{ $this->_save(); header('Location: http://'.$_SERVER['HTTP_HOST'].'/customers.php'); }catch(\Exception $e){ $_SESSION['err'] = $e->getMessage(); header('Location: http://' . $_SERVER['HTTP_HOST'].'/regist.php'); } exit; } public function getError(){ $err = null; if(isset($_SESSION['err'])){ $err = $_SESSION['err']; unset($_SESSION['err']); } return $err; } private function _save(){ $sql = "insert into customer (mail,Password,sex,Birthday) values (:mail,:Password,:sex,:Birthday)"; $Birthday = $_POST['year']."/".$_POST['month']."/".$_POST['day']; $stmt = $this->_db->prepare($sql); $stmt->bindValue(':mail',$_POST['mail'],\PDO::PARAM_STR); $stmt->bindValue(':Password',$_POST['pass'],\PDO::PARAM_STR); $stmt->bindValue(':sex',$_POST['sex'],\PDO::PARAM_INT); $stmt->bindValue(':Birthday',$Birthday,\PDO::PARAM_STR); try{ $stmt->execute(); }catch(\PDOException $e){ throw new \Exception('No insert!'); } } public function getDB(){ return $this->_db; } private function _connectDB(){ try{ $this->_db = new \PDO(DSN,DB_USERNAME,DB_PASSWORD); $this->_db->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); }catch(\PDOException $e){ throw new \Exception('Failed to connect DB'); } } } コード ``````
m.ts10806

2020/02/02 08:25

質問は編集できますし、こちらのコメント欄ではマークダウン使えませんので。
m.ts10806

2020/02/02 08:29 編集

それにそのコード、自分で組んだのでしたらなぜ$stmtに対して直に > 0 でチェックしようとしたり、mail = '$mail としようとしているのか理解できません。 SQLのエラーは出るでしょうけど。出来上がったSQL見てみたら分かりますよ。
guest

回答1

0

ベストアンサー

幾つもおかしい点があります。

$sql = "select count(mail) from customer where mail = '$mail";

これ、例えばabc@example.comというのがきたら、
select count(mail) from customer where mail = 'abc@example.com
というSQLになりますよね。

エラー出るはずです。直に実行して確認してみてください。

それに、せっかくsetAttributeしているのに、肝心のprepare()のときにtry-catch外れているのでどんなエラーがあっても取得できていません。

また、INSERTで利用しているプリペアドステートメントがSELECTで使われていません。これではSQLインジェクションの脆弱性を突けます。
やろうと思ったら全部取ってこれます。
例えば、' or 1 とか送ってみるといいかもしれませんね(未確認)。

望ましい流れはCRUDいずれも
PDO::prepare → PDOStatement::bindValue → PDOStatement::execute の3ステップでクエリを実行する
です。
(なので、INSERTで書けている人がなぜSELECTで書けないのか理解に苦しむわけで)

あとはPHPマニュアルを確認していきましょう。

PDOprepare()

文を実行する準備を行い、文オブジェクトを返す

はい。prepareはあくまで「準備」です。実行していません。
なので幾ら > 0で確認しようとしてもカウントは取れないわけです。

返り値も

もしデータベースサーバーが正常に文を準備する場合、 PDO::prepare() は PDOStatement オブジェクトを返します。 もしデータベースサーバーが文を準備できなかった場合、 PDO::prepare() は FALSE を返すか PDOException を発行します (エラー処理 の方法に依存します)。

なので、
$stmt = $customer->getDB()->prepare($sql);
で$stmtをvar_dump()して確認してみてください。

それに、変数において大文字と小文字は大別されます

PHP の変数はドル記号の後に変数名が続く形式で表されます。** 変数名は大文字小文字を区別します**

$stmtと$STMTは別物です。

以下のようにやっているのと同じ。

php

1<?php 2$a = ""; 3 4if($A>0){ 5 echo 1; 6}

変数未定義のNoticeが出るはずです。

あとは、先に書いた、
PDO::prepare → PDOStatement::bindValue → PDOStatement::execute の3ステップでクエリを実行するをした上で、実行し、その結果を得るように書けば良いわけです。

PHPでデータベースに接続するときのまとめ#SELECT

上記記事には随所にPHPマニュアルへのリンクがあります。必ず確認してください。
記事だけではなく、PHPマニュアルで仕様確認しましょう。

投稿2020/02/02 22:59

m.ts10806

総合スコア80875

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問