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

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

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

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

Q&A

解決済

6回答

886閲覧

掲示板作成中にエラーが出てしまったのですが、原因が分かりません

newyee

総合スコア213

PHP

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

0グッド

1クリップ

投稿2019/02/20 11:36

編集2019/02/21 03:03

PHPの学習で、簡易な掲示板を作成していたのですが、エラーが発生してしまい、解決できない状況です。どなたかご助言頂けましたら幸いです。
以下は自分が作成したコードになります。

php

1<?php 2//1ページに表示される数 3 $num = 10; 4 $dsn = 'mysql:host=localhost;dbname=tennis;charset=utf8'; 5 $user = 'tennisuser'; 6 $password = 'password'; 7 8 $page = 0; 9 if(isset($_GET['page']) && $_GET['page'] > 0){ 10 $page = intval($_GET['page'])-1; 11 } 12 try{ 13 $db = new PDO($dsn,$user,$password); 14 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 15 $stmt = $db->prepare("SELECT * FROM bbs ORDER BY date DESC LIMIT 16 :page, :num"); 17 $page = $page * $num; 18 $stmt->bindParam(':page',$page,PDO::PARAM_INT); 19 $stmt->bindParam(':num',$num,PDO::PARAM_INT); 20 $stmt->execute(); 21 }catch(PDOException $e){ 22 echo "エラー:" . $e->getMessage(); 23 } 24?> 25<html> 26 <head> 27 <meta http-equiv="Content-Type" content="text/html; 28 charset=UTF-8"> 29 <title>掲示板</title> 30 </head> 31 <body> 32 <h1>掲示板</h1> 33 <p><a href="index.php">トップページに戻る</a></p> 34 <form action="write.php" method="post"> 35 <p>名前:<input type="text"name="name"></p> 36 <p>タイトル:<input type="text" name="name"></p> 37 <textarea name="body"></textarea> 38 <p>削除パスワード(数字4桁):<input type="text" name="pass"></p> 39 <p><input type="submit" value="書き込む"></p> 40 </form> 41 <hr> 42 <?php 43 while($row = $stmt->fetch()): 44 $title = $row['title'] ? $row['title'] : '(無題)'; 45 ?> 46 <p>名前:<?php echo $row['name'] ?></p> 47 <p>タイトル:<?php echo $title ?></p> 48 <p><?php echo nl2br($row['body'],false) ?></p> 49 <p><?php echo $row['date'] ?></p> 50 <form action="delete.php" method="post"> 51 <input type="hidden" name="id" value="<?php echo $row 52 ['id']; ?>"> 53 削除パスワード:<input type="password" name="pass"> 54 <input type="submit" value="削除"> 55 </form> 56 57 58 59 60<?php 61 endwhile; 62 63 try{ 64 $stmt = $db->prepare("SELECT COUNT(*) FROM bbs"); 65 $stmt->execute(); 66 }catch(PDOException $e){ 67 echo "エラー:" . $e->getMessage(); 68 } 69 70 $comments = $stmt->fetchColumn(); 71 $max_page = ceil($comments / $num); 72 echo '<p>'; 73 for($i = 1;$i <= $max_page;$i++){ 74 echo '<a href="bbs.php?page=' . $i . '">' . $i . '</a>&nbsp;'; 75 } 76 echo '</p>'; 77 78?> 79 80 81 </body> 82</html> 83

エラーの内容は以下の通りです。
「Fatal error: Uncaught Error: Call to a member function bindParam() on bool in C:\xampp\xampp\htdocs\tennis\bbs.php:18 Stack trace: #0 {main} thrown in C:\xampp\xampp\htdocs\tennis\bbs.php on line 18」

bbs.phpの18行目が原因なのではないかと、見直してみたのですが、つづりのミスなどは見当たらなかった為、原因が分からずご質問させていただきました。
よろしくお願いします。

※追記です。以下のコードはご回答者様に教えて頂きました点などを、コードに加えて変更したコードです。

php

1 2<?php 3//1ページに表示される数 4 $num = 10; 5 $dsn = 'mysql:host=localhost;dbname=tennis;charset=utf8'; 6 $user = 'tennisuser'; 7 $password = 'password'; 8 9 $page = 0; 10 if(isset($_GET['page']) && $_GET['page'] > 0){ 11 $page = intval($_GET['page'])-1; 12 } 13 try{ 14 $db = new PDO($dsn,$user,$password); 15 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 16 $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); 17 $stmt = $db->prepare(" SELECT * FROM `bbs` ORDER BY `date` DESC LIMIT 0,1"); 18 $page = $page * $num; 19 20 //$stmt->bindValue("page",$page,PDO::PARAM_INT); 21 //$stmt->bindValue("num",$num,PDO::PARAM_INT); 22 $stmt->execute(); 23 }catch(PDOException $e){ 24 echo "エラー:" . $e->getMessage(); 25 } 26?> 27<html> 28 <head> 29 <meta http-equiv="Content-Type" content="text/html; 30 charset=UTF-8"> 31 <title>掲示板</title> 32 </head> 33 <body> 34 <h1>掲示板</h1> 35 <p><a href="index.php">トップページに戻る</a></p> 36 <form action="write.php" method="post"> 37 <p>名前:<input type="text"name="name"></p> 38 <p>タイトル:<input type="text" name="name"></p> 39 <textarea name="body"></textarea> 40 <p>削除パスワード(数字4桁):<input type="text" name="pass"></p> 41 <p><input type="submit" value="書き込む"></p> 42 </form> 43 <hr> 44 <?php 45 while($row = $stmt->fetch()): 46 $title = $row['title'] ? $row['title'] : '(無題)'; 47 ?> 48 <p>名前:<?php echo $row['name'] ?></p> 49 <p>タイトル:<?php echo $title ?></p> 50 <p><?php echo nl2br($row['body'],false) ?></p> 51 <p><?php echo $row['date'] ?></p> 52 <form action="delete.php" method="post"> 53 <input type="hidden" name="id" value="<?php echo $row 54 ['id']; ?>"> 55 削除パスワード:<input type="password" name="pass"> 56 <input type="submit" value="削除"> 57 </form> 58 59 60 61 62<?php 63 endwhile; 64 65 try{ 66 $stmt = $db->prepare("SELECT COUNT(*) FROM bbs"); 67 $stmt->execute(); 68 }catch(PDOException $e){ 69 echo "エラー:" . $e->getMessage(); 70 } 71 72 $comments = $stmt->fetchColumn(); 73 $max_page = ceil($comments / $num); 74 echo '<p>'; 75 for($i = 1;$i <= $max_page;$i++){ 76 echo '<a href="bbs.php?page=' . $i . '">' . $i . '</a>&nbsp;'; 77 } 78 echo '</p>'; 79 80?> 81 </body> 82</html> 83

上記のコードを実行した結果が以下の画像となります。
イメージ説明

追記です。
イメージ説明
今、テーブルの構造をコマンドプロンプトで見てみたのですが、「date」カラムがありませんでした。。。
テーブルを作成する際に、dateカラムを作成し忘れていたのかもしれません...

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

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

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

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

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

Nrkw38

2019/02/20 11:46

そのエラーの内容で調べてみた所、prepare()関数がfalseを返す時に出るエラーのようです。 多分SQL文が間違っているとかだと思います。 でも、ちょっと私にはそのSQL文のどこがおかしいのか分からないのですが、多分bindParam()が問題ではないでしょう。
cerfweb

2019/02/20 13:11

エラーの原因とは関係ないかもしれませんが、SQL文のテーブル名及びフィールド名はバッククォートで SELECT * FROM `bbs` ORDER BY `date` のように括ることをお勧めします。サーバによってはフィールド名がバッククォートで括られていないとエラーを返すこともあります。また、括っていた方が処理も若干早くなるようです。
newyee

2019/02/20 13:20

ご指摘ありがとうございます。 バッククォートで括るようにしていきたいと思います。
退会済みユーザー

退会済みユーザー

2019/02/21 01:54

どこで動作させているのか、OSはWindowsとかCentOSとか、テスト環境も詳しく。
guest

回答6

0

ちゃんとエラーモード書こう。話はそれからだ。

php

1 $db = new PDO($dsn,$user,$password); 2 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 3 $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); // <- 追加

投稿2019/02/20 13:58

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

newyee

2019/02/20 14:29

ご丁寧にありがとうございます。 教えて頂きました点を追記しました。質問させていただきました当初と、コードを少し変更しましたので、一度質問内容の方に、追記させていただきます。
guest

0

投稿2019/02/20 12:41

alg

総合スコア2019

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

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

0

ベストアンサー

bindParam警察が来るねw
bindValue()を使うべきだし、
$stmtがbool値、つまるFALSEが入っていたりする、つまり$db->prepare()が失敗している可能性、
そもそも$dbについてもどうなのかとか。


質問内容が改定されたので、回答も変わります。

テーブルのカラムにdateという名称を使うのは避けるべきです。
DATE型というものがデータベース上にあるため、
カラム名に指定する際SQL文では(バッククォート記号で)エスケープしないといけないのと、
dateってそもそもなんの日付なのかって話もあります。
例えば本人の趣味にもよりますが
create_atやpost_at、あるいはcreate_dateやpost_dateなど
後で見て混乱なくわかりやすいカラム名を選択するべきです。

それと Undefined variable: $stmtについてですが、
$dbの定義あたりとかprepare()してるあたりで例外が発生すれば起こりうるだろうと推察されます。
データベースへのPDO接続に失敗している可能性を調べましょう。
mysqlが立ち上がっているか、tennisuserが登録済みなのか、など。


テーブル構造が意図したものになってないので、
一度テーブルを削除(drop table)して、
create table文で作り直したほうがいい。
bodyをdatetime型じゃなく文字列に適した型にしつつ、
dateってカラムも追加するということで。
もしかしてphpmyadmin上で手でコツコツ作ったのかもしれませんが、
SQLファイルを作ってテーブルの作成ができるようになっておくと、
本番環境への反映とかしやすくなりますので是非習得してください。

投稿2019/02/20 12:14

編集2019/02/21 03:12
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

m.ts10806

2019/02/20 12:20

>bindParam警察が来るねw それ以前の問題っぽいのでスルーしてました。 $dbのところってそこで失敗するとPDOException拾いそうな気がしますがどうなんでしょうか・・
newyee

2019/02/20 12:35

ご回答ありがとうございます。 bindvalueにしてみたのですが、やはり、エラーが出てしまいます。エラーは下記の通りです。 「Fatal error: Uncaught Error: Call to a member function bindValue() on bool in C:\xampp\xampp\htdocs\tennis\bbs.php:20 Stack trace: #0 {main} thrown in C:\xampp\xampp\htdocs\tennis\bbs.php on line 20」 「$db」につきましては、「$db = new PDO($dsn,$user,$password);」こちらの直後の行で、var_dump($db)としましたら、「object(PDO)#1 (0) { }」このように表示されました。これはdbに接続できていないということなのでしょうか?
m.ts10806

2019/02/20 12:38

>PDOException拾いそうな気がしますがどうなんでしょうか・・ 自己確認しました。 http://php.net/manual/ja/pdo.construct.php > PDO::__construct() は、 指定されたデータベースへの接続に失敗した場合、 PDOException を投げます。 やはりそうですね。PDOException投げてないならそこは問題なさそうです。
newyee

2019/02/21 01:50

>m6uさん ありがとうございます。 mysqlは正常に立ち上がっており、「tennisuser」で「tennis」データベースへはログインすることには成功しました。SQLは「 " SELECT * FROM `bbs` ORDER BY `date` DESC LIMIT 0,1" 」このように、一旦フィールド名をバッククォートで括っておきました。
退会済みユーザー

退会済みユーザー

2019/02/21 01:57

Windows上でテストしているのであれば、例えばphpからmysqlに接続するときのポート番号が間違っていないかの確認(XAMPP Control Panelなどからポート番号はわかる)とファイアウォールがポートを塞いでいないかの確認、PDOがphpから利用できるのか phpinfo() で確認など。
退会済みユーザー

退会済みユーザー

2019/02/21 02:14

画像みてみ。PDO::ERRMODE_EXCEPTION 設定したんで1行目で回答出てる。
m.ts10806

2019/02/21 02:17

やはり質問にCREATE TABLE文の提示は必須ですね。
newyee

2019/02/21 02:51

「PDO::getAvailableDrivers(); var_dump( PDO::getAvailableDrivers() );」 としまして、実行してみましたところ、「array(2) { [0]=> string(5) "mysql" [1]=> string(6) "sqlite" } 」と表示されましたので、PDOからphpは接続できているのではないかと思います。 ポート番号の確認も、コマンドプロンプトから、確認したのですが、合っていました。
退会済みユーザー

退会済みユーザー

2019/02/21 02:54

dateカラムで並べ替えしようとしたけど、dateなんてカラムがないよ、ってエラーでprepare()失敗。と。 (画像細かく見てなかったわー)
newyee

2019/02/21 03:05

質問本文にも追記したのですが、コマンドプロンプトで、テーブルの構造を確認しましたら、「date」カラムが入っていませんでした... テーブルを作成する際に、追加し忘れていたのかもしれないです...
退会済みユーザー

退会済みユーザー

2019/02/21 03:07 編集

dateカラムがないので、そりゃ並べ替えはできないですよね。 bodyがdatetime型!? create table文がとっちらかってる。 多分このままだと投稿自体記録できないかも。 drop tableしてcreate tableし直したほうが良いかと。
newyee

2019/02/21 03:36

Createtableし直しましたら、エラーが一気に消えました。ありがとうございました。
guest

0

まずは21行目の

$stmt->execute();

のあとに

PHP

1 $rows=$stmt->fetchAll(PDO::FETCH_ASSOC); 2 print_r($rows);

を入れてデバッグですね

細かく追いかけるならfetchする箇所も含めてすべてtryの中でやってみてください

追記

ではもっとソリッドに

PHP

1<?php 2$num = 10; 3$page = 0; 4$dsn = 'mysql:host=localhost;dbname=tennis;charset=utf8;'; 5$user = 'tennisuser'; 6$password = 'password'; 7try{ 8 $db = new PDO($dsn,$user,$password); 9 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 10 $stmt = $db->prepare("SELECT * FROM `bbs` ORDER BY `date` DESC LIMIT :page, :num"); 11 $page = $page * $num; 12 $stmt->bindParam(':page',$page,PDO::PARAM_INT); 13 $stmt->bindParam(':num',$num,PDO::PARAM_INT); 14 $stmt->execute(); 15 $rows=$stmt->fetchAll(PDO::FETCH_ASSOC); 16 print_r($rows); 17}catch(PDOException $e){ 18 die($e->getMessage()); 19} 20?>

投稿2019/02/21 00:54

編集2019/02/21 01:50
yambejp

総合スコア114583

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

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

newyee

2019/02/21 01:39

ご回答ありがとうございます。 教えて頂きました箇所を追記し、更新してみたのですが、なんの変化もありませんでした... 色々な方にご回答いただいているのですが、そもそもなぜ、参考書通りにやっているのに、エラーをはいてしまうのかが疑問といいますか、もしかしたら、参考書通りに勉強を進めている内に自分が重要なミスを犯していたのかもしれないです...
yambejp

2019/02/21 01:51

必要な部分だけ抽出して追記しました
newyee

2019/02/21 01:57

ありがとうございます。 教えて頂きました通り、書き換えてみたのですが、やはりエラーの内容に変化はありませんでした...
guest

0

PDO::ERRMODE_EXCEPTIONの設定とPDOStatement::bindValueに変更してみては?

参考:
PHP で MySQL 接続時に必要な知識(最小限版)

投稿2019/02/20 11:53

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

newyee

2019/02/20 12:26

ご回答ありがとうございます。 リンク拝見させていただきました。一度bindValueにして試してみたいと思います
退会済みユーザー

退会済みユーザー

2019/02/20 12:40

error 内容は、「Call to a member function bindParam() on bool」です。 で、実際 var_dump してその結果を確認してみても bool(false) なのであれば、PDO::prepare() で PDOStatement オブジェクトが返ってきていません。 ERRMODE を変更して EXCEPTION で捕まえてあげると良いです。
guest

0

直前の$stmtをvar_dumpしてみては?
PDO::prepareの返り値がstatementではなくfalseの場合、bindParamどころではないわけですし。
その場合はPDO::prepareにセットしているSQLを見直す必要があります。
文法が合っているかとか存在しないカラム指定してないかとか。

ちなみに。
この手のエラーはエラーメッセージにある行数ズバリよりもその直前の処理や処理結果が原因で起きていることがよくあります。
var_dump()などを効果的に利用し、デバッグする癖をつけると解決が早まります。


補足資料:
MySQLの予約語とキーワード

予約語にあがっているものはそもそもカラムには使えないと思って良いです。
予約語っぽいけど例外的に認められているものもあります。

MySQL では、以前に多くの人々が使用していたので、一部のキーワードを引用符で囲まない識別子として使用することを許可しています。次の一覧に例を示します。

ACTION
BIT
DATE
ENUM
NO
TEXT
TIME
TIMESTAMP

ただ、「その名称だけで何のことかわかるか?」ということもありますし、
紛らわしいので``をつけるだけではなく、きちんと用途や意味が伝わる名前(m6uさんが挙げてくれてますね)にすることを強くすすめます。

もし、その名称によって壁にあたってしまっているのなら、非常に勿体無いです。
idとかもあるかもしれませんが、単にidではなくそれは「何のidか」が分かるようにするのが良いです。

投稿2019/02/20 11:47

編集2019/02/21 00:57
m.ts10806

総合スコア80765

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

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

newyee

2019/02/20 12:25

ご回答ありがとうございます。 「$stmt->bindParam(':page',$page,PDO::PARAM_INT);」こちらの直前の行で「var_dump($stmt)」としてみましたら、bool(false)と表示されました。しかし、何故falseになってしまっているのか、原因はつかめない状態です...
m.ts10806

2019/02/20 12:28

回答に書いてあるようにSQLをまず疑うこと。 試すのは下記: ・:page,:numに固定値を入れてbindParamを一旦コメントアウト ・LIMITから:pageまでにあるよくわからない改行と空白を詰める ・そのうえで同じSQLをDBにログインして直に実行する(MySQL+PHPMyAdminであればそこでも良い) そこまで確認したら状況教えてください。
m.ts10806

2019/02/20 12:56

あと、pageはともかくlimitはシステム側で制御してるから直に入れてもいいような気がします。 また、外部入力情報からくるpageが数値でくる前提なので、数値かどうかのチェックを入れてください。
newyee

2019/02/20 12:58

ご返信ありがとうございます。 >:page,:numに固定値を入れてbindParamを一旦コメントアウト ここの部分につきましては、「$stmt = $db->prepare(" SELECT * FROM bbs ORDER BY date DESC LIMIT:0,1");」こちらのように変更したのですが、合っていますでしょうか...? 実は、「LIMIT:0,1」としたのですが、エラーが出てしまった所でふと気づいたのですが、そもそもエラーが出てしまっていた為、掲示板にコメントを投稿することが一件もできていなかったので、LIMIT句を外し、xamppのshellから直接、「SELECT * FROM bbs;」と打ち込みましたら、「Empty set (0.03 sec)」と表示されました。そもそも、掲示板に一件も投稿していなかったので、これは正しくデータベースには接続できているということなのでしょうか?
m.ts10806

2019/02/20 13:02

LIMIT:0,1 だとSQL構文エラーです。:が残ってます。 LIMIT 0,1 https://www.dbonline.jp/mysql/select/index12.html データがない場合はエラーになりません。0件でもデータオブジェクトは返します。 fetchしているwhileが1週もまわらず終わるだけです。
m.ts10806

2019/02/20 13:03

続き: それはlimitを指定していてもいなくても関係ないです。
newyee

2019/02/20 13:16

LIMIT 0,1 とし、 //$stmt->bindValue("page",$page,PDO::PARAM_INT); //$stmt->bindValue("num",$num,PDO::PARAM_INT); //$stmt->execute(); こちらの3行をコメントアウトをし、更新してみた所、掲示板のフォーム部分は表示されましたが、その下に、またエラーがまた出てしまいました...エラーの内容は以下の通りです... 「Fatal error: Uncaught Error: Call to a member function fetch() on bool in C:\xampp\xampp\htdocs\tennis\bbs.php:45 Stack trace: #0 {main} thrown in C:\xampp\xampp\htdocs\tennis\bbs.php on line 45」 45行目は、htmlのフォーム部分下のここの行です。「 while($row = $stmt->fetch()):」 参考書通りに、コードも書いているので、恐らく自分のPCの設定なのか、自分のコードでどこかでミスをしてしまっているのか、理由は分からないのですが、自分がミスをしてしまっているのだとは思うのですがね...
m.ts10806

2019/02/20 13:29

execute実行しないとSQLの結果受け取れませんよ。
newyee

2019/02/20 13:32

executeした行のコメントを解除して、更新してみたのですが、エラーになってしまい、掲示板のフォームの画面も表示されなくなってしまいました...
m.ts10806

2019/02/20 13:46

今結局どうなってます? 変更した前後だけでもいいので質問に追記しエラーメッセージも追記してください
newyee

2019/02/20 14:42

返信遅れてしまいすみません。 変更後のコードと、実行時の画像を質問本文に追記いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問