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

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

ただいまの
回答率

90.22%

PHPのPDOの記述に起因すると思しきエラー(CPIサーバー)

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,893

arito91

score 9

前提・実現したいこと

PHP・mysql初心者です。

以前、ロリポップサーバーで使用するために作成したCMSを流用してCPIサーバーで使用しようと考えたのですが、上手くいかず、後述のエラーが発生します。これらのエラーは、ロリポップサーバー利用時には確認できませんでした。

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

string(16) "使用する想定のデータベース名" string(67) "mysql:host=127.0.0.1;port:3307;dbname=使用する想定のデータベース名;charset=utf8" 

Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: 1044 Access denied for user 'mysqlログインユーザ名'@'localhost' to database '使用する想定のデータベース名' in /usr/home/ユーザ名/html/ディレクトリ名/init.php on line 8

Warning: PDO::query(): SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected in /usr/home/ユーザーID/html/ディレクトリ名/アドミン画面.php on line 19

Fatal error: Call to a member function rowCount() on a non-object in /usr/home/ユーザー名/html/ディレクトリ名/アドミン画面.php on line 20

該当のソースコード

アドミン画面(一部).php

<?php
ini_set("display_errors", On);
error_reporting(E_ALL);
?>
<?php
    session_start();
    $u = htmlspecialchars($_POST['id'],ENT_QUOTES);
    $p = htmlspecialchars($_POST['pass'],ENT_QUOTES);
    require_once("init.php");
?>

<html>
    <head>
        <title>管理マスター</title>
        <link href="styles/css.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <?php
        $ps = $db->query("SELECT pass FROM member WHERE name='$u'");
        if($ps->rowCount()>0){
            $r=$ps->fetch();
            if($r['pass']===$p){
                $_SESSION['us']=$u;
            ?>
            <script>

            </script>
            <header>
                <h1><a href="master.php"><img src="./images/logo.png"/></a></h1>
            </header>

            <div id="master_flex">
                <div id="master_menu">
                    <!--メニュー-->
                    <?php require_once("左部メニューリンク.php"); ?>
                </div>

                <div id="master_contain" class="toppage">
<!--------------------下層ページリンクHTML部分-------------------->
                </div>
            </div>
            <?php
                }else{
                    session_destroy();
                ?>
                <p>パスワードが違います。</p>
                <a href="index.php">ログイン画面に戻る</a>";

            <?php
                }
            }else{
                session_destroy();
            ?>

            <p>IDとパスワードは正しく入力してください。</p>
            <a href="index.php">ログイン画面に戻る</a>
            <?php
            }
            ?>
    </body>
</html>


init.php

<?php
    require_once("./dbcheck/check.php");
    $dsn = "mysql:host=$SERV;dbname=$DBNM;charset=utf8";
    $db = new PDO($dsn, $USER, $PASS);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    $db->query("USE `$DBNM`");
?>


check.php(CPI時)

<?php
    $SERV="127.0.0.1;port:3307";
    $USER="mysqlログインユーザ名";
    $PASS="mysqlパスワード";
    $DBNM="使用する想定のデータベース名";
?>


check.php(ロリポップ時)

<?php
    $SERV = "mysql110.phy.lolipop.lan";
    $USER = "ユーザー名";
    $PASS = "パスワード";
    $DBNM = "使用する想定のデータベース名";
?>

試したことなど

ロリポップとはサーバーの指定方法が違うため、check.phpを変更したのですが、それでもうまく繋がらず……。
http://shared-blog.kddi-web.com/products/58を参考に修正したのですが、$SERV = "127.0.0.1:3306";のような記述ではそもそも繋がらず、require_once("init.php");の時点でエラーが発生し、現在の形になりました。
(このような記述は、カゴヤに外部接続を試みたときはうまくいったのですが……。)

データベースが選択されていないという内容と思しきエラー・警告が発生するのですが、mysqlを確認してもデータベース名の誤字などは無さそうで、pass、nameという項目も正しく存在しており、主キーも設定されていました。

記述を目立って変更したのはcheck.phpのみなのですが、この記述が何等かのエラーを起こしているような気がします。
一応ポートの設定は3306も3307も試したのですが、どちらも同じ結果になってしまいました。

解決方法や原因について、ご教授いただけると大変助かります。

何卒よろしくお願いします。

追記(10/24 19:50)

・init.phpのセミコロンの誤記について修正しました。
・ポートについて3306ではなく3307が正しいようでしたので、修正しました。
・init.phpに$db->query("USE $DBNM");を追加したところ、新たに警告が確認できました。
・init.phpにvar_dump($DBNM);、var_dump($dsn);を行った結果を発生したメッセージを最上段に追記しました。
・アドミン画面.phpの詳細を追記しました。

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

両サーバーにおける環境の差異は以下のような形です。

【CPI】
■データベースサーバー
サーバ: 127.0.0.1 via TCP/IP
サーバの種類: MySQL
サーバのバージョン: 5.6.30 - Source distribution
プロトコル バージョン: 10
ユーザ: mysqlログインユーザ名@localhost
サーバの文字セット: UTF-8 Unicode (utf8)

■ウェブサーバー
Apache
データベースクライアントのバージョン: libmysql - 5.5.42
PHP 拡張: mysqli curl mbstring
PHP のバージョン: 5.6.19


■phpMyAdmin
バージョン情報: 4.6.2
【ロリポップ】
■データベースサーバー
サーバ: mysql110.phy.lolipop.lan (mysql110.phy.lolipop.lan via TCP/IP)
Server type: MySQL
サーバのバージョン: 5.6.23-log - MySQL Community Server (GPL)
プロトコルバージョン: 10
ユーザ: mysqlログインユーザ名@IPアドレス
サーバの文字セット: UTF-8 Unicode (utf8)

■ウェブサーバー
Apache
データベースクライアントのバージョン: libmysql - 5.1.73
PHP 拡張: mysqli

■phpMyAdmin
バージョン情報: 4.0.10.15
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+1

SQLSTATE[3D000]というエラーメッセージは、クエリを実行する際にデータベースが選択されていないことを示しています(*)。
https://dev.mysql.com/doc/refman/5.6/ja/error-messages-server.html

 エラー: 1046 SQLSTATE: 3D000 (ER_NO_DB_ERROR)
メッセージ: データベースが選択されていません

ご提示のコードから推測できるケースは、

  • init.php または check.php 内で$DBNMという変数名を誤記している。
  • どこか別の場所で変数$DBNMを unset したり、NULL や空文字に上書きしている。

などです。

そのようなことがないか、もう一度確認してみてください。

 修正

データベース名ではなく、ホスト名(と、ポート番号)の指定に誤りがありました。

check.php の変数$SERVを、以下のように修正してみてください。

 Before
$SERV="127.0.0.1;port:3307";
 After
$SERV="127.0.0.1:3307";


または

$SERV="127.0.0.1;port=3307";


http://php.net/manual/ja/ref.pdo-mysql.connection.php

より完全な例は、このようになります。
mysql:host=localhost;port=3307;dbname=testdb

どういうわけか、DSN文字列にPDOまたはMySQLが解釈できないオプションが含まれている場合にも
SQLSTATE[3D000]というエラーが返されるようです。
(紛らわしいですねw)

 追記

どういうわけか、DSN文字列にPDOまたはMySQLが解釈できないオプションが含まれている場合にも 
SQLSTATE[3D000]というエラーが返されるようです。 

について追って確認してみたところ、正しくは

DSN文字列にPDOまたはMySQLが解釈できない文字列が含まれている場合、【それ以降のオプションが無視される】。


という動作になるようです。

port:3307のように、解釈不可能な文字列をDSNの先頭や末尾など、様々な位置に挿入してみると、
挿入した位置によってエラーの内容が変わることが確認できました。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/24 19:47

    var_dumpを追記してみたところ、以下のような形で表示されました。
    (ポートは3307番が正しかったようなので、書き換えました。)
    見た感じ、それぞれに入っている変数はcheck.phpに入っているものと同様のものが入っているようです。

    string(16) "使用する想定のデータベース名" string(67) "mysql:host=127.0.0.1;port:3307;dbname=使用する想定のデータベース名;charset=utf8"

    キャンセル

  • 2016/10/24 20:04

    情報の追記、ありがとうございます。

    回答を追記しましたので、確認願います。
    (当初の回答は見当違いでした)

    キャンセル

  • 2016/10/24 20:23

    先ほど追記していただいた内容で編集を行ったところ、無事管理画面へのログインに成功しました!
    かなり詰まっていたところなので非常に助かりました。

    皆様、貴重なお時間でご協力いただきありがとうございました。

    キャンセル

0

1番目のエラーメッセージの通りデータベースが選択されていないので、どのデータベースに対してクエリを実行してよいかわからずエラーとなっているようです。DB接続はできているのでホストやポートまわりの設定は問題ないと思います。

なぜロリポップでは動くのかわからないのですが、DSNの記述方法がまちがっているようです。

// 修正前
$dsn = "mysql:host=$SERV;dbname=$DBNM,charset=utf8";

// 修正後
$dsn = "mysql:host=$SERV;dbname=$DBNM;charset=utf8";

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/24 10:16

    ご回答ありがとうございます。

    こちらについて、ロリポップのファイルのほうでは修正後の状態になっており、今回編集するにあたって誤って操作してしまったようです。大変失礼致しました。

    修正してみたのですが、質問に書いたエラー表示が直らず、修正前・修正後ともに同様のエラーが発生することを確認しました。
    (ロリポップサーバーでは、;が,になっているとinit.phpの4行目でエラーが出るようでした。)

    キャンセル

0

対処療法として、init.php の最後(setAttributeした次の行)に下記コードを追加してデータベースを明示的に指定してみてください。

$db->query("USE `$DBNM`");

もしこれでエラーが無くなれば、やはり MySQLサーバー 接続時にデータベースの選択が何らかの理由でできていないと思われます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/24 19:14

    setAttributeした次の行に追記したところ、既存の警告・エラーに加えて以下のような警告が新たに表示されました。
    シンタックスエラーと表示されているので、何らかの誤記が存在している形でしょうか……?

    Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: 1044 Access denied for user 'mysqlログインユーザ名'@'localhost' to database '使用する想定のデータベース名' in /usr/home/ユーザ名/html/ディレクトリ名/init.php on line 6

    キャンセル

-1

nameは予約後だからquartで囲ってないときのエラーに見えますが

nameを ` で囲ってください

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/24 10:04 編集

    ご回答ありがとうございます。

    該当部分を
    $ps = $db->query("SELECT pass FROM member WHERE name='$u'");

    $ps = $db->query("SELECT pass FROM member WHERE `name`='$u'");
    に変更してみたのですが、該当のエラーは解消できないままでした……。
    pass、memberもクォートで囲うのも試してみましたが、その場合もうまく動きませんでした。

    キャンセル

  • 2016/10/24 15:41

    name は予約語ではなく "nonreserved keyword" です(*)。
    そのため、バッククォートで囲む必要はありません。

    * 下のリンクの表で NAME に"(R)"が付いていないことから、それが分かります。

    https://dev.mysql.com/doc/refman/5.7/en/keywords.html
    > Nonreserved keywords are permitted as identifiers without quoting.

    キャンセル

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

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