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

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

ただいまの
回答率

87.61%

php7移行でMysqlからデータが取れません。

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 5,093

score 10

前提・実現したいこと

素人です。すみませんが助けてください。php5.6からphp7に対応しようと思っています。
php5.6の状態でプログラムを書き換えてテストしています。
mysqlをmysqliに書き換えましたが、画面が真っ白になってしまいます。
思い当たる二つのプログラム(a.phpとb.php)のmysqlをmysqliに変更しました。
以下のようにエラーがあるとこがわかりました。
Warning: mysqli_query() expects at least 2 parameters, 1 given in C:\xampp\htdocs\html\functioni.php on line 227
Warning: mysqli_query() expects at least 2 parameters, 1 given in C:\xampp\htdocs\html\functioni.php on line 231
Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result, null given in C:\xampp\htdocs\html\functioni.php on line 241
現在は、c.phpでWarning: Invalid argument supplied for foreach() in C:\xampp\htdocs\html\output\schedule.php on line 50
50行目はforeach($ary_imm as $key => $value){?>
となっています。
正常動作するコードは、

//////////////// 一つ目 ////////////////////////
a.php
function get_sql_data($sql,$charset = "SJIS",$flag = 0){
    //文字セットSQLを実行
    mysql_query("SET NAMES ".CHARDB); //SJIS対応

    //SQLを実行
    $sql = mb_convert_encoding($sql,CHARDB,CHAR2);
    $rs = mysql_query($sql);

    //データを返す
    if($flag == 1){
        //レコード数取得
        $rwcnt = mysql_num_rows($rs);
        return $rwcnt;
    } else {
        //レコードをリスト化
        $ary = array();
        while($row = mysql_fetch_array($rs)){
            array_push($ary,$row);
        }

        mb_convert_variables(CHAR2 , CHARDB , $ary);
        return $ary;
    }

    //データを開放
    mysql_free_result($rs);
}
//////////////// 二つ目 ////////////////////////
b.php
<?php
if (empty($dbHandle)) {

    if($_SERVER['SERVER_NAME']=="www.***.co.jp" or $_SERVER['SERVER_NAME']=="***.co.jp"){
        $mysqlHst = "****.ne.jp";//UTF8 DB
        $mysqlUsr = "+++++";
        $mysqlPsw = "-----";
        $mysqlDB  = "*****";
    }elseif($_SERVER['SERVER_NAME']=="www.***.jp" or $_SERVER['SERVER_NAME']=="***.jp"){
        $mysqlHst = "****.ne.jp";//UTF8 DB
        $mysqlUsr = "+++++";
        $mysqlPsw = "-----";
        $mysqlDB  = "*****";
    }elseif($_SERVER['SERVER_NAME']=="***.jp"){
        $mysqlHst = "****.ne.jp";//UTF8 DB
        $mysqlUsr = "+++++";
        $mysqlPsw = "-----";
        $mysqlDB  = "est-ouest";
    }else{
        $mysqlHst = "localhost";//UTF8 DB
        $mysqlUsr = "root";
        $mysqlPsw = "-----";
        $mysqlDB  = "*****";
    }

    $dbHandle = @mysql_connect($mysqlHst, $mysqlUsr, $mysqlPsw);     //MySQL接続
    if ($dbHandle == False) {
        print("SQL Server connection error\n"); 
        exit;
    }

    if(!mysql_select_db($mysqlDB, $dbHandle)) {                     //データベース接続
        print("Database connection error\n");
        exit;
    }
}
?>

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

エラーは、Fatal error: Call to undefined function get_sql_data() in C:\xampp\htdocs\html\output\c.php on line 30
30行目は、$ary_imm = get_sql_data($sql);

エラーの出たc.phpの一部
<?php
intval($year);
$year1 = $year+1;
$year2 = $year;
//**************************************************************************************
//        ■ Loading MySQL
//**************************************************************************************
include("a.phpとb.php.php");
if($year != 2019){                                                            
$sql  = "SELECT * FROM auctionresults WHERE start > '".$year2."' and start < '".$year1."' ";
}else{
$sql  = "SELECT * FROM auctionresults WHERE start >= '".$year."' ";    
}
$sql .= "ORDER BY start DESC ";
$ary_imm = get_sql_data($sql);
@mysqli_close($db);
//**************************************************************************************

function compareDate($year1, $month1, $day1, $year2, $month2, $day2) {
    $dt1 = mktime(0, 0, 0, $month1, $day1, $year1);
    $dt2 = mktime(0, 0, 0, $month2, $day2, $year2);
    $diff = $dt1 - $dt2;
    $diffDay = ceil($diff / 86400);//1日は86400秒
    return $diffDay;
}

foreach($ary_imm as $key => $value){?>
<section class="schedule" <?php if($key%2 == 0){ print "style='background-color:#fafafa;'"; }?>>
<?php
$filename = 'images/books/cover'.$ary_imm[$key]["id"].'.jpg';
if(file_exists($filename)){ $bookscover = $ary_imm[$key]["id"]; }else{ $bookscover = "noimage"; }
?>
<img src="images/books/cover<?php print $bookscover;?>.jpg" alt="cover" style="float:left;width:115px; height:150px; margin-right:20px; border:1px solid #ccc;"/>

該当のソースコード

function get_sql_data($sql,$charset = "SJIS",$flag = 0){
    //文字セットSQLを実行
    mysqli_query(CHARDB."SET NAMES "); //SJIS対応

    //SQLを実行
    $sql = mb_convert_encoding($sql,CHARDB,CHAR2);
    $rs = mysqli_query($sql);

    //データを返す
    if($flag == 1){
        //レコード数取得
        $rwcnt = mysqli_num_rows($rs);
        return $rwcnt;
    } else {
        //レコードをリスト化
        $ary = array();
        while($row = mysqli_fetch_array($rs)){
        array_push($ary,$row);
        }

        mb_convert_variables(CHAR2 , CHARDB , $ary);
        return $ary;
    }

    //データを開放
    mysqli_free_result($rs);
}
////////// これより二つ目 //////////////////////////////
<?php
if (empty($dbHandle)) {

    if($_SERVER['SERVER_NAME']=="www.****.co.jp" or $_SERVER['SERVER_NAME']=="****.co.jp"){
        $mysqlHst = "*****.ne.jp";//UTF8 DB
        $mysqlUsr = "******";
        $mysqlPsw = "******";
        $mysqlDB  = "******";
    }elseif($_SERVER['SERVER_NAME']=="www.****.jp" or $_SERVER['SERVER_NAME']=="****.jp"){
        $mysqlHst = "*****.ne.jp";//UTF8 DB
        $mysqlUsr = "******";
        $mysqlPsw = "******";
        $mysqlDB  = "******";
    }elseif($_SERVER['SERVER_NAME']=="*****.ne.jp"){
        $mysqlHst = "******.ne.jp";//UTF8 DB
        $mysqlUsr = "******";
        $mysqlPsw = "******";
        $mysqlDB  = "******";
    }else{
        $mysqlHst = "localhost";//UTF8 DB
        $mysqlUsr = "root";
        $mysqlPsw = "******";
        $mysqlDB  = "******";
    }

    $dbHandle = mysqli_connect($mysqlHst, $mysqlUsr, $mysqlPsw, $mysqlDB);     //MySQL接続

    if (mysqli_connect_errno()) {
        printf("Connect failed: %s\n", mysqli_connect_error());
        exit();
    }

    *1 if ($result = mysqli_query($dbHandle, "SELECT DATABASE()")) {
    $row = mysqli_fetch_row($result);
    printf("Default database is %s.\n", $row[0]);
    mysqli_free_result($result);
    }

    mysqli_select_db($dbHandle,"*****") ;

    *1 if ($result = mysqli_query($dbHandle, "SELECT DATABASE()")) {
    $row = mysqli_fetch_row($result);
    printf("Default database is %s.\n", $row[0]);
    mysqli_free_result($result);
    }
}

試したこと

上記*1のように結果を表示してみたところ画面にはDefault database is **. Default database is **. と表示しているのでデータベースにはアクセスできていると思っています。
実際には*1は不要なので削除しています。

教えていただいたサンプルコードを基にa.phpを変更しました。当初のエラーは出なくなりましたが別のc.php(実際に抽出して画面表示するプログラム)でエラーを表示しました。
Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\html\output\schedule.php on line 50
50行目は、foreach($ary_imm as $key => $value){?>

a.php
function get_sql_data($sql,$charset = "SJIS",$flag = 0){
$link = mysqli_connect("localhost", "root", "estouest");

if(mysqli_connect_errno() > 0){

    die("接続失敗" . mysqli_connect_error());

}
$db = mysqli_select_db($link, "est-ouest");

if (!$db){

    die("データベースの選択失敗" . mysqli_error());

}
    mysqli_set_charset($link,"utf8");

$sql = mb_convert_encoding($sql,CHARDB,CHAR2);
    $result = mysqli_query($link, "SELECT* FROM news");
if (!$result) {
    die("クエリーが失敗" . mysqli_error());
}
 $ary = array();
        while($row = mysqli_fetch_assoc($result)){
              array_push($ary,$row);
        }



    // MySQLの切断

mysqli_free_result($result);
}

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/02/05 16:36

    あと何度もすみませんが、
    get_sql_data()という関数が呼ばれているのはどこからでしょうか。

    キャンセル

  • kojimak

    2019/02/05 16:54

    エラー個所は
    mysqli_query(CHARDB."SET NAMES ");
    $rs = mysqli_query($sql);
    while($row = mysqli_fetch_array($rs)){ array_push($ary,$row); }
    です。

    キャンセル

  • m.ts10806

    2019/02/05 16:56

    エラー箇所はエラーメッセージに .php line XXと含まれますのでそのままエラーメッセージを追記していただければ良いです。
    ※ただ、回答はしました。この問題だけを解決するのは簡単ですが、「移行」としたときにはこれだけで済まない可能性も高いので、よりクリーンな形へ移行するようにしてください。

    キャンセル

回答 2

+3

下記でエラーがでているということで、

mysqli_query(CHARDB."SET NAMES ");


CHARDBという定数がどこでどう定義されているのか提示内容では分からないですが、
既にコメントで提示したようにmysqli_query()の第1引数は手続き型のみ: mysqli_connect() あるいは mysqli_init() が返すリンク IDである必要があります。
つまり上記の書き方では単にSQLをセットしているだけになっています。
他で下記のような形でちゃんとその情報を渡しているので同じようにするだけ

$result = mysqli_query($dbHandle, "SELECT DATABASE()")

2つ目のmysqli_fetch_array()のところに出ているエラーはmysqli_query()が失敗していて返り値がfalseであるがゆえに、mysqli_fetch_array()どころじゃないといった感じですね。

ではありますが、
現在の作りはかなり非効率に思います。
charsetがSJISなのはともかくとして(今の主流は確かutf8mb4)

文字化け対応にSET NAMESを実行するのは推奨されていません。

初心者がやりがちなミス
SET NAMES あるいは SET CHARACTER SET などで文字コードを指定している

確かにmysql→mysqliへの移行をしたいのは分かりますが、
PDOとmysqliはどっちを使うべき?の質問の回答にあるように、移植性が非常に良くなく、質問者さんのように問題を潰したと思ったらまた問題が・・・と問題対応しているだけで疲弊してしまいます。

できれば上記記事にあるようなPDOへの移行を強くすすめます。

サンプルコード:

答えは「1つ目で出ているエラーではmysqli_connect()の結果linkを第1引数に渡していない」
これは何度もコメントしています。
そこを入れればとりあえず1つ進むはず。

けど、せっかくPHP7ですし、無駄な記述も多いのでPHP7っぽい要素を入れて書き換えてみた。
※文字コードはUTF8前提。もし違うならそこは書き加えてください。その場合の動作の保障はしませんのでエラーが出たら自身で追ってみてください。

<?php
function get_sql_data(String $sql,Bool $record_count = true):array{
    $dbh = connect_db();
    try{
        $rs = mysqli_query($dbh,$sql);

        //データを返す
        if($record_count){
            //レコード数取得
            return ["count"=>mysqli_num_rows($rs)];
        } else {
            //レコード返却
           //蛇足コメント:whileでfetchしても結局全行取り出すならmysqli_fetch_allで第2引数オプション指定するだけでいい
            return mysqli_fetch_all($rs,MYSQLI_ASSOC);
        }

    }catch(mysqli_sql_exception $e){
        var_dump($e);
        die();
    }
    //dbの解放は余程でかい処理をする以外は自動でされるのでなくてもいいと思う。
}

function connect_db(){
    try{
        //蛇足コメント:元のコードではSERVER_NAMEとかで分岐させているけどかなり古いやり方。
       //それなら設定ファイルを別にもってそこから読み出すようにした方がいい。定数定義のファイルとか。「環境毎に変わらない情報」なので。コードを何度も書き換えることになるのでメンテナンス性が悪い
        $dbh = mysqli_connect("***", "***", "***", "***");     //MySQL接続

       //蛇足コメント:SET NAMESは基本使わない。それならmysqli()クラスでnewしてset_charset()した方が自然
        /* 例:PHPマニュアルより引用
    $mysqli = new mysqli("***", "***", "***", "***");
    $mysqli->set_charset('utf8');
        */
        if (mysqli_connect_errno()) {
            printf("Connect failed: %s\n", mysqli_connect_error());
            die();
        }
    //蛇足コメント:これで捕捉できるかは未確認。でもtry-catchは必須。PDOExceptionのほうが正直扱いやすい
    }catch(mysqli_sql_exception $e){
        var_dump($e);
        die();
    }
    return $dbh;
}

var_dump(get_sql_data($sql,false));

蛇足コメントも読んでください。

蛇足コード

ちなみにPDO版。結果は同じ。

<?php
function get_sql_data(String $sql,Bool $record_count = true):array{
    $dbh = connect_db();

    try{
        $stmt = $dbh->query($sql);

        //データを返す
        if($record_count){
            //レコード数取得
            return ["count"=>$stmt->rowCount()];
        } else {
            //レコード返却
            return $stmt->fetchAll();
        }

    }catch(PDOException $e){
        var_dump($e);
        die();
    }
}

function connect_db(){
    try{
        return new PDO("mysql:dbname=***;host=***;charset=utf8mb4"
            ,"***"
            ,"***",
            [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]
        );
    } catch (PDOException $e) {
        var_dump($e);
        die();
    }
}

var_dump(get_sql_data($sql,false));

mysqli版でもpdo版でもですが、本来はSQLには色々あって、
例えばSELECTだとwhere句がついてきたりします。
その場合だとSQLインジェクションの対策もきちんとやってるか?
というのが大事になります。
prepare→bindValueの流れは必須ですね。
今回はそこまで求められていないので書いていませんが。


あと、この記事は読んでいただきたい。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/02/06 10:34

    質問に提示されているエラーは「引数が最低2つ必須だが1つしか与えられていない」です。
    マニュアル参考に組んだのでしたら2つ目の引数を与えたのでしょうけどそれがマニュアルの通りかどうかというのが一点目ですね。
    というか、回答に書いてます。質問者さんのコードでは別の箇所できちんと正しく引数を与えています。
    まずは同じようにするだけですよ?

    キャンセル

  • 2019/02/06 10:45 編集

    ところで
    実際のDBはSJISなんですが?あとプログラム自体の文字コードは?
    無駄なエンコーディングが沢山走っているような気がしてなりません。
    SQL文に対するエンコーディングは正直意味がないように思いますし。
    get_sql_data() に渡されてる$charset どこにも使われてませんし。

    キャンセル

  • 2019/02/06 11:44

    勝手に憶測でサンプルコード作りました。
    pdo版も提示してあります。
    わからないことはPHPマニュアル読んでください。
    というか一通り理解してから作らないとセキュリティリスクたんまり作りこんだ大事故コードになるので(そこから出る損失は計り知れない)
    私が回答に提示した「PHPでデータベースに接続するときのまとめ」の記事などはきちんと読んで理解を進めてください。
    素人であろうと初心者であろうと上級者であろうと何であろうとプログラムは書いた通りにしか動かないので、もしそのコードにセキュリティリスクがあれば容赦なく侵されます。

    キャンセル

0

今出ているエラーはこいつですか?これが起きる原因は3パターン考えられます。
ちなみに起きる原因は、「定義されていない関数が呼び出されている」というものです。

Fatal error: Call to undefined function get_sql_data() in C:\xampp\htdocs\html\output\c.php on line 30

たしかにget_sql_data()は30行目に記述されていますが、その呼び出し先を確認してください。

ケース1:関数の名前が違っている 

function get_sql_bata(){…} とかなっている場合です。

ケース2:外部ファイルに置かれている場合で、それを呼び出す手段が記述されていない

問題のプログラムを見ると、二種類PHPファイルがあるようですが、それを
require_once(外部ファイル.php);で呼びに行くようにしていますか?

PHPはあくまで問い合わせ型の言語であり、個々のサーバーに対して各ファイルが独立しているのでそのファイルの外に関数が置かれている場合、require_once()やinclude_once()などでそのファイルを呼び出さないといけません。

ケース3:サーバールートの外側に置かれているファイルを参照しようとしている

PHPプログラムはサーバのどこに置かれても参照できるものではなく、サーバールート配下でないとPHPを動かすことができません。よくあるミスとしてサーバコンフィグファイル(xxx.conf)のサーバールート設定がhtmlになっているのに、参照しようとしているPHPファイルが同じ階層、あるいは上位に置かれている場合はPHPプログラムを実行することができず、ただの文字列が書かれたテキストファイルとして読み取ってしまいます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/02/23 12:22

    まずは本当にPHP5.6で動いていたプログラムなのか確認してみることです。バックアップとって戻せるなら元に戻してください。その上で関数部分だけをPHP7のときのものに差し替えてください

    キャンセル

  • 2019/02/23 13:56

    ありがとうございます。参考になります。おっしゃるようにちょうどやり直してみたところです。エラーは出なくなりましたが、抽出条件の設定に影響が出たようで、全件抽出表示してしまっています。

    キャンセル

  • 2019/02/23 14:11

    そこは別の質問で投げた方がいいですね。これ以上投げると本題からかなり逸脱してしまいますし。

    キャンセル

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

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

関連した質問

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