ソフト開発の小ネタ

2008年03月04日

SafariでevalScriptsが動かない・・・

 1年くらい前はAjaxやらDOM操作やらを駆使したWEBアプリにSafariを対応させようとすると、すぐに挫折していましたが、3.0.4にバージョンアップされて、意外とすんなり動作するようになった気がします。が、それでもまだちょっとハマってしまいます。

 Ajaxで取得したHTMLテキスト内のscriptタグを実行するため、prototype.js(バージョンは1.6.0.2)のevalScriptsを使ってみたのですが、IE6や7、FireFox2.0では問題なく動作するのに、Safari3.0.4ではうんともすんとも動きません。スクリプトの先頭行すら実行されていないので、どうやらscriptタグの抽出あたりで失敗しているような感じ。Safariでは割りと文字コードの問題があるようなので、試しにscriptタグ内の日本語を取り除くとうまく動作しました。scriptタグ以外に日本語がある分には問題ないようですね、UTF-8だから?
 で、どうしようか悩んだのですが、Unicodeエスケープシーケンス(\uと4桁の16進数で表現するアレ)で日本語を出力すると、Safariでも動くしIEやFireFoxでも問題ないようですので、この方法で対策することにしました。

 今回はRuby on Railsフレームワークを使っているので、どこかの賢い人のコードを参考にさせて頂き、

def to_unicode(text)
  utext = ""
  text.unpack("U*").each {|num|
    utext << sprintf("\\u%04x", num.to_i);
  }
  utext
end
のような変換関数を用意して、evalScriptsで実行するscriptタグ内の日本語を片っ端からUnicodeエスケープシーケンスに変換しました。

2007年07月12日

複数のデータベースを切り替えて使う

 ふつう、XOOPSをこんな風に使おうとはしないかも知れません。1つのXOOPS環境で複数のデータベースを切り替えて使おうなんて――。これってどういうことかピンと来ないかも知れませんね。インストールしたXOOPSのファイルは1セットなんですが、設定ファイルを切り替えて別のデータベースを参照し、まったく別の環境(サイト)のXOOPSを動かそうとすることです。もちろんこれは異なる環境を同時並行に動かすという意味ではありませんので、インターネット上で公開する用途では全く意味のない話しなんです。が、PC上のローカル環境では並行して進めている複数サイトの開発を扱わなければいけないので、それぞれバラバラにファイルセットが点在していると大変です。XOOPSに加えた改造もバラバラになってしまいますし。

 で、どうすれば良いのか。そんなに難しい話しではなく、XOOPSのフレームワークを理解すれば何がデータベースに格納され、何がファイルに格納され、それらをどうやって切り替えれば良いのかが見えてきます。
 まずほとんどすべてのデータがデータベースに格納されるのですが、インストール時にパーミッションを変更するディレクトリやファイルがファイルとして保持されるデータです(基本的には…。OSSなのでモジュール作者の考え方次第ですが…)。具体的には次のものです。

uploadsディレクトリ
cacheディレクトリ
templates_cディレクトリ
mainfile.phpファイル

 環境を切り替えるとき、uploadsディレクトリとmainfile.phpファイルは退避し、cacheディレクトリとtemplates_cディレクトリは空っぽにします。cacheディレクトリにはadminmenu.phpという管理者画面のメニューブロックがキャッシュされている場合がありますので、admin.phpにアクセスして再生成する必要があります。(「インストール後初めて管理画面を開きます。」と言われて、「はぁ〜?」と思いましたが…)
 あと別の環境を新たにインストールするときは、mainfile.phpをインストール状態に戻しておく必要があります。もちろんinstallディレクトリを削除していたらそれも用意しておく必要があります。

 とまぁ〜簡単に言っていますが、XOOPSのソースコードをしっかり理解しないうちにできる芸当ではないかも知れませんね。なんだかまたしても「そんなの誰もしねぇーよ!」というネタを書いてしまったようです…。どちらかと言うと、施した改造がどの環境でも使える汎用的なものかどうかを確かめる手段として使っているかも知れません。

2007年04月25日

なにぃー、メルアドに連続するピリオド!?

 「なにぃー、メルアドに連続するピリオド!?」。皆さん、ケータイのメルアドって凄く凝ってますよね。意味不明な意味ある文字を並べていたり、顔文字になっていたりと。そんな中、先日 ピリオドが10個くらい並んだメルアドに出会いました。一瞬、何かの文字化けかと思ってドキッとしたのですが、ケータイってこんなメルアドもOKなんですね。そう言えばケータイ向けポータルサイトだとかメール転送サービスなどをアンタスで自社開発していた頃に、ケータイ各社のメルアドに使える文字種がRFCに準拠していない、という話しがあったような…。改めて調べてみると、どうもDoCoMoとauがRFCに準拠していないようですね。
 具体的にどこが準拠していないかと言うと、「ピリオドが連続できる」「ピリオドが@の前に付けれる」です。そう、だからピリオドを10個も並べることができるんですね。これって仕様を選定したSEの大きなミスのような気がしますが、それはさておき――

 「XOOPSのメールチェック処理がRFCに準拠してるじゃあ〜りませんか!!」

  このままではRFCに準拠していないユーザーさんはメールアドレスの登録が永遠にできません。これは何とかしないと!

 修正する場所は include/functions.php のcheckEmail関数です。ここの正規表現を手直しするのですが、正規表現はちと苦手…。こんな感じでしょうか、、、

"/^[_a-z0-9-]+([\._a-z0-9-]+)*@[a-z0-9-]+([\.][a-z0-9-]+)+$/i"

 あ、そういえばJavaScriptのメルアド検査にdojoも使っているので、そちらも修正しないと。笑いごとではありませんが、笑って対処しておきましょう、、、。

2007年02月18日

XOOPSがプロパティ値を記憶する仕組み

 XOOPSでは共通の仕掛けで記憶されたプロパティ値が、$xoopsConfigという連想配列に格納されます。たとえば$xoopsConfig['language']はシステム管理で設定した「使用言語」の値が返されます。このプロパティ値はconfigテーブルに保存されていて、conf_modidフィールドでモジュール毎に区分けされ、さらにconf_catidフィールドで細分化されているのですが、それだけではなく、conf_formtypeフィールドやconf_valuetypeフィールドなどの値を使って、標準的な入出力フォームなら汎用的に実現できる仕掛けが組み込まれています。このような仕掛けにどこまで準拠しているかはモジュール作者によって違ってきますが、カーネル部分でもあるシステム管理の[一般設定]ならとても簡単にプロパティ値の入出力フィールドが追加できることを発見しました。

 具体的には、conf_modidが0のものがシステムモジュールで、conf_catidが1だと[一般設定]-[一般設定]のページで設定できるプロパティ値となります。なので例えば conf_formtypeを「textbox」、conf_valuetypeを「text」としてconfigテーブルにレコードを追加すると、いとも簡単にプロパティ値の入出力フィールドが現れます。で、この入出力フィールド、どこで実装されているのかというと /modules/system/admin/preferences/main.php です。なかなか深いところですね。しかもこのコード、システム管理の[一般設定]で表示することだけを意識しているようです。非常に惜しいところ…。これと似たようなコードを他のモジュールでも見かけたことがありますが、共通のコードになっていると嬉しかったのに〜〜。

2007年01月30日

XoopsObjectクラスはすべての始まり

 XOOPSの仕組みを紐解いていくと、程なくkernelディレクトリがXOOPSの中核であることに気付きます。“カーネル”という名前からしてもこれが中核であることは明確なんですが、classディレクトリにあるxoopsuser.phpは /kernel/user.php を丸ごとラップしていたりして、なんだかXOOPSの歴史的背景を感じてしまいます。(って歴史的背景は知りませんが…。)

 このkernelディレクトリの中のobject.php、XoopsObjectクラスは、他の様々なクラスの抽象クラスとなっています。Javaで言うところのObjectクラスですね。しかしJavaのObjectクラスと違って、いくぶん多くの仕事を任されています。それは簡単にいうとオブジェクトのプロパティ値を汎用的に保持する仕組みなんですが、これはXOOPSの重要なフレームワークと言えそうです。
 たとえばユーザー情報を保持するXoopsUserクラスを例に挙げてみると、コンストラクタでXoopsObjectクラスのinitVar関数をコールして、プロパティ値の領域確保と初期設定、いくつかの味付けを行なっています。uidやname、emailなど。それぞれXOBJ_DTYPE_INTやXOBJ_DTYPE_TXTBOXなどのタイプや必須条件、最大文字数なども指定されています。この味付けが実に奥深くて、プロパティ値から値を取り出すときに、表示用か編集用か、あるいはプレビュー用かを指定できます。またデータストアに備えて、値が適切な形であるかをチェックする機能が備わっています。

 ん〜、ただソースコードをちょっと見ただけではこのお仕事の内容が見えてこないのが痛いところです。しかもフレームワークの根底部分なので、ヘタに触ると危険。ここは更なる研究が必要ですね…。

2006年12月22日

MovableTypeのコールバックをフックする

 MovableTypeにはプラグインを追加して機能を拡張する仕組みが備わっています。プラグインでは独自のMovableTypeタグを追加したり、グローバル・フィルターという共通のタグ属性を追加したりできます。この方法はMovableTypeのこちらのマニュアルに紹介されています。またこの他に、MovableTypeが提供する様々なコールバックをフックして、独自の処理を組み込むことができます。実はこのフック処理、マニュアル片手に教科書どおりのプログラムを用意すれば、意外と簡単にプラグインを作成できました。

 これ⇒ サンプルのプラグインです。(HookUpload.pl

 このプラグインのソースコードを紐解くにはマニュアルが必要ですが、ここにPerl APIのマニュアルがあります。ここでの一番のポイントはMT->add_callback関数の第一引数でしょう。コールバック・ハンドラの登録のために、コールバック・メソッドの名前を指定するということなんですが、どんな名前を与えるのか?
 その答えはリファレンス・マニュアルの中にありました。マニュアルを良く見てみると、「コールバック」と書かれた章があります。この第一引数には、この章にあるコールバック・メソッド名を与えれば良いようです。例えばMT::WeblogPublisherの「BuildFile」を与えると、ファイルが構築された直後に呼び出されるコールバックをフックできます。サンプルでは「CMSUploadImage」を与えていますが、これはMT::App::CMSの画像のアップロード毎に呼び出されるコールバックということになります。

 このコールバックのフックの仕方さえ分れば、ここから色んな拡張が考えられますね。

2006年12月02日

MovableTypeでMobile対応、ケータイで蔵之介

 アンタスの社員ブログはMovableTypeを利用していますが、MovableTypeの標準機能を利用してケータイ版のブログを作ってみました。

 これ⇒ 技の蔵之介のケータイ版: http://antas.jp/blog/wazakura/m/

 MovableTypeではテンプレート毎に出力ファイル名を指定できるので、例えばブログのトップページをPC用(/index.html)とケータイ用(/m/index.html)の2種類 出力することができます。ケータイ用のテンプレートにはiモードのC-HTMLタグに準拠するように記述しておけば、キャリア側で端末に対応した形式に変換してくれるので、auでもVodafoneでも大丈夫です。

 ここでちょっと注意が必要なのは、リンク先を示すURLです。ここではケータイ用を/mディレクトリ配下としたのですが、何も気にせずにリンクを生成するとPC用のページを示してしまいます。そのため、正しくケータイ用のページを示すようにリンク先URLを生成する必要があります。
 例えば技の蔵之介では、ケータイ用のエントリー・アーカイブを「m/%y/%m/%b.html」というURLに出力しているのですが、これらのページを示すURLは「<$MTEntryDate format="%Y/%m"$>/<$MTEntryBasename$>.html」のような形で生成する必要があります。

 ただこのように1つのエントリーでPC/ケータイの両方に対応させたとしても、本文中の外部サイトへのリンク先がPC向けのページしかない場合はどうするのか?といったことを考えると、完璧なケータイ版を作るにはやっぱりPC/ケータイの別々に本文も用意した方が良いのでしょうね。とは言え、そこはケータイユーザーもオケージョナリーな使い方として閲覧しているか、ヘビーユーザーはPCサイトビューアーへ移行するなどして、問題は自然に解決していくのでしょー。

2006年11月07日

XOOPSデバッグ出力をlog4phpへ

 XOOPSとlog4phpのネタをもうひとつ。XOOPSのデバッグモードって、見過ごしがちなミスをちくちくとツッコンでくれるので便利ですよね。アンタスのホームページやXOOPSベースのシステム構築では、随所にカスタマイズを加えているので たいへん助かります。でも画面にechoされて、うっとうしい気持ちも少々…。で折角、log4phpを導入したのですから、このデバッグ出力をlog4phpに出力するようにしてみました。

 どうやらデバッグ文字をechoしている箇所はXoopsErrorHandlerクラスのXoopsErrorHandler_Shutdown関数のようなので、

//#mod
    global $logger;
    if (isset($logger)) {
        $buf = $error_handler->renderErrors();
        if (!empty($buf)) {
            $logger->debug($buf);
        }
    } else {
        echo $error_handler->renderErrors();
    }
//#from
// echo $error_handler->renderErrors();
//#end
のようにしてみました。$loggerは以前のエントリーでご紹介したグローバル変数です。

あ、そういえばPHPバージョンとの組み合せによるものだと思いますが、PHP4.4で教科書どおりに使おうとすると、

Notice: Only variable references should be returned by reference
という警告が発生しました。PHPは詳しくないのですが、PHP 4.4.0とPHP 5.1.0以降では、参照戻しの関数で式の結果やnew演算子の結果をそのまま返そうとした場合にE_NOTICEエラーが発生するらしいので、怒られた箇所を地道に書き換えました。たとえばLoggerAppenderクラスのsingleton関数で return null; としていますが、nullを一旦、変数に格納し、その変数をreturnするようにです。なんておバカな努力でしょう。まぁ差し当たり怒られるのは数箇所だったので、今はそんなこんなでXOOPSと組み合せています。

INSERT、実行させてくれ!

 ときとしてOSSの集合知と世間に揉まれたソフトウェアの実力に思い知らされることがあります。そしてそれは、なんてことのないプログラミングでINSERTを実行させてくれず、半日悩まされることがあります。皆さん、XOOPSのデータベース関連のクラスには、XoopsMySQLDatabaseSafeクラスとXoopsMySQLDatabaseProxyクラスがあることをご存知でしょうか?XoopsMySQLDatabaseProxyクラスはSELECTクエリだけを受け付けるリードオンリー型の接続を行なうクラスです。実はXoopsDatabaseFactoryクラスではそのどちらでインスタンスを生成するのか制御されています。そして更に遡ると、POSTリクエスト以外のとき、あるいはHTTP_REFERERのチェックにパスしなかった場合、include/common.phpの中でリードオンリー型のXoopsMySQLDatabaseProxyクラスでインスタンス生成するように実装されています。そう、この条件に合致した場合、INSERTは実行させてくれません。

 現在、アンタスで開発を進めているシステムのひとコマにて、POSTリクエストの発行までは良かったのですが、ちょいとテストするためにローカルのHTMLファイルをC:\〜という感じで開いていました。このことがHTTP_REFERERチェックに引っ掛かり、自サイトからのリクエストじゃないと判断されてしまったようです。ん〜、確かに以前、XOOPSのHTTP_REFERERチェックには要注意!という助言をもらっていたのですが、そのときは実際にコードを確認していなかったので、このことを言っていたとは気付きませんでした。

2006年10月17日

明朝体、使わせてくれ!

 ソフトウェアエンジニアである私は、何故かアンタスのホームページなどのデザインやHTMLコーディングも担当しているのですが、プロのデザインに見よう見まねで勉強して、最近では明朝体を使う知恵をつけました。そう、serifです。どこにどう使えば効果的なのかイマイチわかっていませんが、ブロックタイトルに使ってみようと、style.cssのh2タグに

font-family: "MS P明朝", "細明朝体", "ヒラギノ明朝 Pro W3"
を指定してみました。

が、どう見てもゴシック体。そう、sans-serifです。以前からず〜と気になっていたのですが、Dreameweaverのタグインスペクタに用意されている"MS P明朝", "細明朝体", "ヒラギノ明朝 Pro W3"なのに、今まで明朝体をお見かけしたことがありません。

どうしても明朝体にしたい、と色々調べてみると、どうやらIEのバグがあるとのこと。でも微妙に論点がズレている感じ。このバグは欧文フォントと和文フォントを混在して指定すると、和文フォントが採用されない場合があるというもの。誰も和文フォントだけの指定で明朝体が表示されないとは言っていません。実際のところ、IEでちゃんと明朝体が表示されているサイトもあるし…。なんだか日本語が認識されていないような…。

う、style.cssの文字コード?
現在、style.cssはシフトJISです。XOOPSはEUCで出力しています。ひょっとして…。

そう、style.cssをEUCにしていなかったので、"MS P明朝"が正しく認識できていないだけでした。もうひとつ言えば、"MS Pゴシック", Osaka, "ヒラギノ角ゴ Pro W3"と自慢げに指定していましたが、IEは「なんのこっちゃ〜(-。-)y-゜゜゜」と思ってたんですね。悔しぃ〜〜。

2006年09月07日

XOOPSでMySQL4.1は使えないのか?

 XOOPSが対応するデータベースは、世間一般的にMySQL4.0.xxとなっています。そのため、多くのレンタルサーバーでは少し古いバージョンのMySQLが組み込まれていたりしますが、せめてMySQL4.1は使いたいものです。で、具体的にどこがダメなのか調べてみたところ、どうやら文字化けに関する問題があるようです。でも今まで何の不都合もなく使えていたのに、いったいどんな文字化けが発生するのだろう?と思いながら、あるときダンプ操作をしてみると、どう頑張っても文字がバケバケしてしまいました。XOOPS上で操作するだけでは気付かなかったのですが、データベース内では正しい文字コードで格納されていなかったようです。
 どうしたものかと試行錯誤した結果、問題解決の糸口は文字コードの自動変換機能による弊害(文字化け)に集約されていました。4.0→4.1では文字コードの自動変換機能が加わったことで、サーバーとクライアントのそれぞれにキャラクターセットを設定することになったようですが、クライアント側のキャラクターセット定義がXOOPSのコードに含まれていないことで、エンコードの整合性が保たれていなかったようです。そこでテーブルのキャラクターセットをutf8に変更すると共に、MySQLへのコネクションを生成するXoopsMySQLDatabaseクラスのconnectメソッドで

$this->queryF("SET NAMES ujis");

のような1行を足して問題を回避しました。XOOPSのインストール前にこの対策を施しておけば楽だったのですが、既にインストールを終えているとlatin1でレコードが挿入されているので、正しいエンコードに整えるのがちょっと面倒でした。ということでアンタスが手掛けるXOOPSベースのシステムでは、MySQL4.1を採用しています。

2006年07月12日

デフォルトThemeを観察する

 XOOPSには標準でdefaultというThemeがあります。このThemeをよく見てみると、cssファイルにはstyle.cssとstyleMAC.css、styleNN.cssの3種類が含まれているのですが、theme.htmlからは<{$xoops_themecss}>のように動的にcssファイルをリンクしているだけです。ここに何か仕様が隠れていそうですね。
 そこでこの$xoops_themecssを追跡してみたのですが、どうやら \include\functions.phpのxoops_getcss関数でブラウザのユーザーエージェントから使用するcssファイルを切り替える仕組みがあるようです。今まで何も意識せずにstyle.cssを使うように設計していたのですが、HTTP_USER_AGENTに"mac"の文字が含まれていたらstyleMAC.css、"/MSIE ([0-9]\.[0-9]{1,2})/i"の正規表現にマッチしたらstyle.css、それ以外はstyleNN.cssになるようです。しかしこれらの条件で決まったcssファイルが実際に存在しなければ、style.cssを使うようです。

2006年06月27日

【Tips】XOOPSで日付書式を変える

 XOOPSのTipsです。XOOPSは各言語に応じて/language/japaneseといったファイルが用意されていますが、ふと日本語の日付書式を見ると“2006-6-22”のようになっているじゃないですか!やはりニッポン人、ここは“年月日”としたいところです。そこでアンタスのホームページでは年月日表記に変えてみました。

で、その方法ですが、
/language/japanese/global.php というファイルに

define("_DATESTRING","Y-n-j G:i:s");
define("_MEDIUMDATESTRING","Y-n-j G:i");
define("_SHORTDATESTRING","Y-n-j");
という定義があります。

 これらは日付を整形するときに使われる書式ですが、ここを

define("_DATESTRING","Y年n月j日 G:i:s");
define("_MEDIUMDATESTRING","Y年n月j日 G:i");
define("_SHORTDATESTRING","Y年n月j日");
のように書き換えると、“2006年6月22日”という表記に変わります。
ちなみに書式のYとかnとかjは、PHPの日付書式と同じものですので、この部分の表記もアレンジできます。

 ただしこれはXOOPSの標準的な日付整形を行なっている機能で有効な方法です。もしそれぞれのモジュールが独自の方法で日付を書式化している場合は、それぞれの実装に応じた変更が必要になりますのでご注意を・・・。

2006年06月22日

テーマをデザインする

 XOOPSサイトの見え方はほとんどテーマで決まります。テーマにはページの骨格となるHTMLファイルがあり、それが参照するCSSファイルがあります。またテーマで使われる画像ファイルも存在するでしょう。これらは一見、普通のHTMLです。ただひとつだけ違うことは、Smarty和訳サイト)というテンプレートエンジンのタグが含まれていることです。

smarth Smartyはそれほど難しく考える必要はありません。XOOPSは動的なWEBページですので、静的なHTMLと違ってページ内に埋めこまれるタグや文字は動的に変化します。Smartyはその動的に変化する文字をテーマ内のHTMLに差し込んだり、条件判断や繰り返しなどで部分的な文字列を表示させたりするものです。
 Smartyのマニュアルを片手に、まずはデフォルトのテンプレートやサードパーティーが提供するテンプレートを眺めて研究してみましょう。そうすることで、動的に文字を差し込む個所は<{$xoops_sitename}>のようなタグになっていたり、<{foreach item=block from=$xoops_lblocks}>〜<{/foreach}>のようなタグでブロックの繰り返しが行われていることが分かると思います。実はこれだけ分かれば、もう自由自在にレイアウトを変更できることでしょう。そのほとんどがHTMLレベルの話です。例えば画面から消してしまったユーザーメニューの変わりに、凝ったデザインのメニューをテーマに用意することもできますね。

2006年05月23日

メインメニューとユーザーメニューを消す!!

 XOOPSではメインメニューユーザーメニューがなければ話しが始まりません。そこには各モジュールへのリンクがあり、ログイン画面へのリンクがあります。特にログイン画面へのリンクがなくなってしまうと、システム管理画面を開くことができなくなってしまいます。しかしアンタスのホームページでは、ポータルサイトのように一般の会員がログインすることはありませんし、各モジュールへのリンクもXOOPSの決められた内容には従いたくありません。やはりメインメニューとユーザーメニューは消したいところです。

 メインメニューとユーザーメニューを消す上で重要なことは、それらは単なるリンクであるということです。つまりメニューがなくなっても、そのメニューが指し示すURLさえ与えてやれば、必要な画面が表示されるということです。例えば各モジュールへは"<XOOPSのルート>/modules/<モジュール名>/〜.php"のようなURLになっているでしょうし、ログイン画面は"<XOOPSのルート>/user.php"で表示できます。メニューを消す前にあらかじめリンク先URLをメモしておくのも良いでしょう。

ブロックアクセス権限

 まずはメニューを消し、代わりに必要なリンクだけをテーマやカスタムのブロックなどで加えていきます。

2006年05月22日

それもXOOPSです。

XOOPS Cube XOOPSは現在、メジャーなオープンソースCMSツール(コンテンツ・マネージメント・ツール)のひとつです。PHPとMySQLさえあればとても簡単にインストールでき、手軽にポータルサイトが構築できます。実はアンタスのホームページもこのXOOPSで構築しています。また社内のイントラ・サイトでもグループウェア的に利用しています。

 しかしこのXOOPS、情報の交換に主眼を置いた、XOOPS cube公式サイトのようなホームページであれば入門書に沿ってカスタマイズすれば事足りるのですが、デザイン性を重視するホームページや企業がサービスとして提供するポータルサイトを作ろうとしたとき、なかなか教科書どおりには実現できないものです。しかもそのXOOPSっぽさを無くす方法は、デザイン+応用力が必要なので、なかなかこれと言った情報がないものです。

 そこでWAZAKURAでは、少しでもそのヒントになればと思い、アンタスのホームページを題材にその"コツ"を紐解いていこうと思います。