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

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

ただいまの
回答率

88.64%

PHPの「Warning: Invalid argument supplied for foreach()」エラーについて

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 570

KM46

score 17

PHPのデータベースを利用した掲示板を作成したい

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

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

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

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

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

該当のソースコード

<?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, $db;
    $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() {
    global $db;
    if (isset($_GET["body"])) {
        if ($_GET["body"] == "") {
            echo "<p>内容を入力してください。</p>"; exit;
        }

        $template = "INSERT INTO log (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;
}

試したこと

「DB Browser for SQLite」を利用して確認したところ、
login.db自体は作成されているのですが、テーブル自体がうまく作成できていないみたいです...。
たぶん、該当の部分に問題があると思うのですが...。

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

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

・windows10
・XAMPP

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+4

デバッグしてください。

1.結果を確認すること

    $select_query = "SELECT * FROM log ORDER BY log_id DESC";
    $stmt = $db->query($select_query);
    var_dump($stmt);exit;
    foreach ($stmt as $row) {
        $name = htmlspecialchars($row["user"]);
        $body = htmlspecialchars($row["body"]);
        echo "<div class='log'>$name &gt; $body</div>";
    }

2.SELECT * FROM log ORDER BY log_id DESCをDBに対して実際に実行してみること(sqliteでコマンドから実行する方法例
CREATE TABLEとかも試してみると良いですよ。直接実行して成功しないSQLはプログラムから実行しても成功しません。
SQLテストサービスなども活用してください。(例:SQL Fiddle

3.PDOExceptionをキャッチする仕組みを導入すること

DB接続部

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

問題の箇所

try {
    $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>";
    }
} catch (PDOException $e) {
    var_dump($e);die();
}


※CREATE TABLEに問題があると思うのでしたらそこにも同じようにtry-catch張ってください。
$eはなるべくvar_dump()などで全て出力したほうがより多くの情報を得られます。

デバッグによって問題の切り分けを行い、原因の絞り込み、対策を行っていきます。

蛇足:

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

PHP7.1以上を使いましょう。
5.6ですらサポート終了した今、さすがに5.2は学習対象としてもお世辞にも良いとは言えません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+3

CREATE TABLE IF NOT EXISTS log (                         
    log_id INTEGER PRIMARY KEY,
    user TEXT;
    body TEXT,
);

第2カラムが user TEXT; になってるので、ここで文が終了してしまい、create table 文としては不完全ですね。良く見直してください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

これで解決できませんか?

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

CREATE TABLE IF NOT EXISTS log (                         

原因がわかりました。
上記の文に大量の空欄が含まれていました(-_-;)

CREATE TABLE IF NOT EXISTS log (
上記のように修正したところ、無事にテーブルも作成され、問題なく動いたので報告させていただきます。空白を表示するようにエディターを設定しないといけませんね...。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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