snappy【generateFromHtml()で日本語ファイル名を出力した際にエラー】
phpでwkhtmltopdfを使ってpdf出力しようと思って、snappyをcomposerからインストールした。
下記を参考にした。qiita.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」
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日もかけてしまった。
vba【大量の複数の印刷範囲の設定の仕方】
忘れやすいのでメモ。
vbaのPageSetup.PrintAreaプロパティはセル範囲をA1形式の文字列で設定し、複数の範囲にしたい場合はカンマで区切れば複数範囲の印刷設定が可能である。
こんな風に...
ActiveSheet.PageSetup.PrintArea = "A1:G5,A8:G13"
しかし、なぜそんな制限(というか仕様)にしてしまったのかよくわからないが、残念なことに設定値の文字列が255文字を超えたらエラーになる。
どうすべきかと言えば、一旦印刷範囲をUnionでrangeオブジェクトにして、Nameプロパティでセルに名前を付けて、PrintAreaプロパティに付けた名前を渡せばいい。
Dim ra As Range Set ra = Range("A1:G5") Set ra = Union(ra,"A8:G13") '''ループでどんどんUnionしていくイメージ ra.Name = "印刷範囲" ActiveSheet.PageSetup.PrintArea = "印刷範囲"
excel 2013,2010では動くのを確認できたが、それ以前のバージョンは不明。
vba【コールバックぽく処理を記述】
たとえば、findnextを使って、検索にヒットするすべてのセルに処理を行いたいとします。
こういう時は、コールバックが使えたら便利だなと思っていました。
ただvbaにコールバック関数的なものがあるのか分かりませんが、callbyname関数があってこれを使うとそれっぽくできるとのことなのでやってみたメモを残します。
コールバックする関数はクラスモジュールのCommonMethodsというクラスを作って、そこにパブリックメソッドとして記述します。
第1引数に検索でhitしたセル(findAll関数から渡される)
第2引数にコールバックの大元から送った引数(mainサブルーチンから渡される)
Public Sub changeColor(ByVal fcell As Range, ByRef co As Collection) fcell.Interior.ColorIndex = co(1) End Sub
findnextのループを行う関数はつぎのようになります。
標準モジュールや、クラスモジュールの場合はメソッドとして記述します。
第1引数に検索範囲
第2引数に検索テキスト
第3引数にコールバック関数名のstring
第4引数にコールバック関数に渡す引数のCollection
Private Sub findAll(ByVal ra As Range, ByVal whattxt As String, ByVal callback As String, ByVal callback_args As Collection) Dim fcell As Range Dim fadd As String Set fcell = ra.Find(what:=whattxt, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=True) If Not fcell Is Nothing Then fadd = fcell.Address Do CallByName New CommonMethods, callback, VbMethod, fcell, callback_args Set fcell = ra.FindNext(fcell) If fcell Is Nothing Then Exit Do End If If fcell.Address = fadd Then Exit Do End If Loop End If End Sub
あとはmainから呼び出します。
Sub main() Dim callback_args As New Collection callback_args.Add 10 Call findAll(Cells, "test", "changeColor", callback_args) End Sub
コールバック関数をクラスモジュールに書いているのが若干気持ち悪いです。
javascriptのように無名関数を渡せると非常に勝手がいいなと思いますが、まあそこまでなくても希望の動きはできました。
Virtualbox【guest additionsを入れてもFHD(1920*1080)にならない】
ついこないだまでは、普通にGuest AdditionsをCentOSのデスクトップにインストールすることで、FHDの画面が表示できていた。
しかしこないだVirtualboxのバージョンアップしたところ、FHDにならなくなってしまった。
アイコンもデカいし、文字もデカい。これでは開発環境として使い物にならない。
まあなんかの不具合なんだろうが、対処法が分かったのでメモ。
現在の問題のVirtualboxのバージョンは4.3.28 r100309。
ホストはwindows 7。
色々調べた結果、問題の現象は、仮想マシンのshutdown時にホスト側の仮想マシンのウィンドウをFHD画面で最大化していると、次回仮想マシン起動時に起こると判明。
対処法は、仮想マシンのshutdown時に、ホスト側で、仮想マシンのウィンドウを縮小すること。
縮小して仮想マシンをshutdownすることで、次回起動時は縮小されたウィンドウの状態で仮想マシンが立ち上がる。
そうすると、仮想マシンがいい感じの解像度で立ち上がってくれるので、アカウントにログインした後でホスト側でFHDに最大化する。
何ともアナログな方法だが、今のところこうするしかなさそう…。
リモートアシスタンス【teredoで「サーバー名を解決できませんでした」のエラー】
これまでリモートアシスタンスを使って遠隔地と毎日1回はデスクトップの共有を行っていたのですが、2015年の5月初週ぐらいから急に接続ができなくなりました。
原因は、dnsが名前解決してくれないことのよう。
環境はアシスタンスを受ける側とする側ともにwindows 7
リモートアシスタンスはNAT越えにipv6トンネリング技術の1つteredoを利用する。
ネットワークの設定を見ても、ipv6も有効にしているし、インターネットにも接続できている。
アシスタンスを受ける側のPCのコマンドプロンプト(管理者として実行)で
>netsh interface ipv6 show teredo
とやると
エラー:サーバー名を解決できませんでした
と表示される。
以前までは普通にteredo動いていたんだけど、どういう原因かわからないが、windows7デフォルトで指定のあるteredoサーバ(teredo.ipv6.microsoft.com.)の名前解決が死んでいる模様。
pingを打ってみるも
>ping teredo.ipv6.microsoft.com ping要求ではホスト teredo.ipv6.microsoft.com が見つかりませんでした。ホスト名を確認してもう一度実行してください。
DNSサーバを変えてみるもダメ...
ネットワークアダプタの再起動、PCの再起動、teredoの再起動といろいろやってみましたが状況が変わりませんでした。
社内のwindows7のPCにおいてはまさに全PCそんな状況でした。
途方に暮れかけそうになったのですが、幸い1台だけwindows8.1でテストしていて、そこで
>netsh interface ipv6 show teredo
とやるとこっちは正常にteredoが動いていて、なんでかなと眺めてみるとteredoサーバがwindows7のものと違っていました。
windows8.1のteredoサーバは「win8.ipv6.microsoft.com」。
win8からデフォルトで違うサーバを見ているようです。
もしかしてこのサーバ使えばいけんじゃないかと思って、ためしにwindows7側のteredoサーバを
>netsh interface ipv6 set teredo type=client win8.ipv6.microsoft.com
として変更し、OKが表示されたら再度
>netsh interface ipv6 show teredo
をやるとアシスタンスを受ける側のteredoが復活しました。
アシスタンスを行う側も同様にteredoサーバをwin8...のものを利用し、ようやくリモートアシスタンスが復活しました。
このままwin8サーバを使い続けていいのかどうかはよくわかりませんが、当面これでしのげればいいです。
vba【powerpointのテキストボックスの日本語フォントの変更方法】
PowerPoint VBAでフォントの名前を変更しようとした際、ハマったのでメモ。
環境は以下。
Meiryo UIをテキストボックスのフォントにしようとして、
Slide(1).Shape("textbox").TextFrame.TextRange.Font.Name = "Meiryo UI"
としたんだけど、英数字のみMeiryo UIになって、日本語の文字列にフォント名が反映されなかった。
これは、
Excel 2007 のテキスト ボックスで使用するフォントの種類をマクロで変更できない
に記載があるように、
Slide(1).Shape("textbox").TextFrame.TextRange.Font.Name = "Meiryo UI" Slide(1).Shape("textbox").TextFrame.TextRange.Font.NameFarEast = "Meiryo UI"
と2行にわたって指定しないといけないらしい。