It's raining cats and dogs.

無駄なことなんてないはず

grep結果に色を付けるとなんだか捗る

grepで検索した時にヒットした文字列の色を替えるやり方をmonmonさんに教わったのでメモ。

--color=autoというオプションをつけると良いらしい

$ grep --color=auto 'hogehoge' access.log

のようにするとgrepの検索結果画面のhogehogeという文字に色がついて見やすい。

  • 使用前

f:id:tadasy:20140106234710p:plain

  • 使用後

f:id:tadasy:20140106234703p:plain

ちなみに

GREP_OPTIONSという環境変数を設定しておくと、常に設定したいgrepのオプションを設定しておけるので、

export GREP_OPTIONS='--color=auto'

みたいなやつを.zshrcとか.bashrcに書いておけば、もろもろ捗る。

ホームディレクトリ($HOME)以外の場所にplenvの環境を作ってperlをインストールする

plenvはデフォルトではホームディレクトリ($HOME)にインストールする前提になっているようだ。

で、今回はわけあってホームディレクトリ以外にplenv(perl)の環境を作りたかったので、その時のメモ。

基本的な流れはREADMEの通り。

/path/toディレクトリにインストールすることにする

まずはplenvのclone

$ git clone git://github.com/tokuhirom/plenv.git /path/to/.plenv

pathを設定する。readmeでは~/.bash_profileに書き込んでいるけど一旦設定だけする。特に理由はない。

$ export PATH="/path/to/.plenv/bin:$PATH"

plenvを初期化するが、ここでもひとまず~/.bash_profileには書かない。

$ eval "$(plenv init -)"

perl-buildを入れる

$ git clone git://github.com/tokuhirom/Perl-Build.git /path/to/.plenv/plugins/perl-build/

ここで試しにインストールできるperlのバージョンを確認してみる

$ plenv install -l

すると

plenv: Please install perl-build. See https://github.com/tokuhirom/plenv/blob/master/README.md#installation

perl-buildが入ってないから入れてねと怒られる。

なのでPLENV_ROOTという環境変数を使って、明示的にplenvの場所を設定してあげる

$ export PLENV_ROOT=/path/to/.plenv

もう一度plenv install -lをしてみる

$ plenv install -l
Available versions:
 5.6.0
 5.6.1-TRIAL1
 5.6.1-TRIAL2
 5.6.1-TRIAL3
...

うまくいった。

僕がうまくググれなかっただけかもしれないけど、plenvのコードを読んでみたらそれっぽいことが書いてあったので、試してみたら出来たという話。 https://github.com/tokuhirom/plenv/blob/master/libexec/plenv#L39

携帯(ガラケー)サイトで、PHP5.2以下から5.3以上へのバージョンアップ時にmb_output_handlerを使った文字コード変換でハマった時のメモ

前回のエントリでも触れたけど、とある携帯(ガラケー)サイトをPHP5.2から5.4にバージョンアップ対応していた時にまたハマった。※文字多めのエントリ

ガラケーといえば、3キャリア対応するためにShift_JISでページを作るのは鉄板。やり方はいろいろあるけど、このサイトはmb_output_handler文字コード変換していた。mb_output_handlerはざっくり言うと、ob_startでバッファリングした出力をmbstring.internal_encodingで指定した文字コードから、mbstring.http_outputで指定した文字コードによろしく変換してくれるというすぐれものだ。

ただ、このmb_output_handlerには罠があって、

http://php.net/manual/ja/function.mb-output-handler.php

にも書かれている通り、

デフォルトの MIME 型が text/ で始まる

という条件で発動するらしい。

で、今回何にハマったのかというと、

このサイトではapache側でphp_valueを使って、mbstring.internal_encodingEUC-JP、mbstring.http_outputShift_JISで設定されていた。でもってhtmlのテンプレートは基本EUC-JPで書かれていて、それをtext/htmlで出力していたので、mb_output_handlerが効いていたために、特に問題なくShift_JISに変換されて表示されていたのだけど、何故か一部のページが文字化けしてしまっていた。PHP5.2の環境だと問題なく表示されるのに。

よくよく調べてみると、文字化けしていたページはなぜかはわからないけどapplication/xhtml+xmlが使われていてShift_JISで書かれていた。(たぶん何かの装飾をしたかったのだろう) ただ、mb_output_handlerの仕様上、mimeタイプがtext/でなければ、文字コード変換は行われず、普通にShift_JISとして表示されるはずだし、実際PHP5.2の環境では問題なく表示できていた。

ではなぜ文字化けが起きたのか。

PHP5.3からはmbstring.http_output_conv_mimetypesという設定が追加されている。

http://php.net/manual/ja/migration53.ini.php

ここでも書かれている通り、

このディレクティブは mb_output_handler() 関数が呼び出された場合に使う Content-Type の正規表現パターンを指定します。

要はmbstring.http_output_conv_mimetypesmb_output_handlerで変換対象にしたいContent-Typeの正規表現を書くことで、text/以外でも変換できるとのこと。

で、mbstring.http_output_conv_mimetypesのデフォルト値が^(text/|application/xhtml\+xml)だったために、今まで変換されないはずであったapplication/xhtml+xmlで出力していたShift_JISのページがmb_output_handlerで変換されてしまい文字化けてしまっていたのだった。(Shift_JISのページをEUC-JPとして解釈してShift_JISに変換していた)

対応としては、application/xhtml+xmlのページをEUC-JPにするなどを考えたけど、影響範囲を調査するのが手間だったので、auto_prepend_fileで起動されるbootstrap的なphpmbstring.http_output_conv_mimetypes正規表現text/でのみ文字コード変換されるように変更することにした。

<?php
ini_set('mbstring.http_output_conv_mimetypes', 'text/*');

相変わらず設定値にはハマりますね。

ちなみに

http://php.net/manual/ja/migration53.ini.php

ではmbstring.http_output_conv_mimetypeと書かれているけど、実際にはmbstring.http_output_conv_mimetypesのようにsを付けないと動かない。(もしかしたら5.3では動いたのかもしれない)

PHP5.2以下から5.3以上へのバージョンアップ時にcookie以外の手段でセッションIDを保持する場合のメモ

とある携帯(ガラケー)サイトのPHPを5.2から5.4にアップデートしようとしてハマった。

携帯サイトではcookieを使えない場合もあるので、(セキュリティ的に良いか悪いかは別にして)URLにセッションIDを付ける場合はわりと多いのではないだろうか?

で、試しに5.4で動かしてみたらセッションがうまく引き継がれず、ログイン状態を維持できない場面に遭遇した。PHPのバージョンアップでセッション周りの動きが変わったのかと思い、殆ど触ったことのないプログラムをデバッグしまくって、原因箇所を特定しようと躍起になってみたものの全くわからない。コードを追うのを諦めてphpマニュアルを見ているとそれらしきものを発見。(というかビンゴ)

http://www.php.net/manual/ja/session.configuration.php#ini.session.use-only-cookies

どうやらPHP5.3からsession.user_only_cookiesのデフォルト値がオンになったみたい。すなわちcookie以外でのセッションIDの保持がデフォルトではできなくなってしまったようだ。このせいでURLにくっつけたセッションIDは使われなくなり、アプリケーション側はログオフ状態になってしまっていたようだ。

対策としては php.ini

session.use_only_cookies = 0

とするか .htaccess

php_value session.use_only_cookies Off

とするか php

<?php
ini_set('session.use_only_cookies', 0);

とすれば良い。

PHPのバージョンアップは、言語の動きというよりも、設定のデフォルト値が変わってしまうことでハマることが多い気がする。

[ssh] ssh経由で他のサーバのスクリプトを実行するときに.bash_profileを読ませる方法

書きなぐりメモ。

ssh経由で何かのスクリプトを実行したい時は

$ ssh <hostname> "/usr/bin/perl /path/to/hoge.pl"

という感じで実行できるけど、~/.bash_profileとかに書かれた環境変数を使って処理をするスクリプトだと、sshの非対話モードでは~/.bash_profileを読んでくれないので、困ってしまう。

そんなときは

$ ssh <hostname> "source ~/.bash_profile; /usr/bin/perl /path/to/hoge.pl"

のように明示的に読ませれば良いらしい。

ちなみに

sshdの設定でPermitUserEnvironment=yesを設定して、~/.ssh/environmentというファイルに環境変数を設定するやり方もあるようだけど、必ずしもssh経由で実行するものではなく、対象のサーバで直接実行したい場合もあるので、~/.bash_profile~/.ssh/environmentの両方に設定するのが冗長なので今回は上記のやり方にした。

composerでSmarty2をインストールする

composerでsmartyを入れる時は

{
    "require": {
        "smarty/smarty": "*"
    }
}

とやるとインストールできるのだけど、これだとSmarty3が入ってしまう。でも今の環境ではSmarty2が使われているので2を入れたい(バージョンアップしたらいいがなという話は置いといて)。いろいろ調べてみたけどどうやらSmarty2はcomposerに対応していないようなので、packageを使って個別に入れることにする。

{
    "repositories":[
    {
        "type": "package",
        "package": {
            "name": "smarty/smarty2",
            "version": "2.6.28",
            "dist": {
                "url": "http://www.smarty.net/files/Smarty-2.6.28.tar.gz",
                "type": "tar"
            },
            "include-path": [
                "libs/"
            ]
        }
    }
    ],
    "require": {
        "smarty/smarty2": "*"
    }
}

nameは適当。あとは

$ php composer.phar install

でインストールし、

<?php
require 'vendor/autoload.php';
require 'Smarty.class.php';

$smarty = new Smarty();

という感じで使える。 composer.jsonの中でinclude-pathという項目を設定している。これが何かというと、composerではvendor/autoload.phpをrequireするとcomposerで使うためのinclude_pathを設定してくれる。これはvendor/composer/include_paths.phpの内容が設定されるようだ。composerに対応しているライブラリであれば、このinclude_paths.phpをよろしく編集してくれるので、特にこまらないのだけど、今回のSmarty2のようにpackageを使って入れたりするとinclude_pathを設定してくれないので、そのための設定。ちなみに上記のようにinclude-pathを設定すると

<?php

// include_paths.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    $vendorDir . '/smarty/smarty2/libs',
);

という感じでinclude_paths.phpを更新してくれる。
Smarty.class.phpvendor/smarty/smarty2/libs/Smarty.class.phpにいるので、"include-path": ["libs/"]を書いておくとvendor/smarty/smarty2/libs/までinclude_pathが通るので、

<?php
require 'Smarty.class.php';

で使えるわけだ。

ちなみに、require自体したくない場合は

{
    "repositories":[
    {
        "type": "package",
        "package": {
            "name": "smarty/smarty2",
            "version": "2.6.28",
            "dist": {
                "url": "http://www.smarty.net/files/Smarty-2.6.28.tar.gz",
                "type": "tar"
            },
            "autoload": {
                "files": ["libs/Smarty.class.php"]
            },
            "include-path": [
                "libs/"
            ]
        }
    }
    ],
    "require": {
        "smarty/smarty2": "*"
    }
}

という感じでautoload要素を追加しておけば良い。

composerでライブラリのインストールディレクトリを変える

composerphpのライブラリ管理ツールだ。改めて説明する必要はないくらいだけど、rubyのbundlerとかperlのcartonみたいなもんだ。

composerのざっくりとしたディレクトリ構成は

current_dir
 ├ composer.phar
 ├ composer.json
 ├ composer.lock
 └ vendor
    ├ autoload.php
    ├ composer
    ├ ・・・
    ├ <ライブラリA>
    └ <ライブラリB>

こんな感じになっていて

[current_dir]$ php composer.phar install<or update>

などでライブラリをインストールするとvenderディレクトリにインストールされる。

で、このvendorディレクトリを別の名前にしたかったので、いろいろ調べてみたがそれらしい情報に出会えなかったので、composerのソースをみて試してみた。

結論としてcomposer.jsonに以下の設定をしたらインストール先のディレクトリ名を変えれた。

{
    "config": {
      "vendor-dir": "my_library"
    },
...
}

このようにconfigにvendor-dirに任意のディレクトリ名を設定できるようだ。

他にも

https://github.com/composer/composer/blob/master/src/Composer/Config.php

この辺りのソースを見るとなにやらいろいろ設定できそう。

追記

よくよくcomposerのドキュメントをみるときちんと書いてあって残念な気分になりました。。。ドキュメントはきちんと読みましょう。

http://getcomposer.org/doc/04-schema.md#config