polidog lab

Top About Rss
2021年03月03日

SymfonyのPdoSessionHandlerを使う場合の注意点

今日はPdoSessionHandlerでハマったので記録しておく。

何にはまったのか?

PdoSessionHandlerを利用する際にunix socketでMySQLに接続しようとしたら、PHP Notice: PDOException: SQLSTATE[HY000] [2002] No such file or directoryとエラーがでてしまっていた。

何が原因だったのか?

URL形式で接続先を指定してたためにエラーになっていた。

mysql://user:password@localhost?unix_socket=/cloudsql/xxxxxx:asia-northeast1:vvvvvvv;dbname=hoge_db

上記の形式でした場合 Doctrineだと問題なく接続できるが、PdoSessionHandlerだとうまくいかない。
PdoSessionHandler::buildDsnFromUrl があるが、ここの処理でどうやらうまくunix_socketが認識されないようだ。

原因としてはparse_url()したあとの値の処理の際にqueryに関する部分の処理が考慮されていないのが原因だと思われる。

一方でDoctrineはどのように処理をしているのかというとDATABASE_URL の値をparse_urlしているところまでは一緒といえば一緒だ。
https://github.com/doctrine/dbal/blob/d1b872827c4e80f8b03c39670c296ac44d20b511/src/DriverManager.php#L280

しかしその後parseDatabaseUrlQueryというメソッドでqueryの値も考慮されている。
https://github.com/doctrine/dbal/blob/d1b872827c4e80f8b03c39670c296ac44d20b511/src/DriverManager.php#L360

この違いによりPdoSessionHandlerとDoctrineでは若干DATABASE_URLのフォーマットが異なるようだ。

まとめ

PdoSessionHandlerでunix_socketで接続するときはPDOのDSN形式で接続先の情報を記載すること。

# config/services.yaml
services:
    # ...

    Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
        arguments:
            - 'mysql:dbname=mysql://user:password@localhost?unix_socket=/cloudsql/xxxxxx:asia-northeast1:vvvvvvv'
            - { db_username: myuser, db_password: mypassword }

buildDsnFromUrl ってメソッドを見てDoctrineと同じURL形式は対応できるんだろうと思ってしまったのが今回の敗因。

comments powered by Disqus