PHPアプリケーション内からMySQLデータベースへ接続を行った際、接続出来ないエラーが起きてしまったので原因と解決に至った手段をメモします。
また、記事の最後にPDOを使用した実際のソースコードを貼っておきます。
環境 :
Mac OS High Sierra 10.13.12
PHP 7.1.7
Apache/2.4.28
MySQL Ver 8.0.16 for osx10.13 on x86_64 (Homebrew)
※apacheのvirtual hostで立ち上げたローカルWEBサーバでPHPプログラムを実行
PHP内からMySQLへ接続出来ない。。
原因1. php.iniファイルが存在しない
画面に表示されたエラー
SQLSTATE[HY000] [2002] No such file or directory
phpinfoを利用してブラウザで検証する
検証用に、同環境内でphpinfoの命令を記述したファイルを作成し、PHPの情報をブラウザへ出力する。
<?php phpinfo(); ?>
ページの真ん中の辺り「Loaded Configuration File」の行を確認し、phpからMySQLへ接続するためのファイルが設定されていないことがわかる。
/etc/php.ini ファイルを作成する
(/etcディレクトリ内)
元々存在している、php.ini.default をコピーして php.iniというファイルを作成する
sudo cp /etc/php.ini.default php.ini /etc/php.ini
作成が出来たら、ファイルのパーミッション(権限)を644へ変更する(読み取りと書き込み)
sudo chmod 644 php.ini
ローカル環境のWEBサーバ(apache)を再起動する
sudo apachectl restart
phpinfoの内容を再確認
Loaded Configuration Fileの内容が変わっていることが確認出来る。
/etc/php.iniファイルを編集する
作成した /etc/php.iniへMySQLへ接続するための設定を行う。
sudo vi /etc/php.ini
vi insertモードに切り替えて、以下の行を探して変更を加える
pdo_mysql.default_socket=
ソケットファイルというMySQL接続に必要なファイルの場所を参照するよう変更を加えます。
pdo_mysql.default_socket= /tmp/mysql.sock
/tmp/mysql.sockが消えてしまった場合
php.ini ファイルに変更を加えたら、
/tmp/mysql.sockが消えてしまう現象が起きてしまいました。
同じ事が起こった場合はこちらも確認ください。
mysql.sockを作成し直す。
ファイル作成
sudo touch /tmp/mysql.sock
MySQLを再起動
sudo mysql.server start
WEBサーバ(apache)も再起動
sudo apachectl restart
原因2. MySQLのユーザ認証にPHPが対応していない
再びPHPプログラムからデータベースへアクセス、、
ブラウザ上に、先ほどとは異なるエラーが表示されました。
画面に表示されたエラー
SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
MySQL バージョン8から導入されている「caching_sha2_password」というユーザ認証方法に対して、本記事執筆時点でPHPが対応しきれていないことが原因のようです。
解決策として、接続するMySQLのユーザ認証方法をPHPが対応している旧来の「mysql_native_password」という認証方法へ変更します。
MySQLユーザの認証方式を変更する
ターミナルからrootユーザでMySQLへ接続
mysql -u root
mysqlデータベースを選択
use mysql
Userテーブルからユーザ名と認証方法の列を表示する
SELECT User, Plugin FROM User
接続したいユーザの認証方法が「caching_sha2_password」である事が確認出来る。
– ユーザ認証方法を変更するSQL –
以下のSQL文で認証方法を「mysql_native_password」へ変更する
ALTER USER ユーザ名@localhost IDENTIFIED WITH mysql_native_password BY ‘パスワード’
ALTER USER shop_admin@localhost IDENTIFIED WITH mysql_native_password BY 'shop_admin';
– /usr/local/etc/my.cnf へ設定を行う –
次に、/usr/local/etc/my.cnfという設定ファイルを編集してデフォルトの認証方式を追記します。
(こちらも行わないとプログラムから接続出来ませんでした)
sudo vi /usr/local/etc/my.cnf
インサートモードに切り替え、[mysqld] 項目の一番下へ
default_authentication_plugin= mysql_native_password
の記述を追加する。
ファイルを編集して保存が完了したらMySQLを再起動
sudo mysql.server start
WEBサーバ(apache)も念のため再起動を行っておきます。
sudo apachectl restart
以上でPHPプログラムからMySQLデータベースへ正しく接続が行えました。
解決に辺り以下の記事を参考にさせていただきました。
https://blog.codecamp.jp/php-ini
https://qiita.com/KenjiOtsuka/items/8e520f53df2ae84f75e9
本記事の実際のソースコード
index.php
<?php //require_once('ShopDataSource.php'); require_once(__DIR__.'/ShopDataSource.php'); $dataSource = new ShopDataSource(); $shops = $dataSource->getAll(); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>店舗一覧</title> <div> <ul> <?php foreach($shops as $shop) :?> <li><?php echo $shop->name ?></li> <?php endforeach; ?> </ul> </div> </head> <body> </body> </html>
ShopDataSource.php
<?php ini_set('display_errors', 1); define('DSN', 'mysql:host=localhost;dbname=shop_search'); define('DB_USERNAME', 'shop_admin'); define('DB_PASSWORD', 'shop_admin'); class ShopDataSource { private $_db; public function __construct(){ try { $this->_db = new PDO(DSN, DB_USERNAME, DB_PASSWORD); $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e){ echo $e->getMessage(); exit; } } public function getAll(){ $stmt = $this->_db->query("SELECT * FROM shop ORDER BY id DESC"); return $stmt->fetchAll(PDO::FETCH_OBJ); } } ?>