読者です 読者をやめる 読者になる 読者になる

hiroshi akutsuの日記

主にプログラミング関係のこと

snappy【generateFromHtml()で日本語ファイル名を出力した際にエラー】

phpでwkhtmltopdfを使ってpdf出力しようと思って、snappyをcomposerからインストールした。

下記を参考にした。qiita.com

github.com

ファイルで保存したかったのでgenerateFromHtmlメソッドを使った。
サンプルが動くのを確認して、張り切って日本語ファイル名を出力してみたらエラー。。。

たらたらと以下のようなエラーメッセージが

Uncaught exception 'RuntimeException' with message 'The file 'あいうえお.pdf' was not created (command: /usr/local/bin/wkhtmltopdf --lowquality --encoding 'utf-8' '/tmp/knp_snappy56440646c1c9f9.19491186.html' '.pdf')....


仕方がないので調査開始。

まず環境

Centos7
Apache 2.4
PHP5.6
wkhtmltopdf0.12.2

1.wkhtmltopdfがおかしい?

→まず普通にターミナルからwkhtmltopdfコマンドで日本語名のファイル出力
普通にできる。

2.であれば渡すコマンドがおかしい?

→snappyのAbstractGeneratorクラスでコマンドのエスケープ処理に、escapeshellargを使っていて、そこで日本語などのマルチバイト文字が消えていた。

phpにlocaleが設定されていなかったのが原因。

setlocale(LC_CTYPE, "ja_JP.UTF8");

を、呼び出し元のコードに追加し、snappy側では日本語が認識されたようだが、やはりまだ同じエラー。

3.snappyが呼び出しているsymfonyのProcessクラスを疑う

→snappyではマルチプロセスでwk~コマンドを実行している。
マルチプロセス処理にsymfonyのProcessクラスを利用している。
symfonyではproc_openメソッドでマルチプロセスを実行している。
proc_openの第一引数にはきちんとマルチバイトの文字列がコマンドとしてわたっているのでここでもない。
また標準エラー、標準出力も見てみたが、とくにwkhtmltopdfではエラーは吐いていなかった。

4.proc_openで起動されたプロセスのユーザを疑う

→whoamiコマンドをproc_openの第一引数に渡して実行したらapacheと表示された。
→echo $LANGを渡してみたら「C」と表示された。



これが原因でした。。。

「ja_JP.UTF8」

と表示されていてほしかったところ、$LANGの環境変数で、日本語ではない言語がapacheユーザには適用されていた。

5.Processクラスのソースをいじって、試しに、proc_openコマンドでexport LANG="ja_JP.UTF8"を追加してwkhtmltopdfのコマンドを実行

→やっと日本語ファイル名の出力できた。


実運用時にはsymfonyのソースを直接いじりたくないので、パラメータで渡せないか調べたところ、snappyのコンストラクタの第三引数に配列で渡せばいいことが判明。

次のようにsnappyのインスタンス生成時に第三引数を渡す。

$pdf = new Knp\Snappy\Pdf('/usr/local/bin/wkhtmltopdf', array(), array("LANG" => "ja_JP.UTF8"));

これで万事うまくいった。
調査に3日もかけてしまった。