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

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

ただいまの
回答率

88.59%

PHPの「Fatal error: Uncaught Error: Call to a member function query() on null」エラーについて

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 4,129

KM46

score 17

PHPのデータベースを利用した掲示板で内容が表示できない

ログインした状態からチャットを入力し、

  • 入力したユーザー
  • 内容

の二点を、SQliteを利用して表示する掲示板を作成したいのですが、
エラーメッセージが表示され上手くいきません。

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

Notice: Undefined variable: db in C:\xampp\htdocs\login-bbs2.php on line 91

Fatal error: Uncaught Error: Call to a member function query() on null in C:\xampp\htdocs\login-bbs2.php:91 Stack trace: #0 C:\xampp\htdocs\login-bbs2.php(72): show_log() #1 C:\xampp\htdocs\login-bbs2.php(28): show_login_contents() #2 {main} thrown in C:\xampp\htdocs\login-bbs2.php on line 91

該当のソースコード

<?php session_start();
$users = array(
    "takeshi" => "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",//test
    "yutaka" => "ee3f7d52ca341c51c694af9288701f4ce43be0ad",//rabit
    "akiko" => "f91a8ee646a277a2f1359709604b99c1b32d9f24",//panda
    "mamoru" => "e08f57d03a1a78d2473c0520cbf0db9d3aadcc49"
);

$savepath = dirname(__FILE__).'/log.db';
$script=$_SERVER["SCRIPT_NAME"];

try {
    $db = new PDO("sqlite:$savepath");
} catch (PDOException $e) {
    echo "接続失敗:".$e->getMessage(); exit;
}

$create_query = <<< __SQL__
CREATE TABLE IF NOT EXISTS log (                         
    log_id INTEGER PRIMARY KEY,
    user TEXT;
    body TEXT,
);
__SQL__;
$db->exec($create_query);

if (isset($_SESSION["login"])) {
    show_login_contents();
}

if (isset($_POST["user"])) {
    check_login();
} else {
    show_login_form();
}

function show_login_form() {
    global $script;
    echo <<< __FORM__
    <div id="loginform">
    <form action="$script" method="POST"><h3>ログインしてください</h3>
    <label>ユーザー名</label><input type="text" name="user" />
    <label>パスワード</label><input type="password" name="pass" />
    <button type="submit">ログイン</button>
    </form></div>
__FORM__;
}

function check_login() {
    global $users, $script;
    if(empty($_POST["pass"])){
        echo "パスワードが入力されていません"; exit;
    }
    if(empty($users[$_POST["user"]])) {
        echo "ユーザーが存在しないかパスワードが違います。"; exit;
    }

    $pass_correct = $users[$_POST["user"]];
    if(sha1($_POST["pass"]) != $pass_correct) {
        echo "ユーザーが存在しないかパスワードが違います。"; exit;
    }

    $_SESSION["login"] = array("user" => $_POST["user"]);
    echo "<a href='$script'>ログインしました!</a>";
}

function show_login_contents() {
    $m = isset($_GET["m"]) ? $_GET["m"]:"";
    switch ($m) {
        case "logout": show_logout(); break;
        case "write": write_log(); break;
        default: show_log(); break;
    }
}

function show_log() {
    global $script, $savefile;
    $user = $_SESSION["login"]["user"];
    echo "<h1>こんにちは、{$user}さん!</h1>";
    echo "現在ログイン中";
    echo "→(<a href='$script?m=logout'>ログアウトする</a>)";
    echo "</ul>";
    echo "<form action='$script' method='get'>";
    echo "<input type='text' name='body' size='40' />";
    echo "<input type='hidden' name='m' value='write' />";
    echo "<input type='submit' value='書き込み' />";
    echo "</form>";
    echo "<h3>掲示板</h3>";

    $select_query = "SELECT * FROM log ORDER BY log_id DESC";
    $stmt = $db->query($select_query); //エラー箇所です

    foreach ($stmt as $row) {
        $name = htmlspecialchars($row["user"]);
        $body = htmlspecialchars($row["body"]);
        echo "<div class='log'>$name &gt; $body</div>";
    }
}

// 次回ここから

function write_log() {
    if (isset($_GET["body"])) {
        if ($_GET["body"] == "") {
            echo "<p>内容を入力してください。</p>"; exit;
        }

        $template = "INSERT INTO chatlog (user,body)".
                    "VALUES(?,?);";
        $stmt = $db->prepare($template);
        $stmt->execute(array($_GET["user"],$_GET["body"]));
        header("location: $script"); exit;
    }
}

function show_logout() {
    global $scripit;
    unset($_SESSION["login"]);
    echo "<a href='script'>ログアウトしました</a>";
    exit;
}

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

・windows10
・XAMPP

PHPのバージョンは5.2.0です。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

show_log()内に$dbは未定義です(エラーそのまま)
とりあえずの解決策で良ければglobalで渡すと良いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/04 11:06

    回答ありがとうございます。
    とりあえず該当のエラーは解消されました。

    キャンセル

  • 2019/06/04 11:08

    はい。本当に「とりあえず」です。
    他のglobalも含めてglobalに頼らない実装が望ましいのは言うまでもありません。

    キャンセル

+2

エラー箇所でvar_dump($db);すれば、たぶんNULLだと思うので、
$db = new PDO("sqlite:$savepath");でアクセスする先のデータベースファイルにphpからアクセスできてないのかもしれない。
ファイル自体のアクセス権が足りないとか、そもそもファイルが存在しないとか。

「DB Browser for SQLite」“SQLite”のデータベースを管理できるソフト - 窓の杜
などSQLiteファイルを観られるツールで読めることを確認するなど。

あるいは、そのスコープで$dbが未定義になっているとか。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/04 11:09

    ありがとうございます。
    教えていただいたツールで確認したところlog.db自体は作成されているのですが、肝心の中身が何も作成されていませんでした。テーブル自体が作成されていないようなので、コード自体を見直してみます。

    キャンセル

  • 2019/06/04 11:15

    「CREATE TABLE IF NOT EXISTS 」って構文がSQLiteで使えないかもしれません。テーブルのSELECTに失敗したときにテーブルを作成するなど、アプローチを見直すべきかと。(もうわかってる話かもしれません、すみません。)

    キャンセル

+2

Fatal error: Uncaught Error: Call to a member function query() on null in C:\xampp\htdocs\login-bbs2.php:91 Stack trace: #0 C:\xampp\htdocs\login-bbs2.php(72): show_log() #1 C:\xampp\htdocs\login-bbs2.php(28): show_login_contents() #2 {main} thrown in C:\xampp\htdocs\login-bbs2.php on line 91


書いてあるとおりで、

オブジェクトのメンバーメソッドの query() を呼び出そうとしたけれど、オブジェクトが null です

なのですから、

    $stmt = $db->query($select_query); //エラー箇所です


この $db が NULL で呼び出しているのです。

なぜかというと、

try {
    $db = new PDO("sqlite:$savepath");
} catch (PDOException $e) {
    echo "接続失敗:".$e->getMessage(); exit;
}


で $db は「グローバルスコープ」で配置されていますから、show_log() 関数内部では見ることができません(関数ローカルの $db という変数と見なされ、初期値指定してないので NULL になる)。

PHP のマニュアルを見て、変数のスコープを意識してください。

※まあ、global 指定するよりは show_log() に引数として $db 渡すようにした方がよいと思いますが

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/04 11:15

    $dbを利用しているshow_log()と、write_log()にグローバルでdbを渡すようにしたところ、今度は以下のようなエラーメッセージが表示されました。

    `Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\login-bbs2.php on line 93`

    m6uさんに教えていただいた「DB Browser for SQLite」を利用して確認したところ、
    db自体は出来ているのですが、テーブルが作成されていないみたいなので、改めて質問させて頂きます。

    キャンセル

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

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

関連した質問

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