MySQL 3.23 な環境で CakePHP の hasAndBelongsToMany を利用する

  そもそもですが,CakePHP は MySQL 4.0 以上が対象らしいです.
  ただ,公式のドキュメントは見つかっていませんが……

  それでも,MySQL 3.23 な環境で CakePHP を使って,なおかつ hasAndBelongsToMany も使いたい場合の対処法です.
  MySQL 3.23 な環境では,hasAndBelongsToMany を使うとき,SQL のエラーが出ます.具体的には JOIN に失敗しています.

  このとき CakePHP は以下のような SQL 文を発行します.

SELECT  `Tag`.`id`, `Tag`.`tag`
FROM `tags` AS `Tag`
JOIN `posts_tags` ON `posts_tags`.`post_id` = '2'
 AND `posts_tags`.`tag_id` = `Tag`.`id`
WHERE  1 = 1


  MySQL のリファレンスにあるように,JOIN は MySQL 4.0.11 以降で対応なので,この JOIN を INNER JOIN にしてあげればいいわけです.

- ref.: MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 6.4.1.1 JOIN 構文
  http://dev.mysql.com/doc/refman/4.1/ja/join.html

注意:INNER JOIN 構文で join_condition  を使用できるのは、MySQL 3.23.17 以降に限られます。同様に、JOIN  と CROSS JOIN に関しても、MySQL 4.0.11 以降でのみ条件を指定できます。


  ちょうど昨日 CakePHP の最新版 (1.1.14.4797) がリリースされたので,この最新版と,その前のバージョン (1.1.13.4450) での修正箇所を挙げておきます.

- 1.1.14.4797 の場合
  cake/libs/model/datasources/dbo_source.php の 1051 行目を修正します.

--- cake_1.1.14.4797-orig/cake/libs/model/datasources/dbo_source.php    2007-04-06 04:21:05.000000000 +0900
+++ cake_1.1.14.4797/cake/libs/model/datasources/dbo_source.php    2007-04-06 08:46:09.015389000 +0900
@@ -1048,6 +1048,7 @@
                     'joins' => array(array(
                         'table' => $joinTbl,
                         'alias' => $joinAssoc,
+                        'type' => 'INNER',
                         'conditions' => array(
                             array("{$joinAlias}.{$assocData['foreignKey']}" => '{$__cakeID__$}'),
                             array("{$joinAlias}.{$assocData['associationForeignKey']}" => '{$__cakeIdentifier['."{$alias}.{$linkModel->primaryKey}".']__$}')


- 1.1.13.4450 の場合
  cake/libs/model/datasources/dbo_source.php の 1043 行目を修正します.

--- cake_1.1.13.4450-orig/cake/libs/model/datasources/dbo_source.php    2007-02-03 11:55:49.000000000 +0900
+++ cake_1.1.13.4450/cake/libs/model/datasources/dbo_source.php    2007-04-06 09:13:16.018886000 +0900
@@ -1040,7 +1040,7 @@
                 }
                 $sql .= ' ' . join(', ', am($this->fields($linkModel, $alias, $assocData['fields']), $joinFields));
                 $sql .= ' FROM ' . $this->fullTableName($linkModel) . ' ' . $this->alias . $this->name($alias);
-                $sql .= ' JOIN ' . $joinTbl;
+                $sql .= ' INNER JOIN ' . $joinTbl;
 
                 $joinAssoc = $joinTbl;



  上記の修正はあくまで,hasAndBelongsToMany を使いたい場合で,そのほかの項目はあまりテストしていませんのでご注意を.
  可能であれば,MySQL 4.0.x にアップデートするのが一番だと思います.

Groove Technology の郵便番号検索 API を扱う Services_Groove_ZipSearch を作りました

- グルーブテクノロジー株式会社 - Web サービス
  http://groovetechnology.co.jp/webservice/

  グルーブテクノロジーによる郵便番号検索 API を利用して,結果を取得するライブラリ Services_Groove_ZipSearch を作りました.

  この API の特長は,JSON 形式,JSONP 形式,XML 形式,PHP の serialize() 形式という風に,任意の形式で出力を受け取れることです.
  今回は,PEAR パッケージにしてみました.

- Services_Groove_ZipSearch-0.1.0
  http://pocari.org/tools/php/Services_Groove_ZipSearch-0.1.1.tgz

  インストールは,以下のようできます.

# pear install http://pocari.org/tools/php/Services_Groove_ZipSearch-0.1.1.tgz

- 使い方

<?php

require_once 'Services/Groove_ZipSearch.php';

$zip = new Services_Groove_ZipSearch;

$result = $zip->search(1000001);
if (PEAR::isError($result)) {
    exit($result->getMessage());
}

print_r(unserialize($result));
?>


- 出力

Array
(
    [address] => Array
        (
            [0] => Array
                (
                    [zipcode] => 1000001
                    [prefecture] => 東京都
                    [city] => 千代田区
                    [town] => 千代田
                    [prefecture_yomi] => トウキョウト
                    [city_yomi] => チヨダク
                    [town_yomi] => チヨダ
                )

        )

    [office] => Array
        (
        )

)


  Groove_ZipSearch::search() に郵便番号検索 API のパラメータを渡すことができます.
  パラメータの種類と順序は,郵便番号検索 API のリクエストパラメータと同じです.詳しくはソースを見てください.

  また,郵便番号検索 API の出力形式 (format) のデフォルト値は json になっていますが,このライブラリでは PHP になっています.
  すなわち,serialize() された形がデフォルトで戻ってきます.

- via: using API; RESTで使える郵便番号検索API
  http://api.zuzara.com/archives/115

- 追記 (2007-12-18)
  サンプルが間違っていたのを修正して、0.1.1 (alpha) をリリースしました。
  サンプルの出力結果を追記しました。

FC2 ソーシャルスパム対策の API を扱う Services_FC2 を作りました

  FC2 がスパム情報を共有するソーシャルスパム対策なるサービスを始めたので,公開されている API を利用して結果を取得するライブラリ Services_FC2 をつくりました.

- FC2 ソーシャルスパム対策
  http://seo.fc2.com/spam/

  Services とついていますが,PEAR パッケージには全くなっていません.
  バージョンも 0.0.1 となっていますが,今後バージョンアップされるかどうか不明です.

- Services_FC2
  http://pocari.org/tools/php/Services_FC2-0.0.1.tgz

- サンプル
  上記ライブラリを展開して,Services_FC2-0.0.1 を Services にリネームして,以下のサンプルでとりあえず使えます.

<?php
require_once 'Services/FC2.php';

$fc2 = Services_FC2::factory('SPAM');

// URL を指定してスパムサイトに登録してあるかどうか取得
// オプションを個別に設定する
$fc2->setURL('http://example.com');
$fc2->setCharset('EUC-JP');
$fc2->setData(1);
$result = $fc2->execute();

echo $result, "\n";

// スパムリストの取得
// オプションを一括で設定することもできる
$fc2->setOptions(array(
    'm' => 'ul',
    'chr' => 'EUC-JP',
));
$result = $fc2->execute();

echo $result, "\n";
?>


- API のヘルプ
  http://seo.fc2.com/spam/spamapi.php?m=h

  使ってみるとすぐ分かりますが,この API はまだ発展途上のようです.

o 結果がどのような形で返って来るのかよくわからない
  XML でもなんでもないただの CSV っぽいもので返って来るのですが,戻り値が仕様に明記されていないのでよくわかりません.

o キャラクターコードを指定しても,エラーメッセージは Shift-JIS 固定っぽい

o オプションの data に 1 を指定して,スパム情報詳細を返すようにするとなぜか <br> のように HTML のタグが含まれて返って来る.

o 最新のデータが返されないっぽい (現在は 1 件だけしか返ってこない?)

PHP 4 の --enable-versioning はトラブルの元か?

  PHP 3 と PHP 4 を共存させる場合に,configure オプションに --enable-versioning を指定します.
  実はこれが思わぬ落とし穴になる場合があります.

  それは,DSO で拡張モジュールが動的にロードできないというものです.
  PHP 4.4.4 + Apache 1.3.37 on Solaris 10 x86 の環境なので,もしかしたら環境依存かもしれません.

  コンパイル・インストールはうまくいきますが,Apache を再起動すると以下のようなエラーが出ます.

- SQLite の場合

PHP Warning:  Unknown(): Unable to load dynamic library '/usr/local/lib/php/extensions/no-debug-non-zts-20020429/sqlite.so' - ld.so.1: httpd: fatal: relocation error: file /usr/local/lib/php/extensions/no-debug-non-zts-20020429/sqlite.so: symbol executor_globals: referenced symbol not found in Unknown on line 0

- Xdebug の場合

Failed loading /usr/local/lib/php/extensions/no-debug-non-zts-20020429/xdebug.so:  ld.so.1: httpd: fatal: relocation error: file /usr/local/lib/php/extensions/no-debug-non-zts-20020429/xdebug.so: symbol zend_compile_file: referenced symbol not found

  CLI 版では,全く問題なくロードできるので,原因が全然分かりませんでした.
  これらのエラーが出る場合は,--enable-versioning を外して PHP 4 を再コンパイルするとうまくいくと思います.

  もはや,PHP 3 を共存させることは皆無に等しいと思うので,--enable-versioning のことは忘れてしまったほうがよさそうです.

  参考までに --enable-versioning をマニュアルを見てみると,

--enable-versioning

   要求されるシンボルのみをエクスポートします。 詳細な情報は INSTALL を参照ください。
--enable-versioning

   Solaris 2.x および Linux が提供するバージョン管理機能を 有効にします。PHP 3 限定です!

  とあります.

- Configure オプション
  http://www.php.net/manual/ja/configure.php

- ref.: Blog::koyhoge - [PHP] --enable-versioningを止めるの巻
  http://d.hatena.ne.jp/koyhoge/20061213/1165999933

PHP × Web サービス API コネクションズ

  4797336838
  amazon.co.jp 詳細ページへ
  秋元 裕樹 (著)
  ソフトバンククリエイティブ
  ISBN: 4797336838
  2006/11/30
  2,940 円

PHP によるデザインパターン入門

  4798015164
  amazon.co.jp 詳細ページへ
  下岡 秀幸 (著), 道端 良 (著), 畑 勝也 (著)
  秀和システム
  ISBN: 4798015164
  2006/11
  3,150 円

Smarty を使った開発でデバッグを行う 4 つの方法

  PHP のテンプレートエンジン Smarty を使って開発するときに,割り当てた変数が複雑になって困ることはありませんか?
  その際,何らかの方法を使って割り当てた変数を確認するのですが,いくつか方法があります.

1. 常にデバッギングコンソールを表示する方法


  おそらく一番有名な方法ですが,$debugging に true を指定して,常にデバッギングコンソールを表示する方法です.

require_once 'Smarty.class.php';

$smarty = new Smarty;
$smarty->debugging = true;


  これで,常にデバッギングコンソールが表示されます.

  デバッギングコンソールは,window.open() を使った JavaScript によるポップアップウィンドウですが,以下のように _smarty_debug_output に html を割り当てることで,ドキュメント中に埋め込むことができます.

require_once 'Smarty.class.php';

$smarty = new Smarty;
$smarty->debugging = true;
$smarty->assign('_smarty_debug_output', 'html'); // 'html' を '' にするとポップアップ


- ref.: $debugging
  http://smarty.php.net/manual/en/variable.debugging.php

2. URL に SMARTY_DEBUG が含まれる場合にデバッギングコンソールを表示する方法


  $debugging_ctrl に 'URL' を指定して,URL に QUERY_STRING が含まれる場合にデバッギングコンソールを表示する方法です.

require_once 'Smarty.class.php';

$smarty = new Smarty;
$smarty->debugging_ctrl = 'URL'; // 解除は 'NONE'


  このように設定して,

http://example.com/foo.php?bar=baz

  という URL の場合には,

http://example.com/foo.php?bar=baz&SMARTY_DEBUG

  このようにすれば,デバッギングコンソールが表示されます.
  ちなみに,SMARTY_DEBUG=off の場合は,デバッギングコンソールは表示されません.

  $debugging = true の場合は,この設定は無視されます.

- ref.: $debugging_ctrl
  http://smarty.php.net/manual/en/variable.debugging.ctrl.php

3. テンプレート変数 debug を利用してデバッギングコンソールを表示する方法


  デバッギングコンソールはテンプレート変数を使っても表示することができます.

{debug}


  たったこれだけです.$debugging や $debugging_ctrl の設定にかかわらず表示されます.
  ポップアップ式ではないデバッギングコンソールをドキュメントに埋め込むには以下のようにします.

{debug output='html'}


- ref.: {debug}
  http://smarty.php.net/manual/en/language.function.debug.php

4. debug_print_var 修正子を利用して,割り当てられた変数を表示する方法


  この方法はドキュメントに載っていないのですが,上記 3 つのデバッギングコンソールを表示する方法とは異なり,1 つの変数の内容を表示するものです.

$foo = array(
    'a' => '',
    'b' => '',
    'c'=> array(
        'd' => ''
    )
);

$smarty->assing('foo', $foo);


  上記のように,配列が割り当てられた場合は,

{$foo|@debug_print_var} {* $foo は配列なので @ が必要 *}


  このようにすることで,以下のように $foo の内容だけが出力されます.

Array (3)
a => あ
b => い
c => Array (1)
 d => う

  debug_print_var はプラグインとして含まれてますが,ドキュメントには載っていません.
  しかし,デフォルトのデバッギングコンソール用のテンプレート debug.tpl で使われています.

  debug_print_var はデフォルトでは 40 文字で表示が切られてしまいます.これはオプションで調節できます.
  例えば 100 文字まで表示する場合は,以下のように指定してあげれば OK です.

{$foo|@debug_print_var:0:100}


  100 の前のオプションの 0 は,配列やオブジェクトを表示する際のインデント幅です.


- おまけ
  Smarty のテンプレート内で JavaScript を書く場合 { } がテンプレート変数として扱われるので {literal} で囲むのが面倒だとか,JavaScript の中にテンプレート変数を割り当てられないだとか耳にすることがあります.

  この場合は,テンプレート変数の { } を変更すればいいです.

require_once 'Smarty.class.php';

$smarty = new Smarty;
$smarty->left_delimiter  = '<{';
$smarty->right_delimiter = '}>';


  上記の設定は XOOPS が使っているもので,テンプレート変数は以下のよう記述します.

<{$foo}>


  これを使うと,以下のように JavaScript を場合に {literal} で囲む必要もありませんし,JavaScript の中にテンプレート変数を割り当てることもできます.

<script type="text/javascript">
function foo() {
    var a = '<{$foo|escape:"javascript"}>';
};
</script>



- Smarty 入門 PHP5+テンプレート・エンジンでつくる MVC アプリケーション
  4798108839
  amazon.co.jp 詳細ページへ
  山田 祥寛 (著)
  翔泳社
  ISBN: 4798108839
  2005/3/15
  2,940 円

PHP の薬箱 エラー・トラブル回避のテクニックとセキュリティ対策

  486167140X
  amazon.co.jp 詳細ページへ
  佐久嶋 ひろみ (著)
  九天社
  ISBN: 486167140X
  2006/11
  2,940 円

  Amazon には目次がないけど,出版社のサイトにでていました.

- PHP の薬箱
  http://www.9-ten.co.jp/bookdata/140X.php

  これをみると,Symfony や Zend Framework など最近の話題も扱っているようにみえます (どれくらいのボリュームかはまた別ですが).
  対象がいまいち分からなかったりもするのですが,逆引き用として使えるのかも.ちょっと気になる.

PHP 5.2.0 でデフォルトの拡張モジュールになった JSON 拡張モジュールを試してみる

- JSON 関数
  http://php.net/json

$data = array(
    'a' => '',
    'b' => '',
    'c'=> array(
        'd' => ''
    )
);

mb_convert_variables('UTF-8', 'EUC-JP', $data);
$json = json_encode($data);
echo $json, "\n";

$array = json_decode($json, true);
mb_convert_variables('EUC-JP', 'UTF-8', $array);
print_r($array);


  文字コードは EUC-JP で.文字コードが UTF-8 の場合は,mb_convert_variables() での文字コードの変換は必要ありません.

{"a":"\u3042","b":"\u3044","c":{"d":"\u3046"}}
Array
(
    [a] => あ
    [b] => い
    [c] => Array
        (
            [d] => う
        )

)

  PHP 5.1.6 以前や PHP 4.4.4 以前の場合は Jsphon を使えば同等のことができます.
  もちろん,JSON 拡張モジュールをインストールすれば古いバージョンの PHP でも JSON 関数が使えます.

- Jsphon
  http://www.hawklab.jp/jsonencoder/

- PECL :: Package :: json
  http://pecl.php.net/package/json

mb_convert_variables() は連想配列のキーを文字コードを変換しない

- mb_convert_variables
  http://php.net/mb_convert_variables

$array = array(
    'あいうえお' => 'アイウエオ'
);

mb_convert_variables('UTF-8', 'EUC-JP', $array);
var_dump($array);


  文字コードは EUC-JP で.「アイウエオ」は UTF-8 に変換されるけど,「あいうえお」は EUC-JP のまま.

  まあ,文字コードが変換されるとキーが変わってしまうわけなので,そういう仕様なんでしょう.