まったく更新出来ていなかったので、最近の近況など。

仕事

仕事でポジションが変わってずいぶん忙しくなりました。。
今までは、開発部のリーダーだったので、開発部内のことをメインに考えればよかったのだが、もちっと会社全体のことを考えるようになり、物を作る以外の調整や考えなければならないことが増えてきている。

その他

HT-03Aは、落としてしまった後、FOMAカードだけ再発行して旧端末に指していたのだが、3月にNexusOneを買った。
昨日、Android2.2のアップデートをしてみたが、想像以上にいいし問題無さそう。

ポータブルWi-Fiアクセスの機能を使うとお手軽にPC等からアクセスできるのがいい。欲を言うともちっと接続スピードが出るといいんだけどね。


アプリも最近作るようになってきた。
iPhoneもアプリも会社で作るようになってきたので、会社iPhoneを触ってみると、Androidのインターフェイスよりもよくできているなーと思ったりした。
アプリ関連はもう少し情報たまったら書いていければと思う。


BPStudyという勉強会で刺激されたこともあり、Google Chromeの拡張を少し書いてみたりとかしている。

保存時にリアルタイムテスト実行でお手軽テスト

普段、Ethnaを使用して開発しているのだが、EthnaはWeb画面でテスト結果表示なので、どうしても一手間増えてしまう。
実際にテストケースを書いてブラウザで確認するのであれば、テストケースを書かずに、書いた実コードをブラウザで動作確認していた時と変わらず、Alt+Tab、Ctrl+R とかするのであれば、実コードを実行するいままでのやり方で済ませてしまい、なかなかテストケースを書くというやり方が浸透しない。
もしくは、最初はするけど、忙しくなるとしなくなるという状況でした。


テストケースを書くことで得られる安心感や、結果としてクオリティの担保になるというのは、理解してもらえるとは思うのだが、Alt+Tab、Ctrl+R という、今までと同じ手順ではない、テストを書く方が楽。という方法が確立できればいいのではないか。なんて考えていた。


つい先日、Ethnaの今後のロードマップを考える というか 話し合う飲み会があったのだが、そこでテストの話が少し出た。
id:sotarok から、ファイルの保存時に自動でテストを実行なんて話を聞いて、いつぞやのPHP勉強会で、kunitさんのTDDの話を思い出した。


ちょうど、今回途中参加した案件では、Ethnaではなく独自フレームワークっぽいもので作成だったので、TDDをすべく環境を整えてみた。

テストライブラリに何を使うか

ばっちりテストを書くというよりは、手軽に書きたいので、limeというテストライブラリを使おうとした。

limeでなるべく気軽にユニットテストを書く - id:anatooのブログ
[PHP] limeでTDDを体験する - DQNEO起業日記

このあたりが参考になるだろうか。
SimpleTestのようにクラスを作らずに手軽に出来るのが利点だ。


ところがどっこい、今回の案件は PHP4 でした。。。
limeは当然PHP5用なので、少し書き換えてPHp4用にしようかと思ったが、テストライブラリ自体が信用できない自分が書いたコードというのは意味がない。。。


他に使えそうなのが、PHPUnit、SimpeTest、phptなどなど。
phptは、ちょっと手間がかかるので無理かも。とういことで、Ethnaで使い慣れた SimpeTest を使うことにしました。

お手軽テスト

お手軽にテストするために、テスト用にわざわざ何かを実行するのは手間なので、実行ファイルの最後にテストを書くようにした。
limeでなるべく気軽にユニットテストを書く - id:anatooのブログ
このあたりを参考にしてみる。

<?php
define('BASE', realpath(dirname(__FILE__).'/../'));
class ActionForm1
{
    //ここに実際のコード
}

// test
if (debug_backtrace()) return;
include_once BASE.'/lib/test_autorun.php';
include_once FR_BASE.'/lib/test_autorun.php';

class Test_ActionForm1 extends UnitTestCase
{
    var $ac;
    function setUp()
    {
        $this->ac = new ActionForm1();
    }

    function testPrepare()
    {
        //ここにテストコード
        $this->assertEqual($this->ac->hoge, 'hoge');
    }

}


こんな感じだ。
すこし長くなるが、vimで実行すると、保存後に :!php % とするとテストが実行できる。

test_autorun.php

テストの実行ファイル

<?php
require_once dirname(__FILE__) . '/simpletest/unit_tester.php';
require_once dirname(__FILE__) . '/simpletest/mock_objects.php';
require_once dirname(__FILE__) . '/simpletest/collector.php';
require_once dirname(__FILE__) . '/simpletest/default_reporter.php';

register_shutdown_function('test_autorun');

/**
 *    Exit handler to run all recent test cases if no test has
 *    so far been run. Uses the DefaultReporter which can have
 *    it's output controlled with SimpleTest::prefer().
 */
function test_autorun() {
    $candidates = array();
    foreach (get_declared_classes() as $class) {
        if (substr(strtolower($class),0,5) == 'test_') {
            $candidates[] = $class;
        }
    }
    $loader = new SimpleFileLoader();
    $suite = $loader->createSuiteFromClasses(
            reset($candidates),
            $loader->selectRunnableTests($candidates));
    $result = $suite->run(new DefaultReporter());
    if (SimpleReporter::inCli()) {
        exit($result ? 0 : 1);
    }
}

実行結果は

:!php form1.php
test_actionform1
OK
Test cases run: 1/1, Passes: 0, Failures: 0, Exceptions: 0

続けるにはENTERを押すかコマンドを入力してください

さらに一歩進んで

これだと、保存後にコマンドを実行する必要がある。
もう一歩進んで、保存時に自動的にテストが実行されるようにしてみる。

kansit という、rubyのスクリプトがあることを id:sotarok から教えてもらったのだが、開発しているサーバには rubyが入っておらず、rubyの環境を整えるよりは、作った方が早いので以下のようなものを作ってみた。

<?php
$dirs = array();
foreach ($argv as $arg) {
    $dir = realpath($arg);
    if ($dir && is_dir($dir)) {
        $dirs[] = $dir;
    }
}

$files = array();

while (1) {
    usleep(500);
    $target = array();
    foreach ($dirs as $dir) {
        foreach (glob($dir.'/*.php') as $file) {
            if (isset($files[$file]) && $files[$file] != filemtime($file)) {
                $target[] = $file;
            }
            $files[$file] = filemtime($file);
        }
    }
    if (count($target)) {
        exec('reset');
        foreach($target as $file) {
            echo ">>run test {$file}\n";
            //passthru('php -l '.$file);
            passthru('php '.$file);
            echo "\n";
        }
    }
}

コマンドラインで実行し、引数に監視対象のディレクトリを指定するというスクリプトです。
無限ループで監視を続けるので、停止をするときには、Ctrl+C で止めてください。

開発する環境

screen を縦分割します。
上の画面を 10行ほどにして、そこで、上記の監視スクリプトを実行しておきます。

で、下の画面で普通にコードを書いて、保存をした瞬間に上の画面で結果が表示されます。

Erase is backspace.
>>run test /path/to/form1.php
test_actionform1
OK
Test cases run: 1/1, Passes: 0, Failures: 0, Exceptions: 0

こんな感じ。


保存時に毎回見るわけではなく、気にせずがつがつ書いていけばいい。
PHPの構文エラーもすぐに気づくし、通ると思った瞬間に確認すればいい感じです。

それに、画面上部は常に視界の片隅に入るので、結果がNGの場合に長い行が出るので、気にしていなくても目に入ってくる。



ちょっとしたことだが、コードを書く作業の妨げにならずに何度もテストが実行され、コードが正しく動くというのに自信が持てるので、作成中多少手戻りが発生しても、影響範囲とかを考えたり悩んだりしなくて済むのが楽だ。

RedmineでCVSとSVNのコミットコメントの文字コードが違う場合の対処

現在うちで使っているメインのバージョン管理ツールは SVN(Subversion) だが、過去の案件で CVS を使っているものがある。
開発が活発に続いているものは、タイミングをみて SVN へ移行してきたのだが、ひそやかに保守が続いていて、そこまでコストをかけられないものは CVS のままという状況だ。


SVN から GIT などの分散リポジトリも使ってみようということになり、今までは、SVN+Trac だったのを、Redmine に移すことにした。
RedmineCakePHP へ移植している candycane も考えてみたのだが、ちょっとまだ実務に投入するのは怖いかなぁと。。)
せっかく Redmine にするのであれば、CVSの案件もまとめて管理をしようということになり、追加をしようとしたが、CVSのバージョンが古くてリポジトリの追加ができなかった。


Redmine では、CVSリポジトリを参照するのに rls というコマンドを使用しているのだが、これが、yum などで入れたバージョンでは使えないのでした。
そこで、ローカルのサーバで CVS の環境を構築して、実際にアップデートしてみてテストを行った。

アップデートのログ

# cd /usr/local/src
# wget http://ftp.gnu.org/non-gnu/cvs/binary/feature/x86-linux/RPMS/i386/cvs-1.12.12-ximbiot.1.i386.rpm
# rpm -qa | grep cvs
cvs-1.11.2-10
# rpm -Uvh cvs-1.12.12-ximbiot.1.i386.rpm
Preparing...                ########################################### [100%]
   1:cvs                    ########################################### [100%]
# rpm -qa | grep cvs
cvs-1.12.12-ximbiot.1


これで無事に Redmine から CVSリポジトリが参照できました。

コミットコメントの文字化け対処

CVS 登録直後は、リポジトリは参照出来るのだが、以下のコマンドを動かしてコミットログを取得すると動かなくなる

ruby /phat/to/script/runner "Repository.fetch_changesets" -e production

CVSredmine に登録すると、コミットログが文字化けしてしまい、文字化け状態だとリポジトリが開けないという状況になってしまいました。
http://redmine.jp/faq/repository/shift_jisutf-8/
このあたりの対応とか、リポジトリ消して作り直しとかしてるんですけどねぇ。。。


いろいろ確認したところ、
管理>設定>リポジトリ
コミットメッセージのエンコーディング = Shift_JIS
にすれば、CVSは文字化けせずに表示できるが、SVNが文字化けをする


めんどくさいので、CVSの時だけ nkf を通して文字コードutf-8になるようにパッチ当てちゃいました。

/path/to/redmine/lib/redmine/scm/adapters/cvs_adapter.rb のファイルです。

--- cvs_adapter.rb.bk   2010-02-26 19:23:10.000000000 +0900
+++ cvs_adapter.rb      2010-02-26 19:24:03.000000000 +0900
@@ -66,6 +66,7 @@
           cmd = "#{CVS_BIN} -d #{root_url} rls -e"
           cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
           cmd << " #{shell_quote path_with_project}"
+          cmd << " | nkf -Sw"
           shellout(cmd) do |io|
             io.each_line(){|line|
               fields=line.chop.split('/',-1)
@@ -111,6 +112,7 @@
           cmd = "#{CVS_BIN} -d #{root_url} rlog"
           cmd << " -d\">#{time_to_cvstime(identifier_from)}\"" if identifier_from
           cmd << " #{shell_quote path_with_project}"
+          cmd << " | nkf -Sw"
           shellout(cmd) do |io|
             state="entry_start"

@@ -230,6 +232,7 @@
           logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
           path_with_project="#{url}#{with_leading_slash(path)}"
           cmd = "#{CVS_BIN} -d #{root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
+          cmd << " | nkf -Sw"
           diff = []
           shellout(cmd) do |io|
             io.each_line do |line|
@@ -247,6 +250,7 @@
           cmd = "#{CVS_BIN} -d #{root_url} co"
           cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
           cmd << " -p #{shell_quote path_with_project}"
+          cmd << " | nkf -Sw"
           cat = nil
           shellout(cmd) do |io|
             cat = io.read
@@ -260,6 +264,7 @@
           logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
           path_with_project="#{url}#{with_leading_slash(path)}"
           cmd = "#{CVS_BIN} -d #{root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
+          cmd << " | nkf -Sw"
           blame = Annotate.new
           shellout(cmd) do |io|
             io.each_line do |line|


これで、すでに文字化けているリポジトリは削除して再設定し、script/runner を再実行でコミットコメントも文字化けせずに取得できました。

rhaco2いろいろ

最近、変態的だと噂の rhaco2 を触ってます。

http://rhaco.org/

Lingrでいろいろ質問しまくってます。
Lingr: Sign Up


とりあえず、rhaco2のドキュメント
http://wikihub.org/wiki/rhaco2-doc

とりあえず setup.php

なんかするときは、php setup.php をしてみる

ライブラリインストール

php setup.php -import org.rhaco.storage.db.Dao

自分でライブラリサーバを作れる

setup.php -write_re をして、__repository__.php とかが出来たらOK。
apps libs とかってディレクトリがいるっぽい

環境ごとの差異は

__settings__.php に記述する。
これはバージョン管理対象外にする。

setup.php にコマンド追加

static public __setup_*****__ なメソッドを作れば -**** で使えるようになる

参考
http://code.google.com/p/rhaco/source/browse/repository/trunk/libs/org/rhaco/storage/db/Dbc.php

よくできてる!

引数の取り方

setup.php -hoge abc -hage son

これは
$valueにはabc $req->in_vars("hage")
で、取れる

などなど

後でまとめて rhaco2-docにフィードバックしようと思います。


あと、かなりblogを放置してしまっていましたが、またマイペースに書いていこうと思います。

第43回PHP勉強会@関東に参加してきた

久々にPHP勉強会に参加してきました。


会場はノッキングオンさん。昨年の2月にあったノッキングオンさんの会場で行ったPHP勉強会が初参加なので、ある意味思い出深い感じでした。
出来れば発表したかったけど、時間がありませんでした。。

Text_Pictogram_MobileとHTML_CSS_Mobileを使う

発表者:gusagiさん

yudoufuさんが作られているライブラリを実際に使用してみたものをソースを交えて紹介でした。

モバイルに興味がある、上記ライブラリを使ったことが余り無い人)

実際のソースを交えて、紹介をされていました。
発表資料

サーバ運用関係の話

発表者:ichikawaさん(id:cakephper)
PHPで作ったアプリを乗せるサーバを支える技術

サーバ管理者の恐怖

  • リブート恐怖症
  • Firewallルール変更恐怖症
  • 障害メール恐怖症

たしかにありますね。そーいうの。。。

そこで! YHA (Yaya High Availability)
名前にうけましたw


iScsiを使って物理サーバ間で、HDDをたすき掛けにマウントして使うという話。

発表資料
PHP勉強会 #43でサーバ運用関係の発表をしてきました - cakephperの日記(CakePHP, MongoDB)

phptek2009の話

発表者:id:yandodさん
php|tek2009という海外のイベントの紹介

海外にはいろいろなイベントがあるとは思っていましたが、遠いところでやる別のこと的な感覚を持ってしまっていました。
自分でも普通に使っている slideshare で、海外の講演の資料が見れるというのが感覚としてありませんでしたが、面白そうです。
ちょっと紹介していたスライドにも興味深いのがあったので、いろいろ見てみようと思いました。


yandodさんは、今回、Ustの配信も同時に行ってくださってました。

懇親会

発表が全て終わってから、会議室でそのまま懇親会を行いました。
真ん中に会議室のテーブルがあったからなのか、初めての人が多かったからなのか、少し静かな感じになってしまっていて、自己紹介と同じように、また、独りずつ話すという感じになり、面白かったです。
興味深いこともいろいろありました。

最後に

会場を提供してくださった 株式会社ノッキングオンさん、司会進行、懇親会の手配等をしてくださった、gusagiさん、ありがとうございました!

N-06AのUserAgentが変わった

発売早々に販売停止というトラブルのあったN-06Aだが、UserAgentが変わったようだ。


発売日に送ってきていたUserAgent

DoCoMo/2.0 N06A(c500;TB;W24H16)


今日、アクセスを見ていたら以下のようになっていた。

DoCoMo/2.0 N06A2(c500;TB;W24H16)


以下を確認しても、N06A2という記述が見あたらない。

DoCoMo/2.0 N06A(c500;TB;W24H16) (ブラウザからの通信時、ADF取得時(縦画面))
DoCoMo/2.0 N06A(c500;TB;W24H12) (ブラウザからの通信時(横画面))
DoCoMo/2.0 N06A(c500;TB;W20H13) (ブラウザからの通信時、ADF取得時(縦画面))注意1
DoCoMo/2.0 N06A(c500;TB;W20H10) (ブラウザからの通信時(横画面))注意1
DoCoMo/2.0 N06A(c500;TB;W30H20) (ブラウザからの通信時、ADF取得時(縦画面))注意1
DoCoMo/2.0 N06A(c500;TB;W30H15) (ブラウザからの通信時(横画面))注意1
DoCoMo/2.0 N06A(c500;TB;W16H10) (ブラウザからの通信時、ADF取得時(縦画面))注意1
DoCoMo/2.0 N06A(c500;TB;W16H8) (ブラウザからの通信時(横画面))注意1
DoCoMo/2.0 N06A(c500;SD) (JAR取得時(Starプロファイル))
DoCoMo/2.0 N06A(c500;TD) (JAR取得時(DoJaプロファイル))
DoCoMo/2.0 N06A(c500;SJ) (iアプリからの通信時(Starプロファイル))
DoCoMo/2.0 N06A(c500;TJ) (iアプリからの通信時(DoJaプロファイル))

http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/#p13

UserAgentの形式を見ても機種名となっている。

DoCoMo/2.0機種名(キャッシュ;状態コード;ブラウザ表示可能byte数;個体識別情報)

http://www.nttdocomo.co.jp/service/imode/make/content/browser/browser2/useragent/index.html


表記上の機種名が変わったとも思えないが、内部的な名前が変わったのだろうか。
N-06Aの不具合に対するソフトウェアアップデートがあるとのことだが、明示的にやった記憶はないので、何がかわっているのかわからないが、なにか変わったようだ。


UserAgentを見て、機種判別しているところでは、N06A2 も追加する必要がありそうだ。

追記(2009-05-26)

なんか、前回のソフトウェアアップデートしたが、別の原因による同様の不具合があったとのことで、再度ソフトウェアアップデートが出た。
更新したところ、また UserAgentが変わりました

DoCoMo/2.0 N06A3(c500;TB;W24H16)

追記(2009-05-27)

DoCoMoのサイトでも公式に新UserAgentが出てました。
http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/index.html#p13

DoCoMo iモードブラウザ2.0でCookie

DoCoMoのこの夏モデルから、iモードブラウザ2.0というより高機能なiモードブラウザが搭載されるようになりました。

CookieCSS,JSなど、大きな違いがありますので、実際に実機で確認をしてみます。
端末は、N-06A を使用します。なんか、発売停止なんてなってますが。。


Cookie

まずは、Cookieについて。
以前、以下のような調査をしたことがあったので、同じ調査をしてみました。
auのSSLでのCookieの挙動がおかしい - maru.cc@はてな
au,SoftBankでSSLでCookieセッションを使用する場合の問題点 - maru.cc@はてな


結果は、問題なく使えます。http<->httpsでの動作、secure属性の挙動も問題ありません。
これを使えば、Cookieセッションでセキュアなサイトがちゃんと作れそうです。

setcookie()の httponly の挙動が動いていない?

phpのsetcookie関数には、httponly という引数があります。

httponly
TRUE を設定すると、HTTP を通してのみクッキーにアクセスできるようになります。 つまり、JavaScript のようなスクリプト言語からはアクセスできなくなるということです。 この設定を使用すると、XSS 攻撃によって ID を盗まれる危険性を減らせます (が、すべてのブラウザがこの設定をサポートしているというわけではありません)。 PHP 5.2.0 で追加されました。 TRUE あるいは FALSE で指定します。
http://jp2.php.net/manual/ja/function.setcookie.php

以下のようなテストコードでテストしてみたところ、httponlyの指定が正常に動いていないように思います。
単にサポートしてないというだけなのかもしれません。

http側ファイル

<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
</head>
<body>
<pre>
<?php
print_r($_COOKIE);

$value = "test:".date('H:i:s').' '.$_SERVER['SERVER_PORT'];
$timeout = time() + 20;
setcookie("test",$value,$timeout);
setcookie("test".$_SERVER['SERVER_PORT'],$value,$timeout,'/','example.com',false,true);
?>
</pre>
<hr>
<script  type="text/javascript">
document.write(document.cookie);
</script>
<hr>
<a href="http://example.com/cookie.php?nocache=<?php echo md5(microtime())
?>">http</a><br>
<a href="https://example.com/cookie.php?nocache=<?php echo md5(microtime())
?>">https</a><br>
</body>
</html>
<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
</head>
<body>
<pre>
<?php
print_r($_COOKIE);

$value = "test:".date('H:i:s').' '.$_SERVER['SERVER_PORT'];
$timeout = time() + 20;
setcookie("test",$value,$timeout);
setcookie("test".$_SERVER['SERVER_PORT'],$value,$timeout,'/','example.com',true);
?>
</pre>
<hr>
<script  type="text/javascript">
document.write(document.cookie);
</script>
<hr>
<a href="http://example.com/cookie.php?nocache=<?php echo md5(microtime())
?>">http</a><br>
<a href="https://example.com/cookie.php?nocache=<?php echo md5(microtime())
?>">https</a><br>
</body>
</html>

結果は次のようになりました。
http

https

ちなみに IE7の場合は以下のようになります。
http

https

複数ウィンドウ

iモードブラウザ2.0では、aタグに targetを指定できます。
タブ間でCookieが共有されるかは、当然共有されるようです。

ブラウザを閉じてからの Cookieの保持

上記のテスト中に、iモードブラウザを閉じてからアクセスをしたところ、問題なく前回の Cookieを取得できました。


Kimuraさんのblogに書かれていて気になったので以下も調べてみました。
expireに 0を指定したところ、iモードブラウザを終了後、再度立ち上げたときに、Cookieを取得できませんでしたので、ブラウザを閉じるまでという挙動は正しく動いているようです。

逆に複数タブを(ウィンドウ)を開いた状態では、どれか一つを閉じただけでは、Cookieは保持されていますね。これは当然の挙動かな。

とりあえず

DoCoMoの新しい端末onlyであれば、ちゃんと CookieセッションでOKそうです。
あとは、旧世代との差をどう埋めるかですね。。


JS周りも調べてみようと思います。

追記(2009-05-28)

どうやらソフトウェアアップデートでJavaScriptが動かなくなってしまったようで、上記の画面キャプチャのような結果にならなくなってしまいました。
JavaScriptの部分が動きません。