PHPのバージョンが『非推奨』になって久しいのでアップグレード(アップデート)を決行しました。
単にPHPのバージョンを7.xから8.xへ移行(Migrating)しただけではデータベースでエラーが発生してしまいます。
認証方法が変わったことが原因のようなので、phpプログラムも更新しました。
- 多くなった『データベース接続確立エラー』
- PHPのバージョン
- データベースの挙動
- 下位互換性のない変更点
- 更新作業1.データベース接続
- 更新作業2.クエリの実行
- 更新作業3.レコード数とページ数
- PHP8.x対応コード
- データベースチェック
- おわりに
多くなった『データベース接続確立エラー』
手前どもが管理しているウェブサイトがいくつかありますが、閲覧している最中に『データベース接続確立エラー』という表示が出てしまう事がときどきあります。
おそらく1カ月くらい前から頻繁に見るようになったのですが、普段は自己管理下にあるページを見ないので、もしかするとずっと前からあったのかもしれません。
WordPressの管理ページを開いている際にエラーが発生すると下図のようにコメント付きの画面が表示されます。
データベース接続確立エラー
これは、wp-config.php ファイルのユーザー名とパスワードが正しくないか、あるいは mysql77.sakura.sakura.ne.jp のデータベースサーバーに接続できないかのどちらかを意味します。ホスティングサービスのデータベースサーバーがダウンしているかもしれません。
- ユーザー名とパスワードに間違いはありませんか?
- 正しいホスト名を入力しましたか?
- データベースサーバーは動作中ですか?
こうした用語が何を意味しているのか分からない場合は、ホスティングサービスに連絡するべきでしょう。助けが必要であればいつでも WordPress サポートフォーラムを訪れることができます。
データベース接続確立エラー
PHPのバージョン
私たちが契約しているさくらインターネットのレンタルサーバでは、以下のバージョンのPHPを利用できます。
バージョン | 推奨 | サポート |
PHP 8.3 | 推奨 | サポート中 |
PHP 8.2 | 推奨 | サポート中 |
PHP 8.1 | 非推奨 | サポート終了予定 |
PHP 8.0 | 非推奨 | サポート終了 |
PHP 7.4 | 非推奨 | サポート終了 |
PHP 5.6 | 非推奨 | サポート終了 |
PHP 5.4 | 非推奨 | サポート終了 |
PHP 5.3 | 非推奨 | サポート終了 |
PHP 5.2 | 非推奨 | サポート終了 |
データベースを利用しているのはWordPressと独自データを掲載したPHPページです。
WordPressはPHPのバージョンを変更しても問題なさそうです。最新バージョンへの即日対応を目指しているとのことで、私たちのように最新版公開から遅れて変更する者には問題が無いように見えます。
ウェブサイトのアクセス数が減ってしまうことを脅威とみなして、PHPバージョンを最新のものに変更しました。
データベースの挙動
正常な状態であれば、下図のように表(テーブル)が表示されます。
しかしながら、PHP7.4で正常に動作していたデータベース表示ページは、PHP8.0以降のバージョンでは表示されません。
PHPのウェブページが接続エラーになる訳ではなく、データベースへの接続に失敗している点が注目すべきところだと思いました。
画面の最上段に表示されている内容は以下のとおりでした。
Error: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
PHP7.4向けデータベースをPHP8.xバージョンで表示した場合のエラー
英語なので、日本語に訳してみると以下のとおりパラメーターの異常であることがわかります。
エラー:
DeepLで翻訳
SQLSTATE[HY093]:
パラメータ番号が無効です:
バインドされた変数の数がトークンの数と一致しません。
このエラー番号『HY093』は、PHP のエラー、かつ、PDO を利用しているときのエラーです。
PHPの構文は何も書き換えていない状態で、PHPのバージョンだけ変更したときに現れるので、書き間違いではなく、そもそもこれまで使っていたPDO(PHP Data Objects)が使えないということを示唆しています。
【参考】MeKiKi:医療機器検索(クラス分類表/一般的名称)
下位互換性のない変更点
『PHPマニュアル』というウェブサイトによると、『PHP 7.4.x から PHP 8.0.x への移行』において『下位互換性のない変更点』が挙げられています。
そのページには PDO MySQL という項目もありました。
PDO::inTransaction() は、 PDO が管理しているおおよその情報ではなく、 実際のトランザクションの状態を報告するようになりました。 クエリが “暗黙のコミット” に依存していた場合、 PDO::inTransaction() は後に false を返します。 なぜなら、トランザクションが既にアクティブではないからです。
PDO MySQL
わかる人にはわかる文章なのかもしれませんが、まず『トランザクション』とはデータベースの実行や管理などの処理の仕組みみたいなものです。それが『アクティブ』ということは、処理が実行されている、実行できる状態にあるようなときだと思います(詳しくないのでわかりませんが)。
処理に伴って『暗黙のコミット』が存在したようですが、それができなくなるという内容だと思います。
すなわち、PDOの処理(トランザクション)後に自動的に行われていた暗黙的なコミットが行われない、その時点で false を返すということで、処理が止まることを意味している、かなと思います。
『PHPマニュアル』というウェブサイトには『MySQL 関数 (PDO_MYSQL) 』というページもあり、そちらにMySQL 8 という項目がありました。こちらには PDO に関する記述がたくさんありますが、理解できませんでした。
とりあえず、PDOは使えなくなったので、新たなMySQLの利用方法を考えてください、ということのようです。
更新作業1.データベース接続
元のコードでは、下記のような記述でした。
$dsn = 'mysql:host=mysql777.db.sakura.ne.jp;dbname=データベース名;charset=utf8';
$user = 'ユーザー名';
$password = 'SQLのパスワード';
$dbh = new PDO($dsn, $user, $password);
(以下省略)
変数『$dsn』に『mysql』『dbname』『charset』の順でデータを登録しておき、『$dbh』で PDO を実行する内容でした。
新しいコードでは PDO の代わりに mysqli を使います。以下のコードに書き換えました。
$servername = 'mysql777.db.sakura.ne.jp';
$dbname = 'データベース名';
$username = 'ユーザー名';
$password = 'SQLのパスワード';
$connsql= new mysqli($servername, $username, $password, $dbname);
if ($connsql->connect_error)
{
die("Connection failed: ".$connsql->connect_error);
print('Error:'.$e->getMessage());
$errors['error'] = "データベース接続失敗しました。";
}
(以下省略)
冒頭で変数にデータを入れていきます。
SQLに接続するために『new mysqli』で『$connsql』へ処理を渡します。
『$connsql』にエラーが無い事を『if』で確認します。
データベースへの接続はこれで確立しました。
更新作業2.クエリの実行
元のコードでは、下記のような記述でした。
$strSelect = "SELECT * FROM ○○○○";
$strOrderLimit = " ORDER BY ".$Sort_ID;
$statement = $dbh->prepare($strSelect.$strWhere.$strOrderLimit);
if($statement)
{
$like_Kobetsu_ID = "%".$Kobetsu_ID."%";
$statement->bindValue('1', $Kobetsu_ID, PDO::PARAM_STR);
if($statement->execute())
{
$row_count = $statement->rowCount();
while($row = $statement->fetch())
{
$rows[] = $row;
$General_Name = $row['項目名'];
}
}
else
{
$errors['error'] = "検索失敗しました。";
}
$dbh = null;
}
正しいデータが『$statement』に格納されていれば、それを1行ずつ読込んで『$row』として扱えるようにしてください、といった処理です。その処理は PDO で行われています。
新しいコードでは、接続が mysqli で接続が確立している『$connsql』にクエリ『$sql』を適用して実行します。
該当するデータが1件以上であれば表示のための処理を実行します。件数を取得し、その件数分だけwhileで循環させるという処理は旧構文と同じです。
最後に『$connsql->close』で接続を切断します。
$sql = $strSelect.$strWhere.$strOrderLimit;
$result = $connsql->query($sql);
if ($result->num_rows > 0)
{
$row_count = $result->num_rows;
while($row = $result->fetch_assoc())
{
$rows[] = $row;
$General_Name = $row['項目名'];
}
}
else
{
$errors['error'] = "データは0件です。";
}
$connsql->close();
更新作業3.レコード数とページ数
レコード数が多いデータベースでは、1度に表示する件数を抑えていました。多い物ですと100万件を超えるデータが格納されているので、全件表示は不可能でした。
元のコードでは、下記のような記述でした。全部で何件あるかを『$Max_row_count』に格納、それを1回の表示上限数である変数『MAX』で除して『ceil』で整数化してページ数を取得するという記述です。
$Max_statement = $dbh->prepare($strSelect.$strWhere);
if($Max_statement)
{
if($Max_statement->execute())
{
$Max_row_count = $Max_statement->rowCount();
$Max_Page = ceil($Max_row_count / MAX);
}
}
新しいコードでも実施内容は同じです。『$sql_max』と『$result_max』は最大値を取得するための処理ですが、内容はクエリの実行と同じです。
$sql_max = $strSelect.$strWhere;
$result_max = $connsql->query($sql_max);
$Max_row_count = $result_max->num_rows;
$Max_Page = ceil($Max_row_count / MAX);
PHP8.x対応コード
実際にPHP8.3でも動作したPHP構文は以下のとおりです。一部、機密に関わる部分は差し替えてます。参考程度にご覧ください。
$servername = 'mysql777.db.sakura.ne.jp';
$dbname = 'データベース名';
$username = 'ユーザー名';
$password = 'SQLのパスワード';
$connsql = new mysqli($servername, $username, $password, $dbname);
if ($connsql->connect_error)
{
die("Connection failed: " . $connsql->connect_error);
print('Error:'.$e->getMessage());
$errors['error'] = "データベース接続失敗しました。";
}
$strWhere = "";
$strShubetsu = '全件表示';
ini_set("memory_limit", "3072M");
$strSelect = "SELECT * FROM ○○○○ a left join ◇◇◇◇ b on a.項目1 = b.項目2";
$strOrderLimit = " ORDER BY ".$Sort_ID." " Desc LIMIT ".$RecordNumber.", ".MAX;
$sql_max = $strSelect.$strWhere;
$result_max = $connsql->query($sql_max);
$Max_row_count = $result_max->num_rows;
$Max_Page = ceil($Max_row_count / MAX);
$sql = $strSelect.$strWhere.$strOrderLimit;
$result = $connsql->query($sql);
if ($result->num_rows > 0)
{
$row_count = $result->num_rows;
while($row = $result->fetch_assoc())
{
$rows[] = $row;
$General_Name = $row['項目3'];
$Class_1_4 = $row['項目4'];
}
}
else
{
$errors['error'] = "検索は失敗しました。";
}
$connsql->close();
データベースチェック
更新作業を終えたデータベースをすべて確認していきました。全件表示、キーワード検索などを実施して正常動作を確認しました。
医療機器クラス分類表検索
医療機器クラス分類表検索
医療機器回収・改修情報検索(PMDA+MHLW)
医療機器認証・承認基準検索(PMDA)
医療機器添付文書検索(PMDA)
サンプルデータ:04582270690137
医療機関検索(医科・歯科)
保険調剤薬局検索
医療機関施設基準検索
地域防災計画都市別データベース
災害アーカイブ(デジタル画像検索)
おわりに
今回はPHPのバージョンを非推奨から推奨へ、7.4から8.3へとアップグレード(アップデート)しました。
それに伴い、PHPウェブページで表示していたデータベースが接続不可となったため、コードの書き換えを行いました。新しい構文を使わなければならないので、正常動作に辿り着くまでに時間を要し、その後の検証もエラーが出そうな箇所がわからないので時間がかかりました。
とりあえず、この記事を書き終えている時点では問題ありません。
変更動機となった、WordPressページの表示エラー、データベース接続エラーについては、改善されたかわかりません。PHPのバージョンの問題であったとすれば、今後は大丈夫だと思いますが、様子観察して参ります。
「[備忘録]PHP7.4⇒8.0 アップ … ウェブページのデータベース接続構文を変更 | AmpiTa Project」への3件の返信
[…] その経過については下記サイトで紹介しています。ご興味があればご覧ください。 […]
[…] その経過については下記サイトで紹介しています。ご興味があればご覧ください。 […]
[…] PHP7.4⇒8.0 アップ … ウェブページのデータベース接続構文を変更 […]