最後に挿入したクエリの ID を取得する

PostgreSQL 8.1 になって、
MySQL における LAST_INSERT_ID() に似た機能をもつ、LastVal() がサポートされるようになりました。

MySQL:
CREATE TABLE employee (
  id int unsigned auto_increment not null primary key,
  name varchar(128) not null
);
 
INSERT INTO employee (name) VALUES (‘John’);
SELECT LAST_INSERT_ID();

と、次のものは全く同等の意味になります。

PostgreSQL:
CREATE TABLE employee (
  id serial not null primary key,
  name varchar(128) not null
);
 
INSERT INTO employee (name) VALUES (‘John’);
SELECT LASTVAL();

 
LASTVAL() はシーケンスのインクリメント関数である NEXTVAL() が一番最後に返した値を返すものです。
 
PostgreSQL の LASTVAL() は MySQL の LAST_INSERT_ID() と同様に、
他のセッションでの NEXTVAL()の影響は受けません。
 
一度も自分のセッションで NEXTVAL() を呼び出していない場合は、”ERROR: lastval is not yet defined in this session”というエラーが発生します。
 
参考:
PostgreSQL を MySQL 互換にする(Open Tech Press)
シーケンス操作関数(PostgreSQL 8.1.0 日本語ドキュメント)

ttyrec で Out of pty’s エラー

CentOS 4.3 に ttyrec を入れたところ、RedHat 版の RPM では ttyrec コマンドを使うと Out of pty’s と怒られてしまいました。
 
ソースをダウンロードしてきて、README にならって

make CFLAGS=-DSVR4

としたところ、問題なく動作しました。
参考:
[2006-04-11] 端末での作業を記録/再生する

静的にも動的にも呼び出し可能なメソッドを定義する

次のように、メソッド内で $this の存在を empty() ないし isset でチェックすることで、エラーになることなく static かインスタンスメソッド呼び出しかで動作を分けることができます。
(PHP4.4 / 5.1 にて動作確認済)

<?php
class Foo{
  var $mes;
  // コンストラクタ
  function Foo($mes){
    $this->mes = $mes;
  }
  // クラスメソッド兼インスタンスメソッド
  function greet($mes = false){
    if(!$mes && !empty($this) ){
      // インスタンスが存在する。
      $mes = $this->mes;
    }else{
      // static 呼び出し。
    }
    echo ($mes?$mes:’empty’).”\n”;
  }
}
error_reporting(E_ALL);
$o = new Foo(‘hello’);
$o->greet(); // 結果: hello
 
Foo::greet(‘static hello’); // 結果: static hello
Foo::greet(); // 結果 empty
 
?>

ブラウザの通信の切断は CGI の処理中断につながるか?

HTTP でサーバサイドプログラムの実行中に通信が切断された場合、
サーバサイドのプログラムがどうなるか?という疑問から
PHP 4.4.X + Apache 2.0.X でちょっと実験してみました。

exp_timeout.php:
<?php
set_time_limit (0); // PHP の処理時間制限を無しに。
 
display(‘begin’);
for($i = 1; $i <= 100; $i++){ // 100 秒間処理をする。
  sleep(1);
display(($i*1).’%’);
}
 
display(‘end’);
 
// 表示&記録。
function display($mes){
   $line = date(‘Y-m-d H:i:s’).”: “.$mes.”<br>\n”;
   echo $line; // (*1)
   system(‘echo ‘.escapeshellarg($line).’>> result.html’);
   //flush(); ob_flush(); // (*2)
}
?>

この PHP スクリプトに Apache 経由でアクセスし、
レスポンスが返ってくるまでに HTTP クライアントのリクエストを中断させてみます。中断しても、result.html に結果が書かれるため、result.html にアクセスすることで処理がどこまで進んだか確認できます。
この検証を、(*1)、(*2)のコメントアウト, アンコメントアウトして行ってみました。
 
なお、PHP の設定についてはデフォルトで出力をバッファするものとします。
 
結果(コメントアウト状態を「なし」、コメントアウトを外した状態を「あり」と表記します):
– (*1)あり (*2)なし: 常に 100% まで完了。
– (*1)あり (*2)あり: 切断して数回出力した後に処理が中断。
– (*1)なし (*2)あり: 常に 100% まで完了。
– (*1)なし (*2)なし: 常に 100% まで完了。
 
 
考察:
HTTP 通信が切断された場合、HTTPレスポンス送信に規定回数失敗した時点で切断されたと認識され、スクリプトの処理が中断されるようです。
(*2), (*1)いずれかをコメントアウトした場合、処理完了まで一切出力を行わず、通信の切断を検知しないため、通常通り最後まで実行すると考えられます。
 
注:
この実験は、Apache 2.0 に限定したもので、仕様も一切あたらず行ったため、これ以外の HTTP サーバの場合に必ずしも同じ結果になるとは限りません。
 
捕捉:
処理時間を600秒など極端に長い時間にしてもタイムアウトすることなく動作を続けました。

画像ファイルの EXIF 情報を表示する

Exif 2.2 対応してるものは数が少ないですが、CUI で対応しているものを見付けました。
 
Exifファイルの情報表示プログラム(ナカタの Digital Wonder Land)
 
対応は Windows(バイナリ配布), Linux 他(ソース配布)。
記事を書いている現在、ソース(sanyo.c)が不足しているようですが、工夫すればコンパイル可能です。
 
なお、このプログラムはライセンス形態が特殊なため、ダウンロードの際は注意してください。

変数代入とそのメモリ使用量についての検証

大したことではありませんが、ふと気づいたのでメモしておきます。
 
検証環境: PHP 4.4.2
時間, メモリ量のリミットなし
なお、都合により memory_get_usage() ではなく top コマンドでメモリ消費を確認しています。
 

$n = 5; // sleep する秒数
 
echo “Started..\n”;
$a = str_repeat(“a”, 1024 * 1024 * 10); // 10MB
sleep($n); // #使用量 13MB
echo “Cloning \$a into \$b.\n”;
$b = $a; // コピー
sleep($n); // #使用量..変化なし ←この時点では参照($b=&$a)と同等
echo “Modifing \$a.\n”;
$a{0} = ‘b’; // $a の 0 文字目を ‘b’ に変更
sleep($n); // #使用量..23MB ←一方が変更されて始めてバッファが複製される
echo “Freeing \$a.\n”;
$a = null; // 解放
sleep($n); // #使用量..13MB
echo “Referring \$b for \$c \n”;
$c =& $b; // 参照
sleep($n); // #使用量..変化無し
echo “Modifing \$b.\n”;
$b{0} = ‘c’; // $b の 0 文字目を ‘c’ に変更
sleep($n); // #使用量..変化無し
echo “Freeing memory for \$b (and also \$c)\n”;
$b = null; // 解放
sleep($n); // #使用量..3MB

 
この検証でわかるのは、単純な代入の場合は、代入元、代入先いずれかが変更されるまでは参照と同等に処理する(つまりメモリ確保や strcpy をしない)ということです。
 
上の例のように変数の値を捨てたり unset したりして明示的にメモリを解放してやらなくても、変数が関数の終了でスコープアウトした時点で自動的に解放されます。
 
ただし、Chain of Repository Pattern など、メソッド、関数の呼び出しが連鎖する場合は、呼び出し先の関数が終了するまで、呼び出し元の関数内の変数も存在し続ける事に注意が必要です。
 

$a = str_repeat(“a”, 1024 * 1024 * 10);
// 3 段の連鎖(※1)
$o = new Chain(1,
  new Chain(2,
    new Chain(3, null)
  )
);
$o->handle($a); // 連鎖実行。
// ↑ここだけで最終的に Chain の段数 x strlen($a) バイトのメモリを消費する!!
 
echo “Finished\n”;sleep(6);
echo substr($a, 0, 100).”\n”;
exit;
// ——————————–
// Chain Of Repository パターンの簡単な実装
class Chain{
   var $v;
   var $_next;
   function Chain($v, $next = null){
       $this->v = $v;
       $this->_next = $next;
   }
   function next(&$buf){
       if(!empty($this->_next)) $this->_next->handle($buf);
   }
   function handle(&$buf){
       echo “Step:{$this->v}\n”;
       // $buf に使って何らかの処理をし、結果を $res に格納。
       $res = $this->v.$buf;
       $buf = $res; // $buf を処理結果に置き換え。
       sleep(5); // (※2)
       $this->next($buf); // 次の処理へ($res が生きている)。
   }
}

 
この Chain クラスでは(※1)を重ねれば重ねるほどメモリ利用量が増え続け、handle が全て完了するまで解放されないという一種のメモリリークが発生しています。
これを解消するには(※2) の箇所で $res = null などで解放を明示してやる必要があります。

HTTP_Client 1.1 の不具合?

HTTP_Client が 1.1 になって get/post 時に <meta http-equiv=’Refresh’> のリダイレクトをたどってくれるようになりました。

(ChangeLogより抜粋)
* HTTP_Client now analyzes the response body for <meta http-equiv=”Refresh”>
tags and follows the redirects defined in them (request #5734)

 
便利になっていいのですが、このアップデート以降 “Fatal Error: Too many redirects” というエラーが出るようになりました。_maxRedirects の値に達するまで延々と同じURLをアクセスし続けて、その結果発生しているようです。
 
別の環境での再現を確認していないのですが、この現象は <meta http-equiv=”Refresh” contents=”…;url=/path/to/nextPage”> を利用しているサイトで post() でリクエストすると発生するようです(post($url.$query, array()) も不可)。全く同じコードでget() に置き換えると問題なく動作しました。