2009年12月4日金曜日

PHPでの配列の並び替え(ソート)の比較

PHP5.3で実験。
何気なくsort()を使うと、意外と意外な結果になるので注意。

$before = array('Google', 'apple', '+11112', 1112, '112', 12, '0', -1);

$array = $before;
sort($array);
foreach ($array as $val) echo $val . ', ';
//sort()の第2引数のデフォルトはSORT_REGULAR
//文字列は大文字優先
//今回のように数値と文字列が混在するとおかしくなる?
// => -1, 0, 112, Google, apple, 12, 1112, +11112,
echo '<hr />';

$array = $before;
sort($array, SORT_NUMERIC);
foreach ($array as $val) echo $val . ', ';
//数値としてソート
//文字列は大文字・小文字を無視したソートで、ゼロの前になるようだ
// => -1, apple, Google, 0, 12, 112, 1112, +11112,
echo '<hr />';

$array = $before;
sort($array, SORT_STRING);
foreach ($array as $val) echo $val . ', ';
//文字列としてソート
//記号、数字、文字列(大文字優先)の順
//数は数ではなく文字列としてソートされる
// => +11112, -1, 0, 1112, 112, 12, Google, apple,
echo '<hr />';

$array = $before;
sort($array, SORT_LOCALE_STRING);
foreach ($array as $val) echo $val . ', ';
//localeごとのソート(今回の環境ではSORT_STRINGと同じだった)
// => +11112, -1, 0, 1112, 112, 12, Google, apple,
echo '<hr />';

$array = $before;
natsort($array);
foreach ($array as $val) echo $val . ', ';
//「自然順アルゴリズム」
//人間がやったらまあこうするだろうという感じか
//記号、数、文字列の順
//数値は文字列ではなく数値としてソートされるのがSORT_STRINGとの違い
// => +11112, -1, 0, 12, 112, 1112, Google, apple,
echo '<hr />';

$array = $before;
natcasesort($array);
foreach ($array as $val) echo $val . ', ';
//「自然順アルゴリズム」、かつ大文字小文字を区別しない
// => +11112, -1, 0, 12, 112, 1112, apple, Google,

natcasesort()が一番しっくりくる。
大文字・小文字の違いは無視して欲しいし。

2009年12月2日水曜日

もう一歩踏み込んでGoogle Maps APIを使いこなすためのリンク集

Google Codeにあるもの(全て英語)

Google Maps API Reference - Google Maps API - Google Code

  • Google Maps APIリファレンスの英語版。日本語版と違い、最新情報が載っている

The Google Maps API V3 - Google Maps JavaScript API V3 - Google Code
  • Google Maps API V3 (Version 3)のリファレンス
  • 現時点では英語版のみ
  • Version 2の方がまだ機能が多いが、これからに期待

gmaps-utility-library-dev - Project Hosting on Google Code

google-maps-utility-library-v3 - Project Hosting on Google Code
  • 上記のgmaps-utility-libraryのGoogle Maps API V3版
  • 中身はまだ1つしかない。これからに期待

google-maps-icons - Project Hosting on Google Code

gmaps-api-issues - Project Hosting on Google Code
  • Google Maps APIへの要望やバグ報告など

(おまけ)
Google Mapsの中心人物、PameraさんのGoogle Code上のプロジェクト一覧
pamela.fox - Project Hosting on Google Code



その他


Google Maps 活用講座 - GoogleマップAPIの使い方を分かりやすく解説!
  • 初心者から上級者まで参考になりそう

Google Mapsをほどよくカスタマイズしてお手軽に表示 - Google Mapper [ゼロと無限の間に]
  • Google Mapsをサクッと使うためのプラグイン

2009年11月28日土曜日

Googleサイト内検索結果でページの下端が切れる問題

検索向けAdSenseによるサイト内検索で、IE以外だと検索結果の下端が切れてしまう問題について。


【発生条件】
検索結果を自分のサイト内に表示する場合に起きる。
広告を右のみにした場合に起きた。広告を他の位置にしたら起きないかも。
Firefox(3.5)、Google Chrome(4)、Safari(4 Windows版)で発生を確認した。


【現象】
検索結果の内容に関わらず、検索結果を表示するiframe(JavaScript http://www.google.com/afsonline/show_afs_search.js により生成される)の高さが常に1200pxになる。
その結果、検索結果が少ない場合は検索結果とフッターの間に大きな空白ができる。反対に検索結果が多い場合、検索結果の下端に表示されるページ番号の表示が途中で切れてしまったり表示されなくなってしまう。(実際にはframeの外側にあり、かつframeのスクロールバーが非表示になっているので隠れているだけだが。)


IEの場合、iframe内の検索結果のHTMLのbody要素に、onloadで下記のようなJavaScriptを実行している。

onload="window.top.location='http://(親windowの検索結果のURL)#'+document.body.scrollHeight;"
これにより、親windowのURLの末尾にiframe内のコンテンツの高さを表すhashが付く。

そして検索結果のshow_afs_search.jsの方でlocation.hashを取得し、それをiframeの高さとして設定している。(0.01秒ごとに実行するという監視をしている。高さが取得できた後も。)
その結果、検索結果のコンテンツの内容に応じて検索結果をリサイズするというユーザーフレンドリーなユーザーインターフェイスを実現している。

試しに検索結果を表示した後、URLの最後に「#500」などと付けると検索結果の高さが変わる。これはFirefoxでも有効。


なぜIE以外ではiframe内のbodyのonloadのJavaScriptを付けないのだろう?Firefoxのセキュリティ等により無意味なんだろうか?


【回避策】
検索結果を表示するページのgoogleSearchXxxを設定しているJavaScriptに、下記のように高さを明示的に指定してあげる。
var var googleSearchFrameWidth = 800; //これは既存のコード
var googleSearchFrameHeight = 1210; //これを追加する
これにより、デフォルトの高さが1210pxになり、検索結果の下端が切れなくなる。

IEの場合、これでもリサイズが有効なので、この値は無視してリサイズしてくれると思う。

CakePHPの GetText (i18n)で複数形の翻訳をする

はまったのでメモ。最初からリファレンスや参考サイトを見ながらやれば書いてあったんだろうけど。


CakePHPで単数と複数で異なる翻訳を付けようとした。

__n(' person', ' people', $count);
poファイルも書いた。
msgid " person"
msgid_plural " people"
msgstr[0] "人"
msgstr[1] "人"

するとエラー(Warning)が表示された。
Warning (2): strlen() expects parameter 1 to be string, array given ...


該当箇所はCORE/cake/libs/i18n.phpのtranslate()。
if (is_array($trans)) {
if (isset($trans[$plurals])) {
$trans = $trans[$plurals];
}
}
if (strlen($trans)) {
$singular = $trans;
return $singular;
}
strlen()に配列を渡しているようだ。
でもその上で$transが配列の場合は文字列に入れ替えてるはず。(変数の使いまわしは良くないと思う。)それが効いてないのは「isset($trans[$plurals])」がfalseになっているということか。

この$pluralsをセットしているところを追うと、今回の場合は同じファイル内の__pluralGuess()によりセットしているようだ。
__pluralGuess()の中を追うと、$headerの中身で判断してるようだ。
if (strpos($header, "plurals=3")) {
if (strpos($header, "100!=11")) {
if (strpos($header, "10<=4")) {
return $n % 10 === 1 && $n % 100 !== 11 ? 0 : (略)

$headerを出力してみる。
nplurals=INTEGER;plural=EXPRESSION;

ん?さっきのif文の条件と似ても似つかない。
これは...poファイルで何か設定不足?

poファイルの最初の方を見てみる。
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
まさにこれだ。

こうしてみる。(キャッシュの削除も忘れずに。)
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

動いた!

以上。

2009年11月6日金曜日

PHPで Fatal Error時の状況を調べる方法

PHPでFatal Errorが発生すると以降の処理が実行されない。
かつ、try/catchやset_error_handler()ではFatal Errorを捕まえられない。
なので通常は、Fatal Errorが起きたときの詳しい状況はログに残らない。
(例えばエラーが起きたPHPのファイル名はログに残るが、それを呼び出した側のPHP名や、データの状況は分からない。)

しかし、register_shutdown_function()を使えばエラーが起きたときの状況をログに残せる。

register_shutdown_function('shutdownHandler');

function shutdownHandler(){
$error = error_get_last();
if ($error['type']) { //エラーの場合のみ
error_log(...); //必要な情報を書き出す。
}
}

ただしこれだとE_NOTICEとかでもひっかかってしまうので、Fatal Errorだけを拾いたい場合はtypeを指定する。
register_shutdown_function('shutdownHandler');

function shutdownHandler(){
$error = error_get_last();
if ($error['type'] == E_ERROR) {
error_log(...); //必要な情報を書き出す。
}
}
これだとExceptionが拾えない?


参考:
PHP の「エラー処理ハンドラ」「シャットダウンハンドラ」「例外処理ハンドラ」の挙動 - Web/DB プログラミング徹底解説
PHP: register_shutdown_function - Manual


ブログ アーカイブ

映画の殿堂 The Red Carpet コメントRSS

[掘出(H)市場] 新着の掘出し物

tags