【PHP】アプリケーションからMySQLデータベースへアクセス出来ないとき

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

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);
    }
    
  }

?>

Follow me!