プログラム

EthnaでCLI(コマンドラインインターフェース)用のプログラムを書く

Ethnaではゲートウェイを変更することでwebアプリ用のプログラムだけではなくて、サーバーで定期稼働させたりするコマンドラインのプログラムを作ることもできる。
ethnaコマンドを使ってスケルトン作成。feedcrawle2というプログラムの名前で作ってみる。

% ethna add-entry-point --gateway=cli feedcrawle2

file generated [/Users/〜/pj/feeddown/skel/skel.entry_cli.php -> /Users/〜/pj/feeddown/bin/feedcrawle2.php]
action script(s) successfully created [/Users/〜/pj/feeddown/bin/feedcrawle2.php]
file generated [/Users/〜/pj/feeddown/skel/skel.action_cli.php -> /Users/〜/pj/feeddown/app/action_cli/Feedcrawle2.php]
action script(s) successfully created [/Users/〜/pj/feeddown/app/action_cli/Feedcrawle2.php]

これを実行すると、Ethnaのプロジェクトディレクトリに上の実行結果の通りファイルが作成される。

  • ~/bin/feedcrawle2.php
  • ~/app/action_cli/feedcrawle2.php

あとは、webアプリをEthnaで書くときと同じ様にapp/action_cli/以下のModelをコーディングしていけばよい。
プログラムの実行は、

とすればよい。
ActionClassを継承しているので、$this->backend等々、普通に使える。
ただし、コマンドラインの引数を取得する仕組みは無い*1ので、グローバル変数 $_SERVER['argv']から取得する形になりそう。(これが正しいのかは現状、謎。)

今までこの仕組み使わずにそのまま直書きしていたのは愚かであった。徐々に書き直して行こうと思う。

*1:無いように思われる。というのが正解。

Javaでガウス分布(正規分布)の乱数を得る方法

メモを兼ねて。
Javaガウス分布正規分布)の乱数を得るためにはjava.util.RandomのnextGaussian()メソッドを使えば良い。
返り値として「乱数ジェネレータのシーケンスを使った、平均 0.0、標準偏差 1.0 のガウス (「正規」) 分布の double 型の次の擬似乱数」(APIの解説そのまま)が得られるそうだ。
原理を完璧に飲み込まないまま使うの、本当はよくないのだろうけどやむを得ない。
蛇足だが、普通にJavaのAPIリファレンス中で参照した文献として、KnuthのThe Art of Computer Programmingを参照してます。と書いてあることに驚いた。

PHP Object Generatorのデータベースオブジェクトを使ってみる

お勉強がてらにPHP Object Generatorを使ってみた。そのときのメモ。読みにくいのはご愛嬌。
手順は以下の通り。

1. PHP Objct generator(http://www.phpobjectgenerator.com/)のページでDBオブジェクトの設定をする。
以下の様な内容で設定してみた。

  • テーブルの名前
    • userlist
  • DBの項目
    • NAME = VARCHAR(255)
    • AGE = INT
    • MAILADRS = VARCHAR(255)

設定を入力した際の画面は下の様な感じ。

f:id:hideack:20070805014754p:image

2. オブジェクト一式がzipに固められダウンロードできるのでダウンロードする。

3. ダウンロードしたパッケージを解凍する
解凍すると中身は以下の様な内容になっている。

  • configuration.php (DBに接続するためのパラメータ設定)
  • objectsディレクトリ
    • データベースオブジェクトが入っている模様
  • pluginsディレクトリ
  • setupディレクトリ
    • webサーバの公開領域に置いた際にブラウザから設定やテストができる模様

4. configuration.phpを設定する
おそらく目を通せば、そのままなのでわかると思う。
一部を示すと以下の様な形。そのまんま。

<?php
// edit the information below to match your database settings
$configuration['db']	= 'test';       // database name
$configuration['host']	= 'localhost';	// database host
// (以下続く)
?>

5. DBに実際にテーブルを用意する。
自分自身が手探り状態なので、とりあえず直接MySQLを操作して作る事にした。
で、ここで objects/class.userlist.php を見てみると、自動生成されたソースコードの上部のコメントに以下の様な内容が書かれている。

This SQL query will create the table to store your object.
CREATE TABLE `userlist` (
`userlistid` int(11) NOT NULL auto_increment,
`name` VARCHAR(255) NOT NULL,
`age` INT NOT NULL,
`mailadrs` VARCHAR(255) NOT NULL, PRIMARY KEY  (`userlistid`)) ENGINE=MyISAM;

最初の設定では、name, age, mailadrsの3列分の情報しか定義しなかったのだけど、Php Object Generatorはuserlistidというカウンタ値を付けて、それをprimary keyとして管理するということになっている模様。
なので、上記の定義をそのまま利用してMySQLにテーブルを作成する。

% mysql -u test -ptest
mysql> use test;
Database changed
mysql> CREATE TABLE `userlist` (`userlistid` int(11) NOT NULL auto_increment,`name` VARCHAR(255) NOT NULL,`age` INT NOT NULL,`mailadrs` VARCHAR(255) NOT NULL, PRIMARY KEY  (`userlistid`)) ENGINE=MyISAM;
Query OK, 0 rows affected (0.04 sec)

うむ。無事に出来た。

6. POGのDBオブジェクト経由でデータを書いてみる。
破竹の勢いで自動生成されたソースコードに目を通す。こんな感じで操作するとデーターベースに登録されそうだな。と、目星をつけて書いてみる。

<?php
require_once("configuration.php");
require_once("objects/class.database.php");
require_once("objects/class.userlist.php");
$db = new USERLIST("taro yamada", 30, "taro@hoge.com");
$response = $db->Save();
print "RESPONSE CODE=".$response."\n";
?>

これを実行してみると、

%php -q test.php
RESPONSE CODE=1

となる。ここで返却される数値はデータベースのテーブルのprimary keyとなっている項目(ここでは、userlistidという名前の列)の値であるので、書き込めたに違いないということで、MySQL経由で実際にテーブルを見てみる。

mysql> SELECT * FROM USERLIST;
+------------+-------------+-----+---------------+
| userlistid | name        | age | mailadrs      |
+------------+-------------+-----+---------------+
|          1 | taro yamada |  30 | taro@hoge.com |
+------------+-------------+-----+---------------+
1 row in set (0.01 sec)

おぉ、書けている!!
と、ここまでいった時点で久しぶりの夜更かし状態でかなり眠くなってきたので続きはまた明日。

<蛇足>
この使い方が正しい使い方なのか大きく謎ですので、その点はご了承ください。

Class: OPML Parser Class

PHP classes(http://www.phpclasses.org/)に最近登録されたOPMLパーサー。(http://www.phpclasses.org/browse/package/4026/)
アナウンスのメールを見ていたので試しに使ってみた。
このライブラリ以外に必須となるライブラリは無し。PHP標準関数を使って中で直でXMLを解析する様になっている。
使い方は非常にシンプル。

<?php
require_once('iam_opml_parser.php');
$parser = new IAM_OPML_Parser();
$parser->getFeeds("export.xml");  // export.xmlフィードリーダーが出力したOPML
print_r($parser->data);
?>

上のコードでわかる通り、パースするOPMLのソースを指定してgetFeedsというメソッドでOPMLが解釈されてインスタンスのメンバ変数に格納される。
上記のコードの実行結果は以下の通り。(メンバ変数dataのダンプ)

Array
(
[0] => Array
(
[names] => Subscriptions
[urls] =>
[targets] =>
[feeds] =>
[descriptions] =>
[created] =>
[type] =>
)
[1] => Array
(
[names] => にっき
[urls] => http://d.hatena.ne.jp/hideack/
[targets] =>
[feeds] => http://d.hatena.ne.jp/hideack/rss
[descriptions] =>
[created] =>
[type] => rss
)
[2] => Array
(
[names] => asahi.com
[urls] => http://www.asahi.com/
[targets] =>
[feeds] => http://feeds.asahi.com/asahi/TopHeadlines
[descriptions] =>
[created] =>
[type] => rss
)
)

直接、表示するためのHTMLを得たければdisplayOpmlContentsというメソッドがあるので、それを利用するとすぐにブラウザへ表示させることもできる様だ。

VCでDLLを作る話

DLLの中でMFCを使うと共有DLLでコンパイルしなきゃならないのか。(スタティックリンクにできない)
これに気づかず終日悩んでたのに、先ほど気づいたらあっという間に解決。
てか、以前つくったときには、ちゃんと意識していたんだろうけど時間が経っていたのですっかり忘れていた。
バラバラに作ってるので関連するプロジェクトは1つのソリューションファイルにまとめないとダメだ。と、今日の教訓。
うーん、始終VC++でプログラム書いてると、また違うんだろうけど、どうしても「にわか」状態になるところが悲しい。

勝手に回答するコーナー

id:its-tom の質問に勝手に回答するコーナー。
MySQLだとtimestamp型を使うとか。*1

CREATE TABLE TEST(
ID int,
CHECK_DATE timestamp
)

これで、

INSERT INTO TEST(ID) VALUES(0);

とすると、

ID=0
CHECK_DATE=20070709235540

と、いった感じにINSERT, UPDATEのタイミングで書き込まれる。
ただし、1テーブルに使えるtimestamp型は一つまで。

*1:もしかして、これは無しで、どうしてもDate型 etc... に入れたいって話だったのだろうか

KCAPTCHA + Ethna

EthnaKCAPTCHAを使うというお話。
KCAPTCHAは、よく会員登録サイト等である「ぐにゃ」っと曲がった文字列で画像認証するやつを作るためのPHPクラスライブラリ。PHP+GDで画像を作成してくれます。
例えば、

<img src="sample.php">

の様にして認証用画像を取得。sample.phpの中身はこんな感じ。

<?php
include('kcaptcha.php');
if(isset($_REQUEST[session_name()])){
session_start();
}
$captcha = new KCAPTCHA();
if($_REQUEST[session_name()]){
$_SESSION['captcha_keystring'] = $captcha->getKeyString();
}
?>

上のソースはサンプルのまま。
コンストラクタでヘッダ込みの画像データが吐かれるのでimgタグに画像が表示される。と。
表示の後、認証するためには画像に表示されている文字列を画面遷移後も保持しておく必要があるのでこのサンプルでは$_SESSION['captcha_keystring']に保持されているのだけど、ethnaの場合、Ethna_Sessionクラスでセッションが管理されるのでセッションIDが異なるので保持されない。
ということで、Ethnaのアクションクラスを作成

これで作成される app/action/Captcha.php の perform() 内に上記を真似て次の様な処理を書いておく。

<?php
include('kcaptcha.php');
//(中略)
function perform(){
if(!$this->session->isStart()){
$this->session->start();
}
$captcha = new KCAPTCHA();
$this->session->set("captcha_keystring", $captcha->getKeyString());
return 'captcha';
}
?>

これで、Smartyテンプレート内で

<img src="?action_captcha=true"><br>

何ぞと書けば無事表示。且つ、Ethna_Sessionにも表示した文字列が保持されているので、次のアクションでActionFormで取得した値とセッションの値とを比較すればよい。
なんと便利なライブラリだろう。作者の方に感謝。

…あとでキレイにまとめる。

ずっと愚直にサンプル通りやって、なんでうまくいかないんだろうと悩んでいたのだが、今朝バスに乗った瞬間、気づいたので駅までに着く間の10分でプログラムを書き上げた。
今日、一番集中力が出たのはあの時間だけだったかもしれない。

自作プログラムの話。

上は仕事のプログラムの話で次は自作のプログラムの話。
フィードリーダーを作って、あちこち手を入れつつ使っているのだけど巡回しているフィードの中で明らかに拒否反応的な内容を返してくるところがあることに気づいた。
巡回開始直後は希望するフィードのデータをくれていたのだけど、ある日を境にピッタリと中身が無くなり、広告しか入らなくなった。
これは、へんなbotか何かと解釈された。ってことなんでしょうか。
確かにヘッダとか今、特に書いていないので問題なのかなぁ。でも、巡回対象がフィードだからそんなに気にしなくてもいいと思っていたのだが。
実際に使い始めるといろいろなところが気になってくるものです。

System.out.printf(…)

上とは別にJavaのプログラムも書いているのだけど、そこで標準出力に文字列を出すときに1.5.0以降はSystem.out.printf("...");が使える様になったのを思い出して使ってみた。
うむ。ここだけは、やっぱりC言語みたくフォーマットを指定して書けるのがいいなぁ。
浮動小数点とかの出力を綺麗にしたいときに楽にできて非常にうれしい。
ただ、IBMJITコンパイラでは使えないのが残念。

time

%time php -q feedcrawle.php
0.727u 0.066s 0:50.45 1.5% 3841+6356k 0+1io 1pf+0w

実行してみて気づいた。
出力が微妙に違う気がする。上記は現在レンタルしてるサーバー(FreeBSD 6.1)のもの。
timeには…。

  • /usr/bin/time
  • csh, tcsh組み込みのもの

と2種類あるそうだ。*1
上記の場合、後者に該当して、

0.727u 0.066s 0:50.45 1.5% 3841+6356k 0+1io 1pf+0w

だと、

  • コマンド実行時間50秒45
  • ファイルI/O読み込み0回,書き込み1回

他はページやメモリだろうか。

*1:うーん、結構このコマンド何気に使っていたが気づかなかったなぁ