トップページ

2009年10月02日

OpenSocialの入門記事を『システム開発ジャーナル』vol. 11に執筆しました

毎日コミュニケーションズ発行のシステム開発ジャーナル vol. 11の特集記事『OpenSocial Web & モバイル開発入門』を執筆しました。全7章、56ページに及ぶ特集で、mixiアプリを中心にOpenSocialアプリを精力的に開発されている空飛ぶの赤星琢哉さんと、mixiに先駆けて日本で初めてモバイル版のOpenSocialプラットフォームをスタートさせたgumiの酒徳千尋さんとの共同執筆です。これからOpenSocial/mixiアプリの開発を始めてみようかというかたにお読みいただければ幸いです。

システム開発ジャーナル Vol.11
システム開発ジャーナル編集部
毎日コミュニケーションズ
売り上げランキング: 52343

Category: ウェブ制作
Posted 2009年10月02日 17:05

2009年06月24日

iPhoneとViewPortとXHTML Mobile DOCTYPEと.mobiドメイン

iPhoneのMobile Safariは、通常ウェブページを横幅980ピクセルとして描画する。iPhoneの実際の画面幅は320ピクセルだから、おおよそ1/3に縮小して表示しているわけだ。
いまどきのウェブページは概ね800ピクセル以上の横幅を想定したデザインになっているので、殆どの場合はこれで快適なのだけど、一方それ以下の横幅のページを表示すると、結構残念な感じになる。特にケータイサイトは、通常240ピクセル幅を想定したデザインで、それが980ピクセル幅の領域に描画されるわけだから、かなり間の抜けた表示になる。当然文字も小さく読みづらいので、それではとピンチインで表示を拡大しても、ケータイサイトでは一般的にブロックの横幅が指定されず、こうしたブロックは980ピクセルの横幅いっぱいに描画されるので、今度は文章を追うのに横にスクロールする必要が生じる。

サイト側でMobile Safariの描画領域を指定する手段として、よく知られているのはViewPortの記述だ。例えば以下のようなMETA要素をHTMLに記述しておくと、Mobile Safariはデバイスの画面幅(device-width)で、つまりiPhoneなら320ピクセルでページを描画してくれる。

<meta
 name="viewport"
 content="width=device-width"/>

このcontent属性の値を「width=240」にすれば240ピクセル幅で描画され、カンマ区切りで「user-scalable=no」を追加すれば、ピンチイン/アウトなどのユーザ操作による表示の拡大縮小もできなくなる。

さてそれで、ここからが本題。

開発中のとあるサイトにiPhoneでアクセスさせてもらったところ、すべてのページがもれなく320ピクセル幅で描画されていた。このサイトのターゲットは携帯電話だけというわけではないそうなのだけど、今のところは携帯電話での利用が主なので、デザインもケータイサイト風だ。それでも320ピクセル幅で描画されるということは、iPhoneでのアクセスも想定してViewPort指定を書いてるのだろうと思ったら、開発者に聞いてみたところ、そんなものは書いてないと言う。確かにHTMLソースを眺めてみても、そんなものは書かれていない。それなのに320ピクセル幅で表示される。

これは不思議だなと思ってたのだけど、たまたま別件でググってたら回答を見つけた。

以下は、Apple Developer Connection - Web Apps Dev Center - Designing Contentの、“Web標準および実証済みのデザインプラクティスを使用する”より。

注:iPhone版Safariでは、プロキシにおいても、クライアント上でも、コードの変換は一切行いません。ページは設計されたとおりにレンダリングされます。また、WML(ワイヤレスマークアップ言語)もレンダリングされません。XHTML mobileプロファイルの文書タイプおよび.mobiドメインのサイトはサポートされています。

重要なのは最後の一文。これだけではなんのことなのか、なにが「サポートされて」いるのかよくわからないのだけど、これを目にして、例のサイトが.mobiドメインでホストされていることを思い出した。

また、jQueryの開発者として知られるJohn Resigさんの、iPhone Tech Talkと題された2007年のブログ記事には、Boston iPhone Tech Talkで聞いた話として、以下が記されている。こっちはもうちょっとわかりやすい。

Pages that are marked up with XHTML Mobile or are on a .mobi domain are handled specially (they're shown unmodified - assuming that the developer has already optimized the page for a mobile device appropriately).

あいにく.mobiドメインは持ち合わせてないので、「XHTML mobileプロファイルの文書タイプ」のほうを試してみることにした。XHTML Mobile ProfileのDOCTYPE宣言を記述したHTMLにiPhoneでアクセスしてみる。結果は案の定320ピクセル幅で描画され、一方それ以外のDOCTYPEのものは980ピクセル幅で描画された。
おそらく.mobiドメインのページも、これと同様の扱いを受けるのだろう。例のサイトのDOCTYPEはXHTML Transitionalだったので、このサイトの描画が、DOCTYPEではなくドメインによって決定されているのは間違いない。また、どうやらDOCTYPEよりもドメインのほうが優先されるらしい。

上のものとは別のアップルのページ、Safari Web Content Guide: Creating Compatible Web Contentには、上と同じ記述に続けて、XHTML Mobile ProfileのDOCTYPE宣言として以下が掲載されている。

<!DOCTYPE html PUBLIC
  "-//WAPFORUM//DTD XHTML Mobile 1.1//EN"
  "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd">

XHTML Mobile ProfileのDOCTYPE宣言は何度か変更になっているのだけど、上の通りでなければいけないかというと、少なくともDTDのURIは、この動作には無関係のようで、これの有無で表示が変わることはなかった。
GoogleモバイルにはViewPortが書かれているものと書かれていないものがあり、それでもMobile Safariで一律320ピクセル幅で描画されるのは、すべてのページでDOCTYPE宣言がXHTML Mobile Profileで統一されているからなのだということにも合点がいったのだけど、そのGoogleモバイルのDOCTYPE宣言では、DTDのURIはwapforum.orgドメインのものになっている。もちろんこれでも、Mobile Safariの動作には影響はない。

ちなみにドコモのi-XHTMLのDOCTYPE宣言はダメだった(笑)
そもそも諸外国では、モバイルサイトのDOCTYPE宣言は(WMLでなければ)XHTML Mobile Profileが当たり前に選択される。一方この国では、XHTML Mobile ProfileのDOCTYPEを提示しているのはauだけで、ドコモもソフトバンクも独自のDOCTYPEを推奨している。しかもいずれも、実際はDOCTYPEなど関知していないので、どのようなDOCTYPEを出力しても、表示にはまったく影響がない。それでも日本のケータイサイトの多くは、クライアントに応じてDOCTYPEの出力を切り分けていて、iPhoneからのアクセスは、スタンダードのウェブブラウザと同等に扱われ、HTML/XHTMLのDOCTYPEが出力されている。

ということで、もしあなたがケータイサイトのオペレーションに関わっていて、そのサイトがiPhoneでアクセスされても問題ないものなら、以下のいずれかを採用することで、iPhoneでも本来のように(980ピクセル幅で描画されないように)表示させることができます。

逆に.mobiドメインのサイトで、iPhoneで320ピクセル幅以外で描画させたい場合はViewPortを記述する必要があります。例えばiPhoneやPCのウェブブラウザに対して、「ケータイでアクセスしてね」的なページを表示させる場合に、ViewPortがないと、.mobiドメインのサイトのページは、iPhoneでは320ピクセル幅で表示されてしまうので、それに収まるデザインならばいいけど、そうでなければこれは必須ですね。

Category: ウェブ制作
Posted 2009年06月24日 00:42

2009年05月20日

iモードブラウザ2.0でAcid2テスト

以下は、iモードブラウザ2.0対応の、iモードHTMLシミュレータIIバージョン 8.2が公開されたので、Acid2テストを表示してみた図。

acid2

CSSソースがダラダラ表示され、肝心のスマイリーはまったく描画されなかった従来よりは、一歩前進ではないかと、無理やり前向きに評価してる。

Acid3はさすがに略。

参考までに、以下はiPhone実機のMobile Safariで、同じAcid2テストを表示してみた図。

acid2-iphone

Category: ウェブ制作
Posted 2009年05月20日 00:00

2009年03月05日

AtomでのMobile Link Discovery

ふとシックスアパートのMobile Link Discoveryを眺めていて、そういえばAtomのところにある、x:media の名前空間については現在 Atom Working Group への提出を検討していますという話はどうなったんだろうと思った。

HTMLのものは新たな属性を提案しているわけではないので問題ない。しかしatom:linkにはmedia属性なんてないわけで、何らか新たな定義がない限り使えない。

で、ググってみると確かにドラフト仕様はあった。

Atom Syndication Format Link Extensions

4.1. The 'media' Attribute

The 'media' attribute MAY be used to identify the types of devices for which a resource referenced by an atom:link or atom:content (using the src attribute) has been targeted.

でも2006年1月のものが最後の版で、それも2006年7月に有効期限切れになってる。

案の定おんなじように思ってるひともいた。

Atom Linking Extensions

結局この話はなかったということでFAなのかなー?

Category: ウェブ制作
Posted 2009年03月05日 22:25

2009年02月27日

Gears余談

ラボブログ書いた。

なんで唐突にGearsなのかというと、ラボブではdelってるけどマジでコードレビューのときに、他になんにもネタがなかったから。
そういえば最初はActiveRecord.jsネタにしようかと思ったんだだけど、そうなるとGearsだけじゃなく、AirもHTML5も相手にしなきゃいけなくて、めんどくせーのでGearsにしたんだったけか。

寝惚けながら書いてたのでドキュメントちゃんと読んでなかったんだけど、WorkerPoolのやり取りは文字列オンリーじゃなくなってたのね。リリースした後でドキュメント読み返したらdeprecatedって書いてあって、慌てて直したさ。
しかしそうするとworkerPool.onmessegeの最初の2ヶのパラメータは無意味なわけで(なので、ドキュメントに掲載されてるサンプルも「function(a, b, message)」と、最初の2ヶはどうでもいい名前が振られてる、というかこのコード見てなんだこりゃ?と思って気付いたのでした)。もともとのパラメータいきなりobsoletedにするわけにいかないからしょうがないとは思うんだけど、おかげでここかなりキモいっす。

あとSQLiteは「id integer PRIMARY KEY」と書けばいわゆるauto incrementなカラムが出来るわけですが、「integer」じゃなくて「int」って書くと駄目なのねん。はい書きましたよ、ハマりましたよ。database.lastInsertRowIdはちゃんとID返すのに、なんでプライマリーのカラムがNULLやねん!?と(笑)

Category: ウェブ制作
Posted 2009年02月27日 20:57

2008年04月03日

Atom 1.0 リファレンス

RFC4287の原文と日本語翻訳+構造図で、インタラクティブに参照するAtom(Syndication Format)の仕様。

» Atom 1.0 リファレンス

Atom 1.0 リファレンス

以下は余談。

最初はRSS 0.9x/2.0とRSS 1.0とAtomとの簡単な比較表を作ろうと思ってたのでした(そして、RSS 1.0やAtomの仕様は、杜撰な鷹揚なRSS 0.9x/2.0のそれと比べて厳格なので、各フォーマットを共通のデータソースから生成しようとする場合には、データソースの準備は厳格な側に合わせてやらないとワヤになりまっせ、という講釈を垂れようとしていた)。

で、しかしRFC4287を眺めてたら、Relax NG(のコンパクト構文)スキーマによるストラクチャー表現を、ブロック図に置き換えて操作できるようにしたら面白いかもと思い立ち(この時点で比較表を作ろうという当初の目的は潰える)。しかし要素を並べただけではアレなので説明を加えるにしても、RFC原文のコピペだけでは不親切かなということで、ついでに日本語訳も用意してみた次第。

既存のRFC4287の日本語翻訳

» 「Atom 1.0 リファレンス」の続きを読む

Category: ウェブ制作
Posted 2008年04月03日 00:49

2008年04月02日

iMenuのGoogle検索がいきなりおかしなことになってる件

Googleモバイルで「プロフィール」や「プロフ」を検索すれば、1位は前略プロフだろうと思うのは素人。

http://www.google.co.jp/imode/search?ie=Shift_JIS&mrestrict=chtml&site=mobile&q=%83v%83%8D%83t%83B%81%5B%83%8B

確かに、PCで普通に検索してみれば、少なくとも本日ただ今現在の1位は前略プロフで、そのPCで、Googleモバイルで「プロフィール」を検索する上のアドレスを開けば、本日ただ今現在の結果は以下のような感じで、やはり前略プロフが1位。

  1. 前略プロフィール
    『前略プロフィール』は、誰でも手軽に携帯電話・パソコンの両方に対応した、自己 ...
    pr.cgiboy.com/
  2. FC2プロフ - あなた専用のプロフィールを作ってみよう!!
    あなた専用のプロフィールが簡単に作れちゃう!!プロフィールを作ってみよう!!
    pr.fc2.com/
  3. Amazon.co.jp: プロフィール: デューク・ピアソン,ジーン・テイラー ...
    Amazon.co.jp: プロフィール: デューク・ピアソン,ジーン・テイラー, ...
    www.amazon.co.jp/プロフィール-デューク・ピアソン/d...
  4. 佐野夏芽プロフィール
    タレントプロフィール ・ フォトダイアリー ・ タレント募集 ・ メールマガジン登録 ...
    www.metalbox.co.jp/work/sano/pcolum...
  5. みんなのプロフィール
    みんなのプロフィール 名前をクリックするとプロフィールを閲覧できます。 ...
    www.yukinosake.com/cgi-bin/profile/...

しかし、少なくとも本日ただ今現在、「PREF」という名称のcookieを削除してから上記のモバイル版のアドレスを開いてみると、以下のようにまったく違う結果が表示される。1位は関西のデリヘル。ちなみにこのcookieがない状態で100位(10ページ)まで検索しても、前略プロフは出てこない(以下にもあるような、前略を騙るサイトは出てくる)。

  1. 大阪・兵庫・京都・奈良・和歌山巨乳ロリ・ギャル系専門デリバリーヘルス ...
    プロフィール南大阪 ・ プロフィール京都 ・ プロフィール兵庫 ・ プロフィール奈良 ・ プロフィール和歌山 ...
    www.pro-file.jp/m/
  2. 携帯(ケータイ)無料プロフ作成フリーサイト「My・ぷろふぃーる」
    完全無料でマイプロフィール交換画面を作成できる携帯電話専用プロフ提供フリー ...
    vl-o-l.jp/
  3. プロフィール
    プロフィール. 名前:すぬーぴー. 種別:ビーグル犬の. ぬいぐるみ. 年齢:不明 ...
    penguinmaru.fc2web.com/i/profile.html
  4. 前略プロフィール by aimew
    プロフガイドは数あるプロフィールサイトを厳選してご紹介!もちろんプロフを通じて新しい ...
    aimew.jp/zennryaku/
  5. 前略プロフィール by aimew
    JC、JKに人気のあるプロフィールサイト♪. 前略出会い系 ...
    aimew.jp/zennryakud/
  6. 携帯無料プロフ作成 チェキ!プロフィール
    チェキ!プロフィールでは簡単☆無料でプロフィールサイトを作成できます!
    chpr.jp/
  7. プッチギャル
    女の子コメント:いちゃx2楽しい時間を過ごしましょうねぇ(*^^)v ...
    www.kobe-pucchigal.com/m/gal/k-view...
  8. 京都デリヘル/プッチギャル
    キャッチコピー:☆京都に渋谷系GAL誕生☆ドエロEカップに大興奮! ...
    www.kyoto-pucchigal.com/m/gal/k-vie...

さて、cookieの有無で検索結果が変わるということは、cookieを喰わないドコモの端末ではどうなるかというと、もちろん上と同じ、1位がデリヘルという結果になる。

で、ドコモは4月1日からiMenuのトップ画面にGoogleと連携した検索機能を追加し、Googleの検索エンジンにより、携帯電話向け一般サイト、PCサイトの検索結果も表示されるようになったのだけど、そのiMenuの検索フォームから「プロフィール」を検索してみた結果が以下。

  1. 携帯(ケータイ)無料プロフ作成フリーサイト「My・ぷろふぃーる」
    完全無料でマイプロフィール交換画面を作成できる携帯電話専用プロフ提供フリー ...
    vl-o-l.jp/
  2. プロフィール
    プロフィール. 名前:すぬーぴー. 種別:ビーグル犬の. ぬいぐるみ. 年齢:不明 ...
    penguinmaru.fc2web.com/i/profile.html
  3. 前略プロフィール by aimew
    JC、JKに人気のあるプロフィールサイト♪. 前略出会い系 ...
    aimew.jp/zennryakud/
  4. 京都デリヘル/プッチギャル
    キャッチコピー:☆京都に渋谷系GAL誕生☆ドエロEカップに大興奮! ...
    www.kyoto-pucchigal.com/m/gal/k-vie...

一瞥して明らかなように、これは上の、通常のGoogleモバイルでの結果のサブセット。1位のデリヘルが消えているのは、おそらくドコモなりのフィルターで、「有害」と判定されているサイトが除去されてるためではないかと思われ。

しかし京都のデリヘルは見事このフィルターをくぐり抜け4位に躍進!(4位だとiMenu検索の1ページ目に表示されるので、それ以下とは雲泥の差)なんという脅威のSEO!(違)

………とまあ、そんなこんなで。これはたまたま出くわした極端な例ですが、別にこの例に限らず、ドコモ端末でGoogleモバイルを利用すると、検索結果がなんだかおかしなことになってる模様です、というお話ですた。

Category: ウェブ制作
Posted 2008年04月02日 23:41

2007年06月01日

opm.blitzed.org is pointing at a blackholed nameserver

MovableTypeの管理画面にあるSixApartからの告知に、【重要】コメント投稿に時間がかかる現象についてと出ていて、なにかと思ったら、opm.blitzed.orgが停止したので、バンドルされているSpamLookupプラグインの、DNSBLサーバの設定がデフォルトのままだとヤバイですよ、というハナシで。

いや、ちょっと待てと。OPMが停止したのは一年も前なわけで。それを今頃になって告知かと。OPM statusによると、今年の5月にopm.blitzed.org is pointing at a blackholed nameserverということになったそうで、そのため告知にあるような事態が生じるようになって問題が顕在化したらしい。

で、なんでブラックホールリストのサーバがブラックホール行きになったかというと、in order to reduce query load on our serversだそうで。なんで未だにそんな状態かというと、多くのMTユーザが(もちろんMTだけじゃないだろうけど)OPMの停止を知らずに、デフォルトで設定されているサーバをそのまま使い続けていたであろうからで。なんでそんなことになってるかというと、誰かに言われない限り、普通はDNSBLサーバが停まってるなんてことには気付かないよな、と(ましてデフォルトで設定されてるものだし)。

多くのDNSBLサービスはボランティアな運営なわけで、いつなくなっても不思議ではなく。そもそもDNSBLは、ボットネットの拡大によって以前ほど効果的ではなくなっており、ORDB.orgのようにこれを理由に閉鎖してしまった例もあり。あるいはzen.spamhaus.orgのように、新たなサーバが用意され以前のもののリプレイスが推奨される場合もあり。斯様な状況でDNSBLを利用する場合は、利用するサーバの状況を定期的に確認して設定を見直す必要があるわけですが、それをすべてのユーザにやれというのも無茶なハナシで。しかしMTには折角管理画面に告知コーナーがあるのだから、早期に告知がされていればユーザもSixApartも、そしてBlitzed.orgも無用のトラブルを抱えずに済んだのになあ、と。

………と、OPMの死亡告知を死亡から半年後に出したヤツが、自分のことは棚にあげて自戒の念を込めて申し上げてみるテストでございました。合掌。

以下はMTのハナシではないけれど、DNSBLネタが少々。

Category: ウェブ制作
Posted 2007年06月01日 23:59

Firefox 2/IE7用、OpenSearch検索プラグイン(検索プロバイダ)作成ツール

検索バー

Firefox 2やInternet Explorer 7などの検索バーに検索サイトを追加するOpenSearch形式のプラグインを、極力簡単に作れるようにしてみました、というものです。要Cookie+JavaScript。実は随分前に作って、しかし腑に落ちないまま放置していたものを引っ張り出してきて、全面改装。

» OpenSearch検索プラグイン(検索プロバイダ)作成ツール

ものは試し。上のリンク先で、ページの右側の「ブックマークレット」欄にある、「検索プラグインの作成」というリンクを、マウスの右クリックとかでブックマーク(お気に入り)やツールバーに登録してみてくださいな。

で、例えばGoogleとかで、「TEST」を検索した結果のページでそのブックマークレットを選択してみてください。下図のような表示が出てきたら正解。以上の操作がメンドクセーひとはここをクリック(笑)。

OpenSearch検索プラグイン(検索プロバイダ)作成ツール

「検索プラグインを追加」ボタンをクリックすると、確認ダイアログが表示され、プラグインを追加できるわけですが、お気に召さない項目があれば適宜編集していただければと存じます。各項目の説明は、その入力欄をクリックすると説明が出てくる筈。編集後には「確認・更新」ボタンをクリックしてください。

「名前」は、ウェブブラウザはこれでプラグインを管理してるので、既に登録済みのプラグインと同じ名前は付けられません。

「アイコン」は、Firefox 2の検索バーに表示されるものです(IE7では利用されません)。アイコンはウェブサイトのFaviconを自動検出しますが、Faviconがないサイトや、自分好みのアイコンを使いたい場合は、画像をアップロードすることもできます。画像がJPEGやGIF、PNGなら、自動的に画像の中央部を切り出してアイコンサイズに縮小するので、あらかじめアイコンサイズの画像を用意しておく必要もありません。

なお、ここで検索プラグインを作成できるのは、GETメソッドの検索フォームのみです。つまり、検索結果のページのアドレスに、(検索キーワードである)「TEST」という文字が含まれないものは作成できません(POSTメソッドによる検索プラグインは、OpenSearchの拡張仕様のひとつとして用意されているParameter要素を使って作成できますが、IE7はこれに対応していないためPOSTメソッドのプラグインは利用できません)。

いまでは多くのウェブサイトがオフィシャルな検索プラグインを提供していますが、提供されてない(提供しそうにもない)サイトや、ありそうでなさそうなサイトや、あるいは提供されてるけど名前やアイコンが気に入らない類は、自分で(勝手に)作っちゃえばいんじゃないかと。以下は、現時点でオフィシャルが存在しないものをテキトーに見繕ってみた例。

» 「Firefox 2/IE7用、OpenSearch検索プラグイン(検索プロバイダ)作成ツール」の続きを読む

Category: ウェブ制作
Posted 2007年06月01日 19:22

2007年05月26日

HTMLをXML化してDOMやXPathで操作するWebスクレイピング用PHPクラス

SimpleXMLHTMLParser or TidyHTTP_RequestCache_Liteの組み合わせで、リモートサイトから取得したHTMLソースを整形して、SimpleXMLオブジェクトに変換するライブラリでございます。サーバサイドはもとよりクライアントサイドのAjaxでも、DOMやXPathなどを用いたオブジェクト操作によるScrapingが可能になります。要SimpleXMLなのでPHP5専用(もっとも、SimpleXMLをDOM XMLに置き換えればPHP4でも同じようなことはできますが)。

ええっと手っ取り早く、以下にアクセスしてフォームに適当なURLを入力してみてください。

下図のようにURLがダラダラとリストされれば正解。

test_ajax.htmlの実行例

ここでリストされるURLは、ご覧いただければおわかりの通り、入力したURLのウェブページ内にあるA要素のHREF属性値なわけですが、ポイントはこれを、responseXMLからDOMで取得していること。つまりXMLHttpRequestのリクエスト先は、well-formedなXMLを返してるということでございます。あと、HREF属性値はすべてフルパスに変換されてたりもします。

そのXMLHttpRequestのリクエスト先であるPHPアプリのソースは以下の通り。

<?php

if (!isset($_GET['url']) or empty($_GET['url'])) {
    header("$_SERVER[SERVER_PROTOCOL] 400 Bad Request");
    header('Content-Type: text/plain;charset=UTF-8');
    exit('The URL is not specified.');
} else {
    require_once 'HTMLScraping.class.php';
    $s = new HTMLScraping;
    try {
        $xml = $s->getXmlObject($_GET['url']);
    } catch (Exception $e) {
        header("$_SERVER[SERVER_PROTOCOL] 400 Bad Request");
        header('Content-Type: text/plain;charset=UTF-8');
        exit($e->getMessage());
    }
    $s->convertPath($xml, array('a' => 'href'));
    header('Content-Type: application/xml;charset=UTF-8');
    exit($xml->asXML());
}

?>

HTMLScraping->getXmlObject()は、第1パラメータのURLで取得したHTMLソースから生成したSimpleXMLオブジェクトを返します(エラーの際には例外を投げますんで、上の例のようにtry~catchしてやってください)。

ちなみに、キャッシュ処理を行う場合、まずは以下のように、コンストラクタの第1パラメータにキャッシュファイルを保存するディレクトリを指定しておきます(このディレクトリはもちろん、PHPアプリに対するread/writeパーミッションが必要です)。

$s = new HTMLScraping('/tmp/');

で、getXmlObject()の第2パラメータに秒数を指定すると、URLのレスポンスが指定した秒数キャッシュされます。

$xml = $s->getXmlObject($_GET['url'], 3600);

その他のオプションパラメータやその他のメソッドの説明、及び配布アーカイブのダウンロードなどは、説明ページへどーぞ。

応用例:HTMLをScrapingしてRSSフィードを生成する

さてこれだけでは面白くないので、これの応用例としてHTMLからRSSフィードを生成するということをやってみました。と言ってもHTMLの内容は多様で一律に処理できるわけはないので、共通処理をまとめたabstractなクラスを用意し、この継承クラスでオーバーライドするメソッド内で、HTMLScraping->getXmlObject()で取得したSimpleXMLオブジェクトから必要なデータを抽出していただこうという寸法でございます。

注意:これはあくまで応用例として用意したもので、実用に供されることを意図したものではありません。

配布アーカイブ中のexamplesディレクトリにあるtest_feed.phpはこのサンプルアプリケーションで、同ディレクトリ内にあるtest_feed.htmlからリストアイテム要素を取り出し、フィードを構築して出力します(このアプリケーションはキャッシュ機能を使用しますので、実際に自分の環境で実行する場合は、コンストラクタのパラメータで指定しているキャッシュファイルの保存先ディレクトリ名を、実際に利用可能なものに変更してください)。

HTMLToFeed.class.phpは、test_feed.php内で継承しているabstractクラスHTMLToFeedを定義しています。HTMLToFeed->getFeed()は、DOMで構築したフィードを出力しますが、キャッシュ処理が有効な場合は、フィードの出力をキャッシュし、出力にLast-Modified/Etagヘッダを含めて、If-Modified-Since/If-None-Matchによる条件付きリクエストに応答します。

test_feed.phpでは、アクセス先のURLが単一(しかもコンテンツが変更されない)であるため、出力のみをキャッシュしていますが、複数のURLにアクセスしてその内容をマージするような場合、URLごとに、その更新頻度に応じてキャッシュの有効期間を設定し、それに加えて出力もキャッシュすることで、アプリケーションのパフォーマンスを向上させることができるかもしれません。

DisclaimrBETA

まあこれは、こんな感じでこんなことができますよというサンプルであって、これを広く使ってもらおうなんていう気は毛頭なく。仕様も自分の好みでやらかしてるので、あんまし汎用的ではないかもしれず。そもそもライブラリの組み合わせからして、別段この組み合わせに限ったわけでも、もちろんありません。

特に、Tidyが利用できればこんなことはもっとお手軽に(リソースの消費も少なく高速に)できちゃうわけで。しかし、HTMLParserの趣旨にも書いたように、現在の一般的なレンタルサーバのPHP環境ではこれは殆ど利用できない筈なので、そういう場合には利用価値があるやもしれませんが(このライブラリでは、Tidyが利用可能ならそちらを、そうでなければ(自動的に)その代替にHTMLParserを利用するようになってたりはします)、そんな感じのツクリなので、気に入らないところがあれば、しょせん既存のライブラリの組み合わせなので、わざわざオーバーライドするよりは自分好みの仕様で作り直しちゃうことをお勧め申し上げる次第でございます。

Category: ウェブ制作
Posted 2007年05月26日 00:25

2007年03月25日

ながらTube

Flash Media Playerで遊ぼう企画の第3弾くらい。再生するプレイリストを自動生成しようというネタ。Flashビデオが大量に転がってるところといえばあそこなわけで。そのAPIでプレイリストを作ればいんじゃん?という安直な企画デスネ。

で、出来たのが以下。

» ながらTube

上のリンク先のページの右側にプレイヤーが表示されると思いますが、そのままではいまいち面白くなさそうなビデオがリストされてるかと思います。
で、その左側にある入力フォームでキーワード検索ができるので、ここに好みのキーワード、例えば「浦和レッズ」とか入れてみてください。配色も変えられるので、「Background」を赤に変更してみましょう。「Foreground」と「Rollover」は白と黒の組み合わせがいい感じではないかと。最後に「Update」ボタンをクリックすると、プレイリストの内容とプレイヤーの見栄えが変わるという寸法です。

ながらTubeバッジ

これまで見てきた、ページの右側に出てくるヤツは、ウェブやブログに貼り付けることを想定した「バッジ」版なのですが、一方で下図のように、これをサブウィンドウで表示して、デスクトップで鑑賞する用途を想定した「バー」版もあります。
ながらTubeの、バーの説明にある「Nagara Tube Bar (Bookmarklet)」というリンクをクリックすると、バッジ版と同じ内容が、下図のようにサブウィンドウに表示されます(タブブラウザではポップアップウィンドウの設定を変更する必要があるかもしれません。IE7ではタブブラウズの設定中の、ポップアップの発生時の動作を確認してください)。このリンクはブックマークレットにもなるので、ブックマークやツールバーにこのリンクを登録しておくと、以降はそれを選択するだけで同じ設定のバーを表示できます。

ながらTubeバー

さて。

とか書いときながら実際にブログとかに貼られまくられちゃったりするとそれなりの負荷になるわけで。いつものようにソースを晒してるので、ご利用は自鯖でどーぞ。ただし、自作の部分はいつも通りフリーソフトウェアですが、Flash Media Playerはそうではなく、特に商用利用の場合はライセンス料金が必要になる点ご注意ください。

Category: ウェブ制作
Posted 2007年03月25日 22:58

2007年03月09日

“Reason for Living” - Roddy Frame (a.k.a. Aztec Camera)

ここにはFlashオブジェクトが表示されます。ここにFlashオブジェクトではなくこのテキストが表示されたままの場合は、以下の原因が考えられます。

  • RSSリーダーとかで表示している。
  • ウェブブラウザがDOM対応のものではないか、JavaScriptが無効になっている。
  • Flashプレイヤーがインストールされていない。
  • おいらの手違い。

お送りしている曲は、アズテックカメラことロディ・フレームの1998年のスリーコードチューン、「Reason for Living」です。

で、これは字幕作成のテスト。

歌詞が字幕で表示されるのって好きなんですよ。歌われる言葉は音楽の一部なので、ともすれば聞き流してしまいがちなのですが、書かれた言葉を目にすることでそれをしっかりと捉えられる気がするのです。殊に僕らの言語が採用している表意文字では文字そのものが具体的なイメージを喚起するので、なおさらそう思えるのかもしれません。

A little something about the tune

Technical things

Category: ウェブ制作
Posted 2007年03月09日 20:10

2007年03月06日

野菜小屋の地図をGoogle Maps APIで作ってみるテスト

野菜小屋

野菜小屋

京王線飛田給駅より徒歩30秒

営業時間や取扱商品などの詳細はblog.livedoor.jp/tokyo_la12でご確認ください。

飛田給駅の利用者なら、表通りでも派手に宣伝しているので大丈夫でしょうが、そうでなければ知らないひともいるかもしれないので、野菜小屋の地図を用意してみますた。

という口実で、GoogleマップのDOM APIで遊んでみたテスト。以下はトーキョーとは無関係。

» 「野菜小屋の地図をGoogle Maps APIで作ってみるテスト」の続きを読む

Category: FC東京, ウェブ制作
Posted 2007年03月06日 22:49

2007年01月12日

携帯JavaアプリのFlickrビューアがお蔵入りになった件

Pocket Flickr - a Flickr viewer for Mobile Java Pocket Flickr - a Flickr viewer for Mobile Java Pocket Flickr - a Flickr viewer for Mobile Java

信頼すべき情報筋によれば、“ポケットflickr”というコードネームで昨年末にコソコソ製作されていた、携帯電話向けJava実行環境用の、Flickrのビューア・アプリケーションがお蔵入りになった模様。

Eclipse

製作者はお蔵入りの理由について、「飽きたから」と語っているという。参考までに、製作者の血液型はB型とのこと。

ポケットflickrは、Flickrの写真を、Interestingnessや、タグ、フリーテキストなどで検索して、携帯電話で閲覧するビューア。表示した写真はJavaの保存領域に保存しておくことができ、待ち受けアプリなどとしても楽しめるなどの、よくありがちな機能が予定されていた。
なお、携帯電話のカメラで撮影した写真をアップロードする機能は、「メールでやればいいじゃん」ということで、そもそも検討されていない。

ポケットflickrは、クライアント用のJavaアプリケーションと、FlickrのAPIとの通信や、携帯電話向けの写真の加工、及びこれらのキャッシュ処理などを行うウェブサーバ用のアプリケーションで構成され、その最初のバージョンは、NTTドコモのFOMAシリーズ用iアプリとして2006年内にリリースされる予定であった。

なお、製作が再開される見込みについては、「ないない」とのこと。

このエントリーの画像には、idfontで公開されている「id-カナ007」フォントを使用しています。このフォントの著作権は、井上デザイン・井上優さんが所有しています。

Category: ウェブ制作
Posted 2007年01月12日 23:04

2007年01月11日

heywatch.comどうでしょう

Hey! Watchは、各種の動画変換(再エンコード)を行う、マルセイユ発のウェブサービスでございます。
動画変換のウェブサービスなんてえものは既に多々あるわけですが、TechClunchの記事に、メインの機能はREST APIでディベロッパー向けに公開し、サービスに直接に構築できるよう配慮している(ちなみにヘンな日本語は原文のママ、とゆうかTechClunchの日本語はしばしばヘン)と書かれてたので触ってみますた。

Hey! Watchは、現在は本サービスに移行していますが、つい先日までは「invitation only beta」でした。以下のハナシは原則、その頃のものです。始まったばかりのサービスなので内容はどんどん変更されていく筈で、現状は違ってる可能性がたぶんにあることにご留意ください。

基本的な使い方はいたってシンプル。

  1. 変換したいビデオを、ローカルからアップロードするか、URLで指定する。
    指定できるURLは:
    • ビデオファイルのURL。
    • ビデオファイルのURLが書かれたウェブページのURL(複数ある場合はあらためて選択する)。
    • YouTubeやGoogleビデオなど、対応している動画配信サービスのウェブページのURL。
  2. ビデオがいったんHey! Watchに転送されるので、完了するのを待つ(転送状況は随時確認できる)。
  3. 転送が完了したら、変換したいフォーマットを選んでエンコードする。
    ただし、Hey! Watch全体で、同時に行えるエンコード数には制限がある。これは「スロット」という単位で表現されており、「空きスロット」があれば直ちにエンコードが行われるけれど、そうでなければ待たされる(エンコードの状況も随時確認できる)。

アカウントには、無料の「Free」と有料の「Watcher」(なんでそういう名前なのかは不明)があり、Watcherアカウントは$4.99/月で、「まとめて払えばお得」なプランもあり。ちなみに支払い方法は、現時点ではPayPalのみ(イケてないところ、その1)。
ふたつのアカウントの違いが具体的に書かれたページはログインしないと見れないので、以下にサクっとまとめてみた。

制限Free(無料)Watcher($4.99/月)
1ヶ月間に可能なエンコード回数10回100回
エンコードフォーマットのカスタマイズNGOK
転送した(オリジナルの)ビデオの保存期間6時間12時間
エンコードしたビデオの保存期間12時間24時間
同時に可能な転送数13
同時に可能なエンコード数13
ビデオあたりの再生時間の制限10分25分
ビデオあたりのデータサイズの制限なしなし
転送量の制限なしなし

ちなみに、このページに限らず、ヘルプですらログインしないと見れません(イケてないところ、その2)。

APIどうでしょう

ウェブインタフェースは非常にクールで直感的だが、REST APIも同様に直感的なものだ。ただし、現在のAPIドキュメントは、必要最低限の内容しか用意されていないので、APIドキュメントの解読は直感的というわけにはいかない(笑)。そして、ご多分に漏れずこのドキュメントも、やはりログインしないと見れません。見たければユーザ登録するアルよ。

Hey! Watchのサービスはユーザ認証が前提なので、APIアクセスもユーザ認証が必須ですが、その認証方式は、To use our API, you must be authenticated via Basic Auth.ということで、ベーシック認証でございます。HTTPSでもないので、パケットでIDとパスワードが丸見えなんだな、これが(イケてないところ、その3)。

基本的な仕様はごく普通の(素直な)REST API。
POSTでリソースを作成し、GETで情報取得、PUTで変更、DELETEで削除。

例えば、YouTubeのFLVを変換するなら、/discoverにページのURLをPOSTしてFLVのURLを検出させる。

POST /discover.xml HTTP/1.0
Authorization: Basic hoge
Host: heywatch.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 58

url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DBPsfbV9t8Vw

POSTのレスポンスではまだ検出が完了しているわけではないので、同じURLを適宜GETして検出の完了を確認する。

GET /discover.xml HTTP/1.0
Authorization: Basic hoge
Host: heywatch.com

で、検出が完了したXMLレスポンスはこんなんで、RESULT要素の中身がFLVのURL。
どうでもいんだけど、CREATED-AT要素のタイムゾーンがお国柄を匂わせてたりします。

<?xml version="1.0" encoding="UTF-8"?>
<discovers>
  <discover>
    <id>12345678</id>
    <status>ok</status>
    <download>false</download>
    <result>
      http://www.youtube.com/get_video?video_id=BPsfbV9t8Vw&l=61&t=OEgsToPDskI5F9Jp4wgYUqAzjmkPJN7D
    </result>
    <url>
      http://www.youtube.com/watch?v=BPsfbV9t8Vw
    </url>
    <title>
      YouTube - YouTube Happy New Year
    </title>
    <created-at>
      Mon Jan 01 00:00:00 +0100 2007
    </created-at>
  </discover>
</discovers>

で、検出が完了したらそのURLを、今度は/downloadにPOSTして、Hey! WatchにFLVを転送開始。同様に適宜GETして転送の完了を待ち、完了したら今度は/jobに、そのビデオのIDとエンコードフォーマットのIDをPOSTしてエンコード開始…。

まあ、そんな感じ。

レスポンスの形式は、XMLの他にJSONとYAML。この指定は、APIのリクエストURLに対応する拡張子を付けて行います。例えば、エンコード済みのビデオの一覧を取得する場合、XMLなら「GET /encoded_video.xml」、JSONなら「GET /encoded_video.js」という感じ。
なお、リクエストによっては特殊なレスポンスが用意されていて、例えば「GET /encoded_video.rss」とすると、エンコード済みのビデオの一覧のRSSフィード(Podcastコンパチ)が出てきたり、「GET /encoded_video/video_id.jpg」とすると、エンコード済みのビデオのサムネイル画像が出てきたりします。

リクエスト結果は、まずはHTTPステータスコードで判断するわけですが、ドキュメントにあるのは、200 OK、201 Created、204 No Content、400 Bad Request、404 Not Found、406 Not Acceptable。
どうでもいんだけど204は、means that the resource has been updated or deleted successfullyと書かれていて、おそらくPUT/DELETEの成功を示すのだろうけど、ステータスコードの本来の意味からするとヘン。
一方406は、the format you asked is not availableと書かれていて、この「format」はおそらくエンコードフォーマットのことなのだと思うけど、だとしたら、ステータスコードの本来の意味の履き違え。

携帯どうでしょう

Hey! Watchのエンコードフォーマットには「Mobile 3GP」や「Mobile 3GPP2」、「Mobile MP4」といった選択肢があり、また、Watcherアカウントであればフォーマットのカスタマイズも可能で、例えば「Mobile 3GP」のビデオコーデックはH.263なのだけど、これをMPEG4に変更したりできる。

これらのフォーマットに変換したビデオは、日本の携帯電話でも再生できる場合もある。ただし、Hey! Watchはおそらく、LinuxプラットフォームでFFmpegを使ってエンコーディングを行っており、FFmpegでのエンコード時の問題がそのまま残される(例えばドコモ端末でストリーミング再生できないとかいう類)。

これについてHey! Watchの中のひととメールでやり取りしてみますた(ちなみにレスポンスはめちゃめちゃ迅速でした)。
指定のデータサイズでビデオを分割できるようにして欲しいなあという要望は、やんわりと、しかし即座に却下。3GP_Converter(aka 携帯動画変換君)のQT3GPPFlattenの例を挙げて、Atomフィールドの書き換えとかやって欲しいなあという要望を出してみたら、こっちはうやむやのうちに却下(笑)。
唯一、指定のデータサイズになったらエンコード糸冬了という機能だけ検討してくれることになりますた。って、それってFFmpegに-fsパラメータ渡すだけじゃん。

Category: ウェブ制作
Posted 2007年01月11日 19:10

2006年12月26日

第一次ハラ東京最後の日

天皇杯のハナシを書いてて思い出した、第一次ハラ東京最後の試合となった、松山での天皇杯レッズ戦で撮影していたビデオを公開しておこうかと。

試合後の挨拶

試合後の挨拶

ガスサポの行進

ガスサポの行進

というフリして、動画をYouTubeにアップしてみたテスト。
以下はテストのメモ。もはやハラ東京とは無関係。

» 「第一次ハラ東京最後の日」の続きを読む

Category: FC東京, その他のスタジアム, ウェブ制作, 愛媛のお勉強
Posted 2006年12月26日 18:43

2006年12月15日

Galicia - Sí, es única

ここにはFlashオブジェクトが表示されます。ここにFlashオブジェクトではなくこのテキストが表示されたままの場合は、以下の原因が考えられます。

  • RSSリーダーとかで表示している。
  • ウェブブラウザがDOM対応のものではないか、JavaScriptが無効になっている。
  • Flashプレイヤーがインストールされていない。
  • おいらの手違い。

久しぶりにルアル・ナ・ルブレ Luar na Lubre のウェブサイトが更新され、なにかと思いきや、YouTubeにアップされてる自分たちのビデオへのリンク集というネタで。TVGで放映されたスタジオライブとか、旧作のビデオクリップとか、日本のルブレオタ(推定3人程度)にとっては垂涎の映像が拝めるわけですが、これらはもちろん“オフィシャルに”アップロードされたものなわけはなく。うちらの国なら、アーティスト本人より先にJASRACあたりが、「削除と謝罪と賠償とユーザーの氏名・住所の登録制を要求するニダ」と騒ぎ立てるんだろうなと思ったり。

さて、上のFlashな動画はTurgalicia(ガリシア観光局)が今年の夏に制作したテレビCM集です。
「Tu Gitana」が最初のふたつのもののBGMに採用されているため、ルアル・ナ・ルブレのウェブサイトでも紹介されていますが、いかんせん本家の動画(左のメニューね)を日本から眺めようとすると、ダウンロードにドえらい時間がかかる上に、一部HTMLがクズなのでまともに見れやしない。てなことで、ガリシアへのニッポン人観光客誘致の一助になればという願いをこめて…。

というフリをしてFlashビデオをあれこれいじってみたテスト。
以下はテストのメモ。もはやガリシアとは無関係。

» 「Galicia - Sí, es única」の続きを読む

Category: ウェブ制作, ガリシアのお勉強
Posted 2006年12月15日 21:54

2006年11月22日

ぜろちゃんねる(0ch BBS Script)掲示板のスパム対策

1ヶ月ほど前から、うちのぜろちゃんねる掲示板に英文スパムが来襲するようになり、当初はDNSブラックリスト(DNSBL/RBL)で対処してたのですが、プロのスパム屋は新しいプロキシを次々と用意してくるわけで、ブラックリストがすべてを網羅できるわけはなく。それでも数が少ないうちはコマメに消してたのだけど、日増しにその数が増えて、やってらんねえ状態になったので、こんなふうにしてみますた、というメモ。

やってることは、2ちゃんねる BBQなどの任意のDNSBLサービスに登録されてるホストからの投稿を弾くのと、日本語文字(Shift_JISの2バイト文字)が本文に含まれない投稿を弾くこと(いわゆるひとつのBanAscii)。後者はURLだけのカキコとかも弾いてしまうわけですが、まあしょうがない。

ぜろちゃんねるスクリプトの改造は正直かなりマンドクセー('A`)わけですが、これなら改造が1箇所で済むし簡単な処理なのだけど、結構効果的なのではなかろうか、と。

追記@2007/01/30

# 0ch BBS Scriptの2005/11/13、2006/02/27、2007/01/24版で確認

# test/module/vara.plファイル内の
# IsRegulation(規制チェック)サブルーチン(2007/01/24版なら296行目あたり以降)内の
# 適当なところ(例えば「# 規制ユーザ・NGワードチェック」とある行の前)に
# 以下の「...」に囲まれている箇所を追加

# エラー番号は既存のものを流用なのでエラーメッセージも既存のもののままです
# それではワケワカランと思われる場合は、test/info/errmsg.cgiに新しい番号とメッセージを追加し
# 以下の「return」の後に続く番号をそれと取り替えるとモアベター

sub IsRegulation
{

...

  # 本文にShift_JISの2バイト文字が含まれていなければ
  # 600エラー(NGワード)

  if ($this->{'FORM'}->Get('MESSAGE') !~ /[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]/) {
    return 600;
  }

  # 本文に<a~>または[url=や[url]が含まれていれば
  # 600エラー(NGワード)

  if ($this->{'FORM'}->Get('MESSAGE') =~ /(<a\b[^>]*?>|\[url(?:\s?=|\]))/i) {
    return 600;
  }

  # メール欄に@が含まれていれば
  # 600エラー(NGワード)

  if ($this->{'FORM'}->Contain('mail','@')) {
    return 600;
  }

  # IPアドレスが以下で指定するDNSBLのいずれかに登録されてれば
  # 997エラー(PROXY規制)
  # ブラックリスト鯖はお好みで

  my @dnsbls = (
    'niku.2ch.net',
    'bsb.spamlookup.net',
    'bbx.2ch.net'
  );

  $ENV{'REMOTE_ADDR'} =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
  foreach my $dnsbl_host (@dnsbls) {
    $dnsbl_host = "$4.$3.$2.$1.$dnsbl_host";
    if (gethostbyname($dnsbl_host)) {
      return 997;
    }
  }

...

}

で、昨日これを仕込んで以降24時間のうちに、以下のようなホストがスパムの投稿にやってきたわけですが、幸いすべて弾けた模様。エラーが103となってるものは「本文長すぎ」で、これは規制チェックより前に実施されるので、これに引っ掛かるヤツもいるのだけど、これで既に結構な数が弾けている。で、600エラーが本文に日本語文字が含まれなかったもの。ここまでですべて弾けてしまい、結局DNSBLのチェックにまではどいつも至ってなかったり。

来襲時刻エラーホスト名#1#2#3#4#5
11/21 20:29103c-71-230-86-217.hsd1.pa.comcast.net     US
11/22 19:13600bzq-84-110-225-57.red.bezeqint.net     IL
11/22 19:13600bzq-84-110-236-82.red.bezeqint.net     IL
11/22 19:12600bzq-84-110-231-119.red.bezeqint.net     IL
11/22 19:12600bzq-84-110-233-25.red.bezeqint.net     IL
11/22 16:4810382.137.247.132yes    SY
11/22 15:00103www.farmington.k12.mi.usyes    US
11/22 13:2210384-123-102-217.onocable.ono.com     ES
11/22 12:11600200.29.137.217yes   yesCL
11/22 12:10600218.236.45.155yesyesyes  KR
11/22 12:05600S01060040ca37ccf6.cn.shawcable.netyesyes   CA
11/22 12:05600avquarantine.sec.kq.noyesyes   NO
11/22 11:23103proxy4-jan.integrity.comyes    US
11/22 10:1710389-149-205-145.internetserviceteam.com yes   DE
11/22 09:51600218.236.111.150yesyesyesyes KR
11/22 09:3710382.137.247.131yes    SY
11/22 07:5010394.190.189.72.cfl.res.rr.com     US
11/22 06:21600ool-44c0fe41.dyn.optonline.net     US
11/22 06:02103adsl-75-52-193-66.dsl.chcgil.sbcglobal.netyes    US
11/22 04:11600bzq-84-110-226-237.red.bezeqint.net     IL
11/22 02:27103ulbcenter-04-b07.it-datacntr.louisville.edu     US
11/22 01:08103riy01che02.ae.net.sayesyesyes  SA
11/22 00:3810364.8.149.34     US
11/21 23:56600bzq-84-110-251-251.red.bezeqint.net     IL
11/21 23:56600bzq-84-110-252-72.red.bezeqint.net yes   IL
11/21 23:55600bzq-84-110-241-44.red.bezeqint.net     IL
11/21 23:31600220.119.158.14yesyesyes  KR
11/21 23:3060086.35.202.101yes yes  RO
11/21 23:29600211.207.215.84yes yes  KR
11/21 23:25600210.113.30.208yesyesyesyesyesKR
11/21 22:5310363-109-248-28.reverse.newskies.netyes yesyes US
11/21 21:1510389-149-205-145.internetserviceteam.com yes   DE

上表の「#1~5」の欄は、各ホストについて以下の各DNSBLサービスでの登録の有無です。

  1. 2ちゃんねる BBQ - niku.2ch.net
  2. SpamLookup - bsb.spamlookup.net
  3. The Spamhouse Project - sbl-xbl.spamhaus.org
  4. SpamCop.net - bl.spamcop.net
  5. RBL.JP - all.rbl.jp

ご覧の通り、どのブラックリストにも登録されていないホストが結構あり、プロのスパム屋に狙われたら、やっぱしDNSBLでの規制だけでは不十分なんだよね、ということですな。

なお、2ちゃんねる BBQはDSBLでの登録状況も併せて応答するので、上表ではDSBLは端折ってます(なので、このふたつを併用するのは無意味です)。また、ちなみにどのホストも、2ちゃんねる BBX(bbx.2ch.net)には登録されていなかったので、こちらも上表では端折ってます。

参考になったり興味深く拝見したページ

» 「ぜろちゃんねる(0ch BBS Script)掲示板のスパム対策」の続きを読む

Category: ウェブ制作
Posted 2006年11月22日 23:38

2006年10月20日

Googleカレンダーを携帯で利用するPHPスクリプト

これは自作のGData API用クラスライブラリのデモとして制作した、携帯電話向けにGoogleカレンダーの表示と編集を行うウェブアプリケーションです。
しかしそもそも、携帯電話の画面にHTMLだけで、カレンダー/スケジューラのまともなインタフェースを作るのは結構無理難題なわけで。いちいち通信が必要なウェブアプリじゃあ、操作性も決してよろしくなく。携帯電話でGoogleカレンダーを利用する理想形は、やっぱ、Googleカレンダーとデータを同期するJavaアプリとかだと思うのですよ。実際iアプリなどには優れたカレンダー/スケジューラが既に多くあり、これらがこういう機能を備えれば、こんなウェブアプリはそりゃもう用無しだ罠。

予定リストの表示 カレンダー形式の表示 予定の詳細 予定の編集

PC/PDAで、このスクリプトのオンラインデモを確認できます。
このデモでは、アカウントの認証をこのアプリの本来の方式ではなく、AuthSubという方式で行います。この認証方式は、iモードやEZwebなどの携帯電話ブラウザからは利用できません。またGoogle Apps for Your Domainのアカウントも利用できません(当然ですが、このアプリの本来の方式では、いずれも利用できます)。

アーカイブのダウンロード

» gcal.zip 0.9.5 (eternally beta) issued 2007-06-06

機能制限

以下は現時点でGoogle側に不具合があるための制限です。追記参照

動作要件とか

設置手順

このアプリ自体の認証は、携帯電話の端末ID(製造番号とかサブスクライバIDとかシリアル番号とか)とパスコード(暗証番号)で行います。(端末IDが送信される状態で)ログインフォームに暗証番号を入力するだけという、ケータイフレンドリーな認証ですね。
そういうわけで、最初に設定ファイル(Config.inc.php)に、端末IDとパスコード、そしてGoogleアカウントのメールアドレスとパスワードを登録しておく必要があります。

  1. アーカイブ内の各ファイルをサーバの任意のディレクトリにアップロードし、「data」ディレクトリのパーミッションを707など、書き込み可能なものに変更します。
  2. 携帯ブラウザで_check_auth.phpにアクセスし、パスコードを入力して表示される内容をメールなどでPCに送ります。この内容を、Config.inc.phpファイルの「$auth_db」とある箇所に登録してください。「SERIAL」と表示される内容を$auth_dbの「serial」欄に、「PASS」と表示される内容を$auth_dbの「password」欄に、それぞれ登録します。
  3. 引き続き$auth_dbの、「google_username」欄にGoogleアカウントのユーザ名(@記号以降のドメイン名までを含むメールアドレス)を、「google_password」欄にそのパスワードを登録し、Config.inc.phpファイルをサーバにアップロードします。
  4. PCや携帯のブラウザでgcal.phpにアクセスして、期待通りに動作するか確認してみてください。この時点ではまだ、認証はパスコードのみで、端末IDでの認証は行っていないので、PCのブラウザでもアクセスできる筈です。
  5. 最後に、Config.inc.phpファイルの冒頭にある「define('GCAL_USE_DEVICE_ID_FOR_AUTHENTICATION', true);」とある行の、先頭のコメント記号(ふたつのスラッシュ記号)を削除し、これをサーバにアップロードしてください。これで、認証時に端末IDも照合されるようになり、端末IDを登録した携帯電話以外からはアクセスできなくなります。

gcal.phpのファイル名は任意のものに変更できます。設定などは不要です。
HTML表示を変更するにはTemplate.htmlを編集してください。各種の設定はConfig.inc.phpで行います。

ありがちなトラブル

スクリプトにアクセスするとHTTP 500 Internal Server Errorになる。
アーカイブ中の.htaccessファイルをサーバにアップロードしている場合は、この. htaccessの記載内容による設定変更が許可されていないことが原因かもしれません。.htaccessファイル中の「php_flag」で始まる行を削除して、再度試してみてください。ただこの場合、サーバのPHPの設定次第では、このスクリプトは期待通りには動作しないかもしれません。
日時が日本時間じゃない?
PHP4ではスクリプトが明示的にタイムゾーンを設定することができないため(できたっけ?)、日時はスクリプトが動作しているサーバのタイムゾーンに沿ったものとして表示されます。例えば海外のレンタルサーバなどでPHP4の場合は、日時が現地のタイムゾーンで表示されるかもしれません(適切なタイムゾーンが設定されていないサーバも同様です)。逆に、Googleカレンダーのタイムゾーンが海外に設定されていても、国内のサーバでは、PHP4なら日本時間で表示されることでしょう。
PHP5では、設定ファイルで、定数GCAL_TIMEZONEの値に指定したタイムゾーンのIDに沿ったものになります。このIDは、例えば「Asia/Tokyo」や「America/Los_Angeles」など、タイムゾーンのリストにあるものです。

ライセンスとか

このプログラムの本体であるgcal.phpファイルはGNU GPL v2+でライセンスされますが、このプログラムは、そそくさと制作を済ませるために既存のオープンソースソフトウェアをあれこれ流用しており、かつ簡単に設置できるように、アーカイブにはこれらのファイルも含まれてるかもしれません。こうしたソフトウェアのライセンスは、そのファイルに記載のものとなり、gcal.phpとは別にライセンスされる点ご注意ください。

» 「Googleカレンダーを携帯で利用するPHPスクリプト」の続きを読む

Category: ウェブ制作
Posted 2006年10月20日 00:00

2006年10月04日

Google Calendar APIの基礎

当初はGoogle自身がPHP用のライブラリを用意する予定だと表明していましたが、結局10月の終わりになって、Zend Google Data Client Libraryが登場しました。てなことで、PHP5をご利用の場合、以下のクラスライブラリは無用の長物と化しましたので、そこはすっ飛ばして、カレンダーAPIの解説としてご利用ください(ZendのものはPHP5用なので、PHP4をご利用の場合には、以下のクラスライブラリにも利用価値はあるかもしれません)。
なお、Googleカレンダーの携帯向けウェブアプリは元々このクラスライブラリのデモとして作ったものなので、このまま放置の予定。


PHP 4/5 class library for Google Data APIs

これは、GData APIとの通信を処理する、PHP4/5用のシンプルなクラスライブラリです(フィードの解析や作成を行う機能は提供されません)。詳細はREADMEをご覧ください。

» ZIPアーカイブのダウンロード

アーカイブの内容
  • Google
    • Account.php - アカウント認証API用クラス
    • GData.php - GData APIの共通クラス
    • Calendar.php - カレンダーデータAPI用クラス
    • Blogger.php - BloggerデータAPI用クラス
  • test.php - テストアプリその1
  • gbase_demo_alt.php - テストアプリその2
  • XMLParseIntoStruct.php - XMLを配列に処理する汎用のSAXパーサ(おまけ)
  • README

テストアプリその1(test.php)は、以下で説明するふたつのアカウント認証API(ClientLoginとAuthSub)のそれぞれを使ってカレンダーフィードを取得する、シンプルなものです。
テストアプリその2(gbase_demo_alt.php)はGoogle Baseで料理レシピの投稿と編集を行うものです。これは、Google自身による、Google BaseデータAPIのPHP版デモを、このクラスライブラリを使って書き直したもので、これを動作させるにはAPIキーを取得して、このスクリプトの冒頭に登場する定数「GOOGLE_BASE_DEVELOPER_KEY」の値にそれを設定してください。


目次

GoogleカレンダーデータAPIへのアクセスは、公開予定の取得、及び「magicCookie」と呼ばれるURLを利用した非公開予定の取得については認証は不要ですが、予定の追加、変更、削除には認証を要します。
ここでは最初にアカウント認証について、次いでカレンダーデータAPIについてまとめています。

Google Account Authentication

  1. アカウント認証の概要
  2. ClientLogin
  3. AuthSub

Google Calendar Data API

  1. カレンダーデータの取得
  2. イベントの追加
  3. イベントの変更と削除

アカウント認証の概要

認証を要するGoogleの各サービスAPIへのリクエストを行うアプリケーションは、ユーザIDとパスワードそのものではなく、アカウント認証APIによって発行される、トークン(token)と呼ばれるその代替データを送信します。トークンはその有効範囲内で繰り返し利用可能なので、アプリケーションはアクセスの都度トークンを取得する必要はありません。

アカウント認証APIにはClientLoginAuthSubがあります。

AuthSubでは、ウェブアプリケーションは、ユーザをGoogleアカウントのウェブサイトに誘導して、アプリケーションに対するアクセスの許可を依頼します。このときのURLには、「next」パラメータに、AuthSubからのレスポンスを処理するURLを指定しておきます。
以下の画像は、ユーザに表示されるログインフォームとアクセス要求の確認フォームの例です。アクセス要求の確認フォームでユーザが「アクセスを許可」をクリックすると、「next」パラメータで指定したURLに対してリダイレクトが行われます。

Googleアカウント - お客様のアカウントにサードパーティのサービスがアクセスできるようにするには、ログインする必要があります。 Googleアカウント:アクセス要求 - www.abcd.comがGoogleカレンダー アカウントにアクセスを要求すると、代わりにGoogleアカウントにアクセスすることができます。[アカウント情報]から、いつでもアクセスを取り消すことができます。www.abcd.comがお客様のパスワードおよび個人情報を入手することはありません。
注意

なお、AuthSubのアクセスの確認フォームでは、アプリケーションがGoogleに登録されたものではない場合、以下のような警告文が表示されます。

このウェブサイトはGoogleに登録されていないため、承認リクエスト用の保護された接続を確立できません。
下記のリンク先を信頼できる場合にのみ、処理を続行してください。

登録済みのアプリケーションでは、この警告文は表示されません。また、登録済みのウェブアプリケーションはセキュアなトークンを利用可能ですが、これはここでは省略します。


ClientLogin

ClientLoginでは、https://www.google.com/accounts/ClientLoginに対して以下のようなリクエストを送信します。

POST /accounts/ClientLogin HTTP/1.1
Content-Type: application/x-www-form-urlencoded

Email=Email&Passwd=Passwd&service=service&source=source

ポストデータの内容は以下の通りです。

キー
Email ユーザID(ドメイン名を含むメールアドレス)
Passwd パスワード
service 対象サービスのID(Googleカレンダーの場合は「cl」)
source アプリケーションのID(任意の文字列で、「企業名-アプリケーション名-バージョン」形式が推奨されています)
logintoken CAPTCHAチャレンジのトークン(CAPTCHAチャレンジ以外では省略)
logincaptcha CAPTCHAチャレンジの回答(CAPTCHAチャレンジ以外では省略)

リクエストが成功した場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。このうち「Auth」キーの値がトークンです。他の値は現時点では使用されていません。

SID=DQAAAGgA...7Zg8CTN
LSID=DQAAAGsA...lk8BBbG
Auth=DQAAAGgA...dk3fA5N

なお、リクエストが不成功の場合、そのボディが、以下のような「キー=値」形式のテキストで、「Error」キーの値が「CaptchaRequired」である場合があります。これは、ClientLoginがロボットなどによる不正侵入の可能性を疑い、CAPTCHAチャレンジ(画像認証)を要求しているものです。

Error=CaptchaRequired
CaptchaToken=DQAAAGgA...dkI1LK9
CaptchaUrl=Captcha?ctoken=DQAAAGgA...dkI1LK9

この場合、アプリケーションは、「CaptchaToken」キーに示された値と、「CaptchaUrl」キーに示されたURLで表示されるCAPTCHAチャレンジ画像の回答を、それぞれ「logintoken」と「logincaptcha」の値としてポストデータに追加し、ClientLoginへのリクエストを再度行うことになります。

クラスライブラリを使ったサンプルプログラム

以下の例は、この文章の冒頭で紹介しているPHPクラスライブラリを利用して、ClientLoginでトークンを取得し、それを表示するものです。

<?php
$email = 'example@gmail.com';
$password = 'password';

require_once 'Google/Calendar.php';
$service = new Google_Calendar;

session_start();
if (!isset($_SESSION['tokens'])) {
  $_SESSION['tokens'] = array();
}
if (!isset($_SESSION['tokens']['calendar'])) {
    if (!$service->requestClientLogin($email, $password)) {
    exit("ClientLogin has failed.\n".$service->getResponseBody());
  }
  $_SESSION['tokens']['calendar'] = array(
    $service->token,
    $service->authType
  );
}
var_dump($_SESSION['tokens']);
?>

ここでは、取得したトークンはいったんPHPのセッションデータに保存しています。トークンは繰り返し利用可能なので、アプリケーションがサービスAPIに複数回のリクエストを行う予定なら、トークンをPHPのセッションデータに保存しておくことで、リクエストの都度トークンを取得せずに、保存してあるものを利用することができます。この場合、実際にAPIにリクエストを行う際には、トークンを取得したアカウント認証APIがClientLoginかAuthSubかによって送信内容が異なるので、トークンには、それを取得したアカウント認証APIの種類(このクラスではauthTypeプロパティ)も紐付けておきます。
また、トークンは各サービスAPIごとに異なるので、アプリケーションが複数のサービスを利用する場合は、上の例でハッシュのキーにサービス名を用いているように、それがどのサービス用のものかを識別できるようにしておきます(AuthSubでは、AuthSubTokenInfoによってトークンの対象サービスを確認することが可能です)。


AuthSub

Googleアカウント:アクセス要求 - www.abcd.comがGoogleカレンダー アカウントにアクセスを要求すると、代わりにGoogleアカウントにアクセスすることができます。[アカウント情報]から、いつでもアクセスを取り消すことができます。www.abcd.comがお客様のパスワードおよび個人情報を入手することはありません。

AuthSubではトークンは、Googleアカウントのウェブサイトで表示されるアクセス要求の確認フォームで、ユーザが「アクセスを許可」をクリックすることで発行されます。
ユーザはまず、https://www.google.com/accounts/AuthSubRequestに、以下のパラメータをクエリー文字列に指定したURLにアクセスします(ウェブアプリケーションはユーザにこのURLを示して、アクセスの許可を依頼します)。

キー
next アクセスが許可された場合に行われるリダイレクト先のURL(AuthSubのレスポンスを処理するウェブアプリケーションのURL)
scope 対象サービスのURL(Googleカレンダーの場合は「http://www.google.com/calendar/feeds/」)
session 使い捨てトークンをセッショントークンと交換するか否か

アクセス要求の確認フォームで、ユーザが「アクセスを許可」をクリックすると、AuthSubは「next」パラメータで指定されたURLに、「token」パラメータを付加してリダイレクトします。
この「token」パラメータの値は使い捨てトークン(one-time|single use token)です。これは一回限り有効で、繰り返し利用することはできませんが、上表にある「session」パラメータの値が「1」の場合、この使い捨てトークンは、繰り返し利用可能なセッショントークン(multi-use session token)と交換することができます。

使い捨てトークンをセッショントークンと交換するには、https://www.google.com/accounts/AuthSubSessionTokenに対して以下のようなリクエストを送信します。Authorizationヘッダで指定するtokenは使い捨てトークンの値です。

GET /accounts/AuthSubSessionToken HTTP/1.1
Authorization: AuthSub token="token"

リクエストが成功した場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。このうち「Token」キーの値がセッショントークンです。他の値については、現時点では使用されていません。

Token=DQAA...7DCTN
Expiration=20061004T123456Z

なお、Googleに登録済みのウェブアプリケーションはセキュアなトークンを利用可能ですが、これはここでは省略します。

クラスライブラリを使ったサンプルプログラム

ユーザが、以下の例で示されるリンクをクリックして表示されるアクセス要求の確認フォームで、「アクセスの許可」をクリックすると、http://www.abcd.com/gcal/auth.php?token=tokenというURLにリダイレクトが行われます。このURLの「token」パラメータの値は、カレンダーデータAPIを対象とした、セッショントークンと交換可能な使い捨てトークンです。

<p>以下のリンクをクリックしてGoogleアカウントのウェブサイトに移動し
お客様のGoogleカレンダーにABCD.comがアクセスすることを許可してください。<br />
ABCD.comがお客様のパスワードおよび個人情報を入手することはありません。</p>

<p><a href="<?php
require_once 'Google/Calendar.php';
echo Google_Calendar::getAuthSubRequestUrl('http://www.abcd.com/gcal/auth.php')
?>">Googleアカウント アクセス要求</a></p>

そして以下の例では、使い捨てトークン(「token」パラメータの値)をセッショントークンと交換しています。なお、取得したトークンはClientLoginでの例と同様に、PHPのセッションデータに保存しています。

<?php
require_once 'Google/Calendar.php';
$service = new Google_Calendar;

session_start();
if (isset($_GET['token']) and strlen($_GET['token']) > 0) {
  if (!$service->requestAuthSubSessionToken($_GET['token'])) {
    exit("AuthSubSessionToken has failed.\n".$service->getResponseBody());
  }
  if (!isset($_SESSION['tokens'])) {
    $_SESSION['tokens'] = array();
  }
  $_SESSION['tokens']['calendar'] = array(
    $service->token,
    $service->authType
  );
  var_dump($_SESSION['tokens']);
}
?>

トークンの確認と廃棄

AuthSubの有効なトークンの発行数は、1ユーザ/1アプリケーションあたり10ヶまでに制限されています。そのため、取得済みの有効なトークンを廃棄(revoke)する必要が生じる場合があります。

https://www.google.com/accounts/AuthSubTokenInfoに対して以下のようなリクエストを送信することで、そのトークンが有効かどうかを確認できます。

GET /accounts/AuthSubTokenInfo HTTP/1.1
Authorization: AuthSub token="token"

指定したトークンが有効な場合のレスポンスはHTTP 200 OKで、そのボディは、以下のような「キー=値」形式のテキストです。

Target=www.abcd.com
Scope=http://www.google.com/calendar/feeds/
Secure=false

有効なトークンを廃棄するには、https://www.google.com/accounts/AuthSubRevokeTokenに対して以下のようなリクエストを送信します。

GET /accounts/AuthSubRevokeToken HTTP/1.1
Authorization: AuthSub token="token"

リクエストが成功した場合のレスポンスはHTTP 200 OKです。

なお、ユーザはGoogleアカウントウェブサイトの「アカウント情報」ページで、現在有効なAuthSubトークンの確認と廃棄が行えます。また、AuthSubのアクセス要求時に、既に制限数を超えるトークンが発行されている場合は、その旨のメッセージが表示されます。
以下の画像は、制限数を超えるトークンが発行済みの場合のメッセージと、トークンの確認と廃棄の画面です。確認と廃棄の画面で「アクセスを取り消す」をクリックしたトークンは廃棄され、無効になります。

Googleアカウント:アクセス要求 - Sorry, you have too many oustanding 3rd party sessions. Please revoke the access you've given to another 3rd party in order to continue. Googleアカウント:認証済みのウェブサイト - お客様のGoogleアカウントでは次のサービスにアクセスできます。

クラスライブラリを使ったサンプルプログラム

以下の例では、まずトークンが有効かどうかの確認を行い、有効な場合はそのトークンを廃棄しています。

<?php
$token = 'GD32CMCL25aZ-v____8B';

require_once 'Google/Calendar.php';
$service = new Google_Account;

if (!$service->requestAuthSubTokenInfo($token)) {
  echo("Token $token is not valid.");
} else {
  if (!$service->requestAuthSubRevokeToken($token)) {
    exit("AuthSubRevokeToken has failed.\n".$service->getResponseBody());
  }
  echo("Token $token has been revoked and is no longer valid.");
}
?>

カレンダーデータの取得

GoogleカレンダーデータAPIとアプリケーションは、Atom 1.0(またはRSS 2.0)に準じた、GDataと呼ばれるフィードデータをHTTP通信でやり取りします。

Googleカレンダーのフィードは、http://www.google.com/calendar/feeds/User_ID/Visibility/Projection[/Entry_ID|?Query_String]という形式のURLにアクセスすることで取得しますが、イベントの追加、変更、削除を行うアプリケーションでは一般的に、http://www.google.com/calendar/feeds/default/private/fullに対して以下のようなリクエストを送信して、読み書きのいずれにも利用可能な、非公開予定を含むフィードを取得します。

GET /calendar/feeds/default/private/full[/Entry_ID|?Query_String] HTTP/1.1
Authorization: [GoogleLogin auth=ClientLogin_token|AuthSub token="AuthSub_token"]

URLに以下の検索パラメータをクエリー文字列に指定することで、条件付きでフィードを取得できます。
なお、日時は、Atom 1.0が採用しているRFC3339形式で指定します。

キー
q 文字列の検索式(Googleのウェブ検索などと同様、「"」、「|」、「-」などのオペレータが使用可能です)
max-results 最大取得件数(省略時:25件)
start-index 取得開始エントリーの索引番号(省略時:1)
orderby エントリーの並び順(省略時:更新日時順|starttime:開始日時順)
start-min 最も古いイベントの開始日時(省略時:1970-01-01)
start-max 最も新しいイベントの終了日時(省略時:2031-01-01)
updated-min 最も古いエントリーの更新日時
updated-max 最も新しいエントリーの更新日時
author エントリーのauthor/name要素またはauthor/email要素(完全一致)
alt フィード種別(省略時:Atom 1.0|rss:RSS 2.0)

これらの検索パラメータのうち、「start-min」、「start-max」、「orderby」はカレンダーデータAPI特有のもので、それ以外はGData共通のものです。なお、カレンダーデータAPIは、GData共通の検索パラメータのうち、「category」はサポートしていません。

クラスライブラリを使ったサンプルプログラム

以下の例では、ClientLoginでトークンを取得した後、現在以降に開始予定のイベントエントリーのうち「横河」または「佐川」という文字列を含むものを、イベントの開始日時順に最大10件、という条件でフィードを取得しています。

<?php
$email = 'example@gmail.com';
$password = 'password';

require_once 'Google/Calendar.php';
$service = new Google_Calendar;

if (!$service->requestClientLogin($email, $password)) {
  exit("ClientLogin has failed.\n".$service->getResponseBody());
}
$queries = array(
  'q' => '横河|佐川',
  'max-results' => 10,
  'orderby' => 'starttime',
  'start-min' => date('Y-m-d\TH:i:s+09:00', time())
);
if (!$service->requestFeed($queries)) {
  exit("Requesting a feed has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>

イベントの追加

イベントを追加するには、http://www.google.com/calendar/feeds/default/private/fullに対して以下のようなリクエストを送信します。

POST /calendar/feeds/default/private/full HTTP/1.1
Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"]
Content-Type: application/atom+xml

GData

GDataは、例えば以下のような、Atom 1.0に準じたフィードデータです。

<entry
    xmlns="http://www.w3.org/2005/Atom"
    xmlns:gd="http://schemas.google.com/g/2005">
  <category
    scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/g/2005#event">
  </category>
  <title type="text">横河武蔵野FC vs. 佐川急便東京SC</title>
  <content type="text">最後の東京ダービー</content>
  <gd:where valueString="横河電機グラウンド">
  </gd:where>
  <gd:when
    startTime="2006-10-07T15:00:00+09:00"
    endTime="2006-10-07T17:00:00+09:00">
  </gd:when>
</entry>

イベントが「終日」の場合は、gd:when要素のstartTime/endTime属性値に日付のみを指定します。「繰り返し」のイベントの場合は、gd:recurrence要素を指定します。GData要素の詳細は、Common Elements: “Kinds”を参照してください。
GDataの文字エンコーディングはUTF-8です。日時は、Atom 1.0が採用しているRFC3339形式で指定します。

リクエストが成功した場合のレスポンスはHTTP 201 Createdで、そのボディは、送信したGDataにid要素やupdated要素などが追加されたフィードデータです。

クラスライブラリを使ったサンプルプログラム

以下の例では、ClientLoginでトークンを取得した後、イベントを追加しています。

<?php
$email = 'example@gmail.com';
$password = 'password';

$entry = <<<GDATA
<entry
    xmlns="http://www.w3.org/2005/Atom"
    xmlns:gd="http://schemas.google.com/g/2005">
  <category
    scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/g/2005#event">
  </category>
  <title type="text">横河武蔵野FC vs. 佐川急便東京SC</title>
  <content type="text">最後の東京ダービー</content>
  <gd:where valueString="横河電機グラウンド">
  </gd:where>
  <gd:when
    startTime="2006-10-07T15:00:00+09:00"
    endTime="2006-10-07T17:00:00+09:00">
  </gd:when>
</entry>
GDATA;

require_once 'Google/Calendar.php';
$service = new Google_Calendar;

if (!$service->requestClientLogin($email, $password)) {
  exit("ClientLogin has failed.\n".$service->getResponseBody());
}
if (!$service->insert($entry)) {
  exit("Inserting an entry has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>

イベントの変更と削除

イベントの変更及び削除は、そのイベントエントリーのlink要素中、rel属性値が「edit」のものの、href属性値に示されているURLに対してリクエストを送信します。

変更の場合は、以下のようにPUTメソッド(または、X-Http-Method-Overrideヘッダに「PUT」を指定したPOSTメソッド)を用いて、変更したGDataを送信します。

PUT Edit_URL HTTP/1.1
Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"]
Content-Type: application/atom+xml

GData

削除の場合は、以下のようにDELETEメソッド(またはX-Http-Method-Overrideヘッダに「DELET」を指定したPOSTメソッド)を用います。

DELETE Edit_URL HTTP/1.1
Authorization: [GoogleLogin auth="ClientLogin_token"|AuthSub token="AuthSub_token"]

いずれも、リクエストが成功した場合のレスポンスはHTTP 200 OKで、変更の場合は、そのボディは、送信したGDataが加工されたフィードデータです。

クラスライブラリを使ったサンプルプログラム

以下の例では、ClientLoginでトークンを取得した後、イベントの開始/終了日時を変更しています。

<?php
$email = 'example@gmail.com';
$password = 'password';

$edit_url = 'http://www.google.com/calendar/feeds/default/private/full/abcd/1234';
$entry = <<<GDATA
<entry
    xmlns="http://www.w3.org/2005/Atom"
    xmlns:gd="http://schemas.google.com/g/2005">
  <category
    scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/g/2005#event">
  </category>
  <gd:when
    startTime="2006-10-07T14:00:00+09:00"
    endTime="2006-10-07T18:00:00+09:00">
  </gd:when>
</entry>
GDATA;

require_once 'Google/Calendar.php';
$service = new Google_Calendar;

if (!$service->requestClientLogin($email, $password)) {
  exit("ClientLogin has failed.\n".$service->getResponseBody());
}
if (!$service->update($entry, $edit_url)) {
  exit("Updating an entry has failed.\n".$service->getResponseBody());
}
header('Content-Type:application/xml;charset=UTF-8');
echo $service->getResponseBody();
?>

Some Tips

Category: ウェブ制作
Posted 2006年10月04日 22:53

2006年08月17日

HTMLを整形式のXML文書に修正するPHPクラス

注意

このスクリプトはPHP4用です。PHP5では整形式のXMLへの変換はDOMDocument::loadHTMLで簡単に行えます。

$doc = new DOMDocument('1.0', 'UTF-8');
$doc->preserveWhiteSpace = false;
$doc->loadHTML($html);
echo $doc->saveXML();

PHP5では、独自の構成ルールの利用や任意の要素/属性の削除/置換など、このスクリプトの付加機能が必要でない限りDOMの機能を利用してください。


ガーロ解任記念(無関係)。夏休みの宿題(嘘)。

HTMLなどにありがちなズサンなマークアップを、整形式のXMLドキュメントに補正するPHP用のクラスライブラリです。
一般的なXHTML変換処理にみられる、タグ書式の修正や不適切に用いられている解析対象記号の置換などに加えて、DTD的構成ルールを用いて、欠落している要素の補完や、要素の親子関係の補正をある程度行なうことができます。構成ルールは任意に指定可能で、これにより例えば、HTMLソースから不要な要素や属性を除去したり、別の要素に置換したりといったことも行えます。
各種のプログラミング言語において様々に提供されているマークアップの補正機能は、PHPでは、PECL拡張モジュール版のTidyなどを利用できますが、残念ながらこれらは、現在の一般的なレンタルサーバのPHP環境では必ずしも用意されているわけではありません。このスクリプトベースのクラスライブラリは、このようなバイナリ拡張モジュールが利用できない環境で、マークアップの補正を行う際の補助となることを意図したものです。

てゆうか、まあこいつのために作ったんだけど。

このクラスライブラリは、Free Software FoundationによるGNU Lesser General Public License(LGPL)のバージョン2.1あるいはそれ以降のバージョンの規約に従いライセンスされます。

応用例

» HTMLをXML化してDOMやXPathで操作するWebスクレイピング用PHPクラス

仕様とか制限事項

リリース

» 1.2.1 (stable) released 2007/05/17

※バージョン1.1からは、それ以前のバージョンと異なり、HTML_Sax3クラスのオブジェクトを別途に作成する必要がなくなりました。

ファイル名概要
HTMLParser.class.phpクラスライブラリ本体。
xhtml1-transitional_dtd.inc.phpXHTML 1.0 TransitionalのDTDを基に作成した、サンプルの構成ルールを表す連想配列を返す外部PHPファイル。
sample.phpHTMLを読み込み、補正結果を表示するサンプルアプリケーション。
ファイル中の、ターゲットのURIを指定している箇所を編集して、お好みのウェブページを表示してみてください。また、冒頭にあるふたつの変数を、output_xmlをTRUEに、output_xmlnsをFALSEにすると、Mozilla FirefoxなどではXMLドキュメントツリーを確認できると思います。

概要

このクラスライブラリは、SAXベースのXMLパーサである、PEARのXML_HTMLSax3用のイベントハンドラを定義したものです(従ってその利用にはXML_HTMLSax3が必要です)。XML_HTMLSax3は、PHPのネイティブXMLパーサと異なり、不適切なマークアップに対しても処理を継続します。XML_HTMLSax3は、一般的なSAXパーサと同様に、パース対象のドキュメント中に開始タグや終了タグ、キャラクターデータなどの要素を検出する都度、各要素に対応するハンドラを呼び出します。このクラスライブラリの各ハンドラメソッドは、XML_HTMLSax3から引き渡された各要素を、指定の構成ルールに従って文字列に構築していきます。

サンプルプログラム

以下のダメダメHTMLをパースする簡単なサンプルプログラムを見ていきます。
以下のHTMLはShift_JISエンコーディングで、sample.htmlという名称のファイルで存在しているものとします。

<META NAME=DESCRIPTION CONTENT=Foo&Bar>
<H1>
  <DIV ALIGN=CENTER>Foo&Bar</DIV>
</H1>
<HR NOSHADE>
</BODY>
<P>Foo<BR>Bar
<TABLE FOO=BAR>
<TD>Foo&Bar</TR></TR></TR></TR>
</TABLE>
<LI>Foo
<LI>Bar
<FOO>
<HTML>

まず、このHTMLを読み込み、UTF-8エンコーディングに変換しておきます(XML_HTMLSax3が扱える文字エンコーディングはUTF-8のみです)。

$source = file_get_contents('./sample.html');
mb_convert_variables('UTF-8', 'Shift_JIS', $source);

このクラスのオブジェクトを作成し、アーカイブに付属している、サンプルの構成ルールを表す連想配列を返す外部PHPファイル(xhtml1-transitional_dtd.inc.php)を指定します。このサンプルの構成ルールはXHTML 1.0 TransitionalのDTDを基に作成したものです。setRuleFileメソッドは外部ファイルを指定しますが、これに替えて、setRuleメソッドで配列を指定することもできます。

require_once('./HTMLParser.class.php');
$parser = new HTMLParser;
$parser->setRuleFile('./xhtml1-transitional_dtd.inc.php');

このクラスのオプションを指定します。

$parser->setGenericParent('body');
$parser->setRoot('html',
  array('xmlns' => 'http://www.w3.org/1999/xhtml', 'xml:lang' => 'ja')
);

パースを実行します。

$parser->parse($source);

パース結果の出力を得ます。オプションの文字エンコーディングが指定されている場合、mbstringが利用可能であれば、文字列は指定した文字エンコーディングに変換されます。オプションが未指定の場合、及びmbstringが利用不可の場合、文字エンコーディングはUTF-8となります。

$result = $parser->dump('Shift_JIS');

この出力は以下のようになります(改行とインデントは見易いように追加したもので、実際はこの通りではありません)。

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
  <head>
    <meta name="DESCRIPTION" content="Foo&amp;Bar" />
  </head>
  <body>
    <div align="CENTER">
      <h1>Foo&amp;Bar</h1>
    </div>
    <hr noshade="noshade" />
    <p>Foo<br />Bar</p>
    <table>
      <tr><td>Foo&amp;Bar</td></tr>
    </table>
    <ul>
      <li>Foo</li>
      <li>Bar</li>
    </ul>
  </body>
</html>

この例では以下のような処理が施されています。

しかし一方、これを例えばXHTML 1.0 TransitionalのDTDで検証した場合、以下のような不備があり、これらは、このクラスライブラリの処理の限界の例です。

なお、ドキュメントのパース結果は文字列として返されますが、幾つかのタグについてはより利便性の高い形式でその属性値を取得したい場合があるかもしれません。例えば、HTMLを解析する際にはしばしばMETAやLINKの属性値を得る必要がありますが、これらをパース結果の文字列から再度取得し直すのは非効率的です。
このクラスライブラリでは、あらかじめ指定されたタグについて、その属性値を連想配列に保存し、パース結果とは別途にこれを取得する手段を用意しています。

まず、パースを開始する前に、setTagsToSaveメソッドで属性値を保存するタグ名を指定しておきます。タグ名は、以下のような文字列、または配列のいずれでも指定でき、両者の混在も可能です。

$parser->setTagsToSave('meta', 'link');

パース後にgetSavedTagsメソッドで保存された連想配列を得ることができます。オプションの文字エンコーディングが指定されている場合、mbstringが利用可能であれば、文字列は指定した文字エンコーディングに変換されます。オプションが未指定の場合、及びmbstringが利用不可の場合、文字エンコーディングはUTF-8となります。

$saved_tags = $parser->getSavedTags('Shift_JIS');

以下は例として、取得した配列からMobile Link DiscoveryのURIを得るものです。

if (isset($saved_tags['link'])) {
  foreach ($saved_tags['link'] as $value) {
    if (isset($value['href'])
      and isset($value['rel'])
      and isset($value['media'])
      and strtolower($value['rel']) == 'alternate'
      and strtolower($value['media']) == 'handheld') {
      $mobile_link = $value['href'];
      break;
    }
  }
}
if (isset($mobile_link)) {
  var_dump($mobile_link);
}

リファレンス

void HTMLParser->setRuleFile ( string filename )
構成ルールを表す連想配列を返す外部PHPファイルを指定します。
連想配列及び外部ファイルの詳細はアーカイブに付属のサンプルを参照してください。
void HTMLParser->setRule ( array )
構成ルールを表す連想配列を指定します。
連想配列の詳細はアーカイブに付属のサンプルを参照してください。
string HTMLParser->dump ( [string to_encoding] )
パース結果の文字列を返します。オプションの文字エンコーディングが指定されている場合、mbstringが利用可能であれば、文字列は指定した文字エンコーディングに変換されます。オプションが未指定の場合、及びmbstringが利用不可の場合、文字エンコーディングはUTF-8となります。
void HTMLParser->setRoot ( string tag_name [, array tag_attributes] )
ドキュメントのルート要素を指定します。パーサから開始タグのハンドラに最初に渡されるタグ名がここで指定した名前と合致しない場合は、指定の値に基づく要素が補完され、ハンドラから渡された要素は、その子要素として評価されます(なお、属性値は評価対象ではありません。名前さえ合致していれば、その属性値に関わらずハンドラから渡された要素がそのまま利用されます)。
void HTMLParser->setGenericParent ( string tag_name )
要素の親子関係の補正を行う際には、構成ルールに定義される、各タグの「既定の親(default_parent)」が参照される場合があります。HTMLでは、多くのタグについてこれは「body」ですが、これらのタグについて構成ルールに逐次「既定の親」を記述するのは効率が悪いので、「既定の親」が未定義のタグについては、ここで指定したタグが「既定の親」となります。
void HTMLParser->setTagsToSave ( mixed tag_name )
このメソッドによって指定したタグの属性値は連想配列に保存され、パース後にgetSavedTagsメソッドによってアクセスすることができるます。タグの指定は、タグがひとつなら文字列で、複数ある場合はカンマ区切りの文字列または配列で行い、文字列と配列は混在することができます。
array HTMLParser->getSavedTags ( string to_encoding )
setTagsToSaveメソッドで指定したタグの属性値を保存した連想配列を返します。オプションの文字エンコーディングが指定されている場合、mbstringが利用可能であれば、文字列は指定した文字エンコーディングに変換されます。オプションが未指定の場合、及びmbstringが利用不可の場合、文字エンコーディングはUTF-8となります。

ACKNOWLEDGMENT

The idea of this software is in fact inspired by PEAR XML_DTD maintained by Thomas V.V.Cox and Stephan Schmidt. And, of course, this software is greately depends on PEAR XML_HTMLSax3 maintained by Harry Fuecks. I would like to thank them all.

Category: ウェブ制作
Posted 2006年08月17日 21:54

2006年05月31日

Jリーグ各クラブのサイトのHTMLを評価してみた

日本サッカー界の総元締めであるJFAのサイトがリニューアル!
…だそうなので、このご時世のリニューアルだからして、きっと国内の全サッカー関連サイトが手本とすべき素晴らしいものに仕上がっているのだろうと、期待に胸を膨らませながら、Another HTML lintにかけてみますた。

結果。

116個のエラーがありました。このHTMLは -20点です。

( ´_ゝ`)

まあ、W3C原理主義者でもないので、ずさんなマークアップはどうでもいんだけど、実際にページを眺めてみると、アクセシビリティの類も一切無視というツクリで。JFAという組織の性格からしても褒められたものではないわなと。
で、ついでなのでJリーグ各クラブのサイトについても調査(と言っても他力本願なんだけど)を実施してみますた。


調査の概要

J1/J2各クラブのウェブサイトの「トップページ」※1のURLについて、Another HTML lintと、W3C Validatorのそれぞれによる評価結果を確認した(Another HTML lintとW3C Validatorとの違いは、Another HTML-lintのよくある質問と答を参照)。URLごとの結果の一覧では、Another HTML lintについてはその得点(100点満点からの減点式)を、W3C Validatorについてはエラーの数を記してある。
また、各URLをMozilla Firefox 1.5.0.3で表示した際に、「JavaScriptコンソール」に示されるエラーも併せて確認した。URLごとの結果の一覧では、エラーのうちCSSに関するものの数を記してある(JavaScriptに関するエラーは殆ど見られなかったので割愛した)。

結果のサマリー

Another HTML lintでの最高&最低得点
最高:横浜FC(79点)
最低:横浜F・マリノス(▲817点)
W3C Validatorで「Valid」と評価されたページ
無し
FirefoxでのCSSエラーの最多個数
横浜F・マリノス(210個)

総評

はたして、標準仕様の信奉者たちは目を疑うだろうか。
Another HTML lintの採点は、100点満点からの減点式だが、得点がプラスである例すら稀で、殆どのURLは0点以下のマイナス得点となっている。また、W3C Validatorで「Valid」と評価されたものは、URL単位でひとつしかなく、しかもそれは、具体的な内容の無い、フレームセット中1のフレームであるため、フレームセットドキュメントについては、それを構成する全URLの総合で考えるとした場合、「Valid」なページは無かったということになる。
ただし、もちろんこれは、あくまでW3Cの仕様などに照らし合わせた結果の評価である。ウェブ製作者の多くが認知している通り、こうした仕様は、必ずしも一般に普及しているウェブブラウザの実情には沿っていない場合があり、厳格な仕様の遵守は、現状では未だに困難を伴う。例えば、EMBED要素は、旧世代のNetscapeのウェブブラウザで、Flashオブジェクトなどの配置に利用し得る唯一のものだが、これはW3Cの仕様には存在しないため、この要素が書かれたHTMLは、W3C Validatorではあまねく「Valid」ではないと評価される。Another HTML lintで高得点を得ている横浜FCは、W3C Validatorでは「Valid」ではないと評価されているが、8箇所あったエラーのうち、7箇所までは、このEMBED要素を記述しているためのものである。

ただ、それにしてもあまり好ましくない状況ではある。なぜなら、こうした減点やエラーとされた箇所は、必ずしも前述のような実情を考慮したものばかりではなく、単に配慮を欠いているが故の産物にしか思えないものが極めて多いからだ。
市場を少数のユーザエージェントが寡占している状況では、標準仕様に拘ったマークアップ自体は必ずしも重要ではないかもしれないが、マークアップ記述に対する配慮が見られるウェブサイトは、例えばアクセシビリティのような、より実用的な(そしてより軽視されがちな)事柄に対する配慮も期待できる。例えば、TABLE要素をレイアウトのために利用することは、「論理的」に正しくないというだけではなく、「特別なソフトウェアを利用しているユーザーにとって、ページの構成を理解することやサイト内を行き来することを難しくして」※2しまうという問題を生じ得る。あるいは、IMGなどの要素に適切なALT属性を付与することは、アクセシビリティの観点では非常に重要である。このような、アクセシビリティに対する配慮は、Jリーグクラブのような公共性の高い団体のウェブサイトにとっては特に重要なのではないかと思われるのだが、少なくとも今回対象としたURLについては、こうした配慮を確認することは殆どできなかった。
そうした中、モンテディオ山形のものは、TABLE要素をレイアウトに用いず、いわゆる「構造的な」HTMLであることが心掛けられているようだ。残念ながらマークアップ自体は標準仕様から外れている箇所があるため、評価結果は決して芳しいものではないが、この点は評価できるだろう。
また、大宮アルディージャのものは、音声読み上げブラウザに対して配慮しようとしているようだ。ただしこれは、今回対象したURLに関しては残念ながら万全に機能しているとは言い難く、この点は善処を期待したい。

URLごとの結果の一覧

クラブURLAnother HTML lint得点W3C Validatorエラー数Firefox CSSエラー数
札幌http://www.consadole-sapporo.jp/-12295171
仙台http://www.vegalta.co.jp/-14637
山形http://www.montedio.or.jp/index.htm36120
鹿島http://www.so-net.ne.jp/antlers/61320
水戸http://www.mito-hollyhock.net/-25521
草津http://www.thespa.co.jp/top.html-15110
浦和http://www.urawa-reds.tv/-10722※36
http://www.urawa-reds.co.jp/ (FRAMESET)-18040
http://www.urawa-reds.co.jp/cont.htm (FRAMESET)-311150
http://www.urawa-reds.co.jp/menu.htm-29270
http://www.urawa-reds.co.jp/ind_main.htm-211170
http://www.urawa-reds.co.jp/ind_sw.htm-164220
大宮http://www.ardija.co.jp/8770
千葉http://www.so-net.ne.jp/JEFUNITED/ (FRAMESET)-323180
http://www.so-net.ne.jp/JEFUNITED/head.html-251190
http://www.so-net.ne.jp/JEFUNITED/left.html-22750
http://www.so-net.ne.jp/JEFUNITED/contents.html-106720
http://www.reysol.co.jp/-46710
東京http://www.fctokyo.co.jp/-631961
ヴェルディhttp://www.verdy.co.jp/-10483
川崎http://www.frontale.co.jp/-174890
横浜FMhttp://www.f-marinos.com/index_dist.php-817376210
横浜FChttp://www.yokohamafc.com/7980
湘南http://www.bellmare.co.jp/ (FRAMESET)-27824※30
http://www.bellmare.co.jp/header.htm-146170
http://www.bellmare.co.jp/left.htm-30292
http://www.bellmare.co.jp/main.htm-18680
http://www.bellmare.co.jp/footer1.htm-14560
http://www.bellmare.co.jp/footer2.htm-288260
甲府http://www.ventforet.co.jp/-511190
新潟http://www.albirex.co.jp/ (FRAMESET)-358180
http://www.albirex.co.jp/menu1.htm-8760
http://www.albirex.co.jp/title1.htm-14070
http://www.albirex.co.jp/top.htm-10550
http://www.albirex.co.jp/left.htm-76270
清水http://www.s-pulse.co.jp/ (FRAMESET)-37722※40
http://www.s-pulse.co.jp/s-pulse/header2006.html-998※40
http://www.s-pulse.co.jp/s-pulse/menu.html-2514※40
http://www.s-pulse.co.jp/s-pulse/home.html-1623※40
http://www.s-pulse.co.jp/s-pulse/footer.html-14250
磐田http://www.jubilo-iwata.co.jp/-1241412
名古屋http://www.so-net.ne.jp/grampus/ (FRAMESET)-241140
http://www.so-net.ne.jp/grampus/menu.html-102420
http://www.so-net.ne.jp/grampus/main.html-67500
京都http://www.kyoto-purple-sanga.co.jp/-9225224
G大阪http://www.gamba-osaka.net/-16310
C大阪http://www.cerezo.co.jp/index.html-43340
神戸http://www.vissel-kobe.co.jp/-165127
http://www.vissel-kobe.co.jp/index.html-471928
広島http://www.sanfrecce.co.jp/-52205
徳島http://www.vortis.jp/-15144
愛媛http://www.ehimefc.com/p/index.html-53-※51
福岡http://www.avispa.co.jp/ (FRAMESET)-278160
http://www.avispa.co.jp/side.html26Valid0
http://www.avispa.co.jp/header.html-212170
http://www.avispa.co.jp/index_body.html-64565
鳥栖http://www.sagantosu.jp/39305
大分http://www.oita-trinita.co.jp/-681122
Jリーグhttp://www.j-league.or.jp/-3194※65
JFAhttp://www.jfa.or.jp/-20411

幾つかの覚え書き

注釈

  1. 確認対象としたURLは、J1/J2各クラブのウェブサイトの「トップページ」のものであり、これは原則として、Jリーグのウェブサイトの「クラブガイド」に記載されているURLである。
    • URLがフレームセットドキュメントの場合、その各フレームもそれぞれ対象とした。
    • URLが、サーバサイドでの処理や、META要素の「refresh」、JavaScriptなどによって、一般的なPC用のウェブブラウザでのアクセス時に、異なるURLに自動的にリダイレクトされることが想定されていると思われる場合は、そのURLを対象とした。
    • 浦和レッズの場合、Jリーグのウェブサイトには http://www.urawa-reds.tv/ が記載されているが、一般的に「浦和のサイト」として認識されているのは http://www.urawa-reds.co.jp/ であると思われるので、これについては両方を対象とした。
    • ヴィッセル神戸の場合、 http://www.vissel-kobe.co.jp/ はいわゆる「扉ページ」であり、他クラブの「トップページ」と同等の役割は http://www.vissel-kobe.co.jp/index.html であると思われるので、これについては両方を対象とした。
    なお、ここでの結果はあくまで本日現在の各URLのものであり、後日の確認では確認結果は当然変化することが予想される。
  2. W3CのWeb Content Accessibility Guidelines 1.0の、ZSPCに掲載されている日本語訳より抜粋。
  3. HTTPヘッダ及びMETA要素に文字エンコーディングが指定されていないため自動検出が試みられたが、UTF-8であるとされたので、文字エンコーディングを指定して評価した。
  4. META要素で指定された文字エンコーディングが「x-sjis」であるため、不正なエンコーディングであるとして解析に失敗したので、文字エンコーディングを指定して評価した。
  5. 機種依存文字が含まれているため、不正なエンコーディングであるとして解析に失敗した(対処不能)。
  6. HTTPヘッダで指定された文字エンコーディングが「none」であるため、不正なエンコーディングであるとして解析に失敗したので、文字エンコーディングを指定して評価した。なお、「none」という文字エンコーディングは、ウェブサーバの文字化け対策として知られる間違ったTIPSで、ちなみにJ's GoalのHTTPヘッダも同様である。

なお、えらそうなこと言っててめえのはどうなんだコラとかいう話題はスルーで。

Category: その他の蹴球, ウェブ制作
Posted 2006年05月31日 02:24

2006年04月25日

画像→HTML変換ツール

AAを画像に変換というのはよくあるハナシだけど、tsujitakoさん画像→HTML変換ツールはこの逆で、画像をAAに変換するもの。いや、正確にはいわゆるAAではなくて………、とか説明してるよりも実物を見れば一目瞭然だ罠。

こんなんなります。これ画像じゃないよ。
CSS整形なので、RSSリーダーとかアンテナとかで見てるとワケワカメかもしれない。

元画像を指定のスケールにリサイズしてパレットイメージに変換した上で、imageColorAt()あたりで各ピクセルの色インデックスを取り出して、表組みに展開という感じ?imageColorAt()なんてなんに使うのさと思ってたけど、こういうふうに使うのか(違)。おもしれえええ。

とりあえず、これで水玉模様なTシャツとか作ると簡単オサレではなかろか。もうすぐ夏だし。

Category: ウェブ制作
Posted 2006年04月25日 22:01

2006年03月15日

MacのIEは、CSSではシングルコーテーション(')を無視しくさります

自作のウェブページなんて、自分のメインブラウザでしかちゃんと見てないわけで。Firefoxユーザのおいらは、Firefoxでの表示はしっかり確認するものの、あとはたまにIE6で見てみるくらいなわけです。

サイトのログに、以前からたまーに「/ucb/'images-site/azulgrana/banner-bg.png'」のようなURIが404 Not Foundとなってたのですが、ログと言ってもxreaのデフォの、Analogでの解析済みのもので、生ログじゃないので突っ込む気も起こらず放置していたわけですが。気が向いたのでググってみたらば原因が判明すますた。

で、まあ原因はタイトル通りで。MacのIE5は、CSSではダブルクオテーション(")はOKだけどシングルクオテーションはNGだと。なんじゃそりゃあ。てなことで全部書き換えますたよ。

Category: ウェブ制作
Posted 2006年03月15日 14:00

2006年02月24日

青赤バリデータ

「バリデータ」とカタカナで書くとなんかヤな感じ。

w3cのCSSアイコンをパクってAoaka Styleアイコンを作り、調子こいて、今度はValid HTML系アイコンをパクってValid Aoakaアイコンを作り、そうなると、なにがValidであるかを検証するために、Markup Validatorのパクリも必要だろうということで作ってみますた。そりゃもう、ヒマなオフシーズンのなせる業さ。

» Aoaka Validator

ウェブページのテキストを解析し、その内容が青赤的に適切なものであるかどうかを判定させてみようというネタでございます。一応、その手のページを読ませると、それっぽいスコアが出てくる筈。インチキなんだけど。なお、w3cのパクリであることが身上なので、表記は当然すべて横文字です。デタラメなんだけど。

青赤なドキュメントとは、FC東京についてなんらかの言及があるものを言うわけですが、そこにはもちろん、かくあるべしという基準なんてありゃしません。w3cのValidatorなどのHTML解析器は、基準が明確なので減点方式の採点ですが、ここでは同様の手法を採ることができないため満点というものはなく、プラスのポイントとマイナスのポイントを別々に与えていて、それぞれのポイントは幾らでも膨らんでいきます。
で、プラスポイントは、FC東京について言及していると思われるフレーズに対して発生し、マイナスポイントはFC東京のファンとしては不適切と思われるフレーズに対して発生するのですが、後者のルールはひとつだけで、かつ厳格です。一方前者は、「FC東京についてなんらかの言及をしているフレーズ」なんて無限に想定されるわけで、そんなの網羅できるわきゃないので、チョーいい加減なルールになってます。そんなわけで、プラスポイントのほうは単なるお遊びだと思ってくれろ。
いかんせんルールがいい加減なので、プラスポイントを発生させているフレーズが、FC東京にはまったく関係のないものだったり、ネガティブな言及であったりすることは多々あるわけですが、アンチなページがハイスコアを叩き出したりするのもまた一興。

ちなみに、これはもちろんHTML解析器じゃないので、HTMLがw3c標準に準拠してようがしてまいが一切関知しませんが、いわゆる「構造的なHTML」であるほうがハイスコアにはなりやすいかも。

なお、チェックの際の選択肢にある「Transitional」と「Strict」とは、マイナスポイントが発生していても、総ポイントがプラスなら「Valid」なのがTransitionalで、マイナスポイントがあれば、いくら総ポイントが高くても「not Valid」なのがStrictです。まあ、w3cのパクリっぽくなるように無理矢理用意してみただけなんだけど。

ところで、このサイトのトップページとか、やたらとスコアが低いよね、というのは、オフシーズンでネタがないんだからしょーがないんだよ、多分。

Category: FC東京, ウェブ制作
Posted 2006年02月24日 20:54

2006年02月17日

続・ジオシティーズ広告スクリプトの不具合

Mozilla/Firefoxをご利用の皆さまにおかれましては、geocities.jpのページを表示したとき、縦長の広告バナーの表示される位置が、画面の右端だったり左端だったりする現象をご覧になったことがあるかもしれません。これは、この現象が、またしてもジオシティーズ謹製のJavaScriptの不具合によるものでしたよ、というハナシ。

事の発端は、およそ1年半ぶりに行った、geocities.jpに置いてあるラ・コルーニャへの道の手直し。と言っても新しい内容を加えたわけではなく、目的のひとつは古くなっていたリンクなどの修正で、特にCRTVGのウェブサイトのリニューアルに伴い、動作しなくなっていた「ガリシアヲチ」ツールバーの修正とか。まあ、このあたりは本題とは関係なく。

で、もうひとつがHTML(の構造)とスタイルシートの書き直し。
これはなにかと言うと、これを作った当時、ジオシティーズの広告スクリプトはドキュメントの先頭(つまりDOCTYPE宣言より先)にインクルードされる場合があり、このためHTML/CSSの記述は、Quirksモードで描画されることを前提にしなければならなかったわけです(この当時のハナシはこちらにありますが、この記事は、ジオシティーズの広告スクリプトの変更に伴い無意味なものになっているため、このサイトには移してません。なお、「DOCTYPE宣言とかQuirksモードってナニ?」というかたは、例えばこちらとかをどーぞ)。
で、しかし確か昨年の夏頃に、ジオシティーズの広告スクリプトが全面的に変更され、少なくとも自分の知る限り、ドキュメントの先頭にインクルードされるということはなくなっていたので、ならばHTML/CSSをStandards Compliantモード向けに作り直そうか、と。

てなことで、手直しを施したファイルをアップロードしてFirefoxで表示してみると、広告バナーが左端に表示される。IE6では右端に表示される。これは、「Firefoxは左」という仕様なのか?と思ったのですが、確かFirefoxでも右端に表示されるページを見た覚えがあるので調べてみたらば、またしてもジオシティーズのJavaScriptの不具合が原因だということが判明したという次第。

さて、今回問題を起こしているのは、インクルードされるSCRIPT要素で読み込まれるJSファイルのうち、div.jsの、以下の部分。

function auPos(divId) {
  posL = findX() -177;
  if (ns4) {
    posL='1';
    document.layers[divId].visibility = "show";
    document.layers[divId].left = posL;
  } else if (ie5 || ns6) {
    document.getElementById(divId).style.visibility = "visible";
    document.getElementById(divId).style.left = posL;
  } else if (ie4) {
    document.all[divId].style.visibility = "visible";
    document.all[divId].style.left = posL;
  }
}

このファンクションauPos()は、広告バナー部分の各DIV要素について、ウィンドウの左端からの位置を設定するもので、各DIVのstyle.leftを、(変数posLに格納された)ファンクションfindX()が返すウィンドウの内側の幅から、177(広告バナー部分の横幅)を引いた数値に設定しようとします。
で、問題は、style.leftに設定されるのが数値であるために起こります。スキモノの皆さまはお気付きかと存じますが、本来CSSでは、この手の類には単位指定が必須なわけで。しかし、ここでは単位が省略されてしまっているため、Standardsモードで動作しているGeckoエンジンでは、この設定は不正だとして無視され、結果、広告バナー部分の左端の位置は設定されずじまいとなります。
一方、ウンコな仕様でお馴染みのInternet Explorerは、描画モードに関わらず、単位が省略されていると、単位はピクセルだと勝手に解釈しやがるので、このスクリプトは、その作者の本来の意図通りに動作し、またGeckoエンジンも、Quirksモードでは同様の動作となるため、Mozilla/Firefoxでは、Quirksモードで描画されるHTMLに限っては、やはり作者の本来の意図通りに動作してしまうのでした。

ちなみに、この広告バナー用のスタイルシートであるdiv.cssを見ると、ご丁寧なことに、数値がゼロの場合のみ単位が指定されていて、それ以外は省略されてたりします。逆だっつうの。

さて、しからばもう一度Quirksモード向けにHTML/CSSを作り直すかというと、それはメンドくさい、というかいい加減にしてくれ。
てなことで、またぞろ修正用のスクリプトを用意してみたあるよ。各HTMLファイルに以下のスクリプトを書いたJSファイルを読み込むscriptタグを追加し、そのbodyタグに「onload="fixGeocitiesBug()"」を追加。

function fixedAuPos(arg) {
  document.getElementById(arg).style.left = document.body.offsetWidth?
    (document.body.offsetWidth -177) + 'px': (findX() -177) + 'px';
}
function fixedRlPg() {
  fixedAuPos('y_gc_div_adcntr');
  fixedAuPos('y_gc_div_au1');
  fixedAuPos('y_gc_div_mast');
}
function fixGeocitiesBug() {
  if (document.getElementById
    && document.getElementById('y_gc_div_adcntr')
    && !document.getElementById('y_gc_div_adcntr').style.left) {
    fixedRlPg();
    onresize = fixedRlPg;
  }
}

onloadでの処理なので、ドキュメントの読み込みが完了するまで、広告バナーはウィンドウの左端に居座ってしまいますが、それはしょうがない(なにかいい対策をご存知のかたは教えてくださいな)。

なお、ファンクションfindX()を使用した元々のスクリプトが返す左端の位置をそのまま適用すると、Mozilla/Firefoxでは広告バナーの右端がウィンドウの右端から若干はみ出る(横スクロールバーが表示される)ため、ここではdocument.body.offsetWidthを使用しています。これはもちろん、ウィンドウの幅ではなくBODY要素の幅なわけで、(広告バナー部分の横幅である177を差し引いている)上のスクリプトでは、BODYのmargin値がゼロの場合に、ウィンドウの丁度右端に広告バナーは位置することになるわけですが、このように、BODYのmargin値に応じて、差し引く値を調整する必要があるです。

Category: ウェブ制作
Posted 2006年02月17日 23:30

2006年02月15日

Jリーグ/JFL観戦日程シミュレータ

2006年度シーズン前半のデータしか登録してませんよ。
つまり現在は、以下にあるものにはなんの価値もありません。


シーズンオフにつき、大半のドメサカオタの皆さまにおかれましては、ブログの更新を停止してみたり、別の話題にカミングアウトしてみたりしながら、来るシーズンの妄想に励んでおられるかと存じます。
この時期の主な妄想のひとつに観戦スケジュールの立案があり、平均的なドメサカオタはリーグの日程表を眺めながら、愛するチームのホームゲームは当然全て観戦するとして、アウェイはどうしようか、遠方アウェイなら近場の他クラブのゲームをひやかそうか、などと思案されておられるかと存じますが、お気楽に妄想を拡げられるように、お好みの試合の日程一覧をサクっと表示するスクリプトを作ってみますた。

» Jリーグ/JFL観戦日程シミュレータ

使い方

  1. まずはホームゲームを観戦するチームを選びます。
    マイチームは当然として、近場なのでホームなら見に行ってもいいかなと思うチームも、とりあえずチェックしておきます。
  2. 同様にアウェイゲームを選びます。アウェイは、チームとスタジアムが一致したもののみ表示されます。マイチームのアウェイゲームはすべて観戦したいところですが、さすがにここは行けないや、というスタジアムはチェックしないでおきます。
  3. 表示された日程表から、観戦予定ではないゲームのチェックを外します。
    日程表の下に表示される「CSV形式で表示」をクリックすると、チェックの付いているゲームのリストを、Excelなどで利用可能な、カンマ区切りのテキストで表示します。

更新履歴

Technical Stuff

JKL.Calenderについて

日付範囲指定の入力フォームでポップアップ表示するカレンダーは、川崎有亮さんJKL.Calender - ポップアップするカレンダー表示クラスによるものです。自分で作るのは面倒だったので拝借。クラス化されているので、ここでの利用例のように、複数の入力フォームについて、それぞれのインスタンスでもって利用できるところがステキ。
なお、オリジナルの以下の部分の「ymd」は、日付をYYYY/MM/DD形式で表した文字列で、「splt[1]」はそのMMの部分なのですが、これは(Dateオブジェクトではなく)文字列なので、有効範囲は0~11ではなく1~12が正解の筈。てなことで、失礼ながらここだけ勝手に書き換えちゃってます。

// オブジェクトに日付を記憶する(YYYY/MM/DD形式で指定する)
JKL.Calender.prototype.setDateYMD = function (ymd) {
  var splt = ymd.split( "/" );
  if ( splt[0] > 0 && 
    splt[1] >= 0 && splt[1] <= 11 && 
    splt[2] >= 1 && splt[2] <= 31 ) {

Category: その他の蹴球, ウェブ制作
Posted 2006年02月15日 21:36

2006年01月26日

ガリシア風CSSデザイン

青赤デザインはlivedoor Blogからのもので、さすがに飽きてきたので、これはこれで置いといて、切り替え用のCSSをもうひとつ用意してみますた。新たにいちから作ったわけではなく、以前に別の企画で用意していてお蔵入りになったものの復活。
一応、「ガリシア風」のつもり。しかし背景に居座る木の写真は、ガリシアのものではなく等々力緑地のものだったりする罠。「どこがガリシアやねん」と言われると返す言葉もございません。あくまでイメージということでひとつ。
ま、シックでニート(NEETではなくneat)な雰囲気がお好みの貴兄や、青赤嫌いな貴兄はこちらをどーぞ。

青赤 ガリシア風

Mozilla/Firefoxなかたは、もちろん「スタイルシート」メニューから切り替えていただけますが、それではページを遷移するごとにメニューを操作しなければいけないわけで。トップページのサイドメニューにあるアイコンで切り替えていただくと、cookieを仕込ませるので、セッション終了までは、ページを遷移しても引き続き同じデザインで表示される筈。
これはJavaScriptでの実装で、しかもかなり安直。例によってMozilla/Firefox以外での動作は気にしちゃいません。IEエンジンをご利用の皆さまにおかれましては、切り替えアイコンをクリックすると、どういうわけかfont-sizeがsmallerになりやがったり(ページをリロードしたり遷移すると元に戻る)、印刷への反映がヘンだったりする模様ですが、知ったこっちゃありません。

ついでに、トップページの写真の一覧をランダム表示にしてみますた。
こっちはサーバサイドのPHPでの実装。これもクライアントサイドにしようかと思ったのですが、PHPのランダムってあまりにも楽チンなので。

Category: ウェブ制作, ガリシアのお勉強
Posted 2006年01月26日 21:43

2006年01月20日

AA(アスキーアート)を画像に変換

新年お蔵入りPHPスクリプト集そのさん。

2ちゃんねる及び2ちゃんねると同形式のDATファイルを利用する、まちBBSや、したらば、ぜろちゃんねるスクリプト(0ch BBS Script)などの各掲示板のレスを画像に変換する、要するにAASモドキですが、AASとは比べものにならない低脳。単にGDのimageTTFText()でなんか描いてみるテスツで作り始めて、ソッコーで飽きたため。
なお、p2機能拡張パックに、(真っ当な)PHP版のAASクローンがあるでございます。

PCサイト->携帯変換スクリプトで、画像化されたAAを表示 レスを画像に変換するニーズは、携帯端末などでAAを確認したい場合が主なわけで、これはPCサイト->携帯変換スクリプト(pc2m)との連携を前提にしていて、こいつ単独では、レスをPNG化する機能しかありません。
必要なパラメータを含む、こいつへのリクエストURLの生成や、こいつが吐き出したPNGを、携帯端末が対応している画像形式や画面サイズに応じて変換するあたりは、すべてpc2mに任せるという仕様で、pc2mを、これらの掲示板にアクセスした際に、こいつにリクエストして、そのレスポンスに再びpc2mでアクセスするようなリンクを付け足すように改造しておくという寸法になってます(URLから板とスレはわかるので、あとはレス番号ごとに、適当なところにリンクを付ける)。

負荷軽減をねらって、取得したDATと生成したPNGはローカルに一時保存しておくようになってます。
リクエストに合致するPNGが保存されていれば、それを単に表示して終了。なければ、該当のレスを含むDATがあればそこからPNGを生成し、それもなければDATの取得から始めます。
一定時間経過後のDATとPNGは、以下ではDAT取得時に掃除するようになってます。

注意点とか

» 「AA(アスキーアート)を画像に変換」の続きを読む

Category: ウェブ制作
Posted 2006年01月20日 21:32

Seesaa Blogなどのコメントを携帯向け掲示板風に変換

新年お蔵入りPHPスクリプト集そのに。

Seesaa Blog(及びシーサーのBlogServerシステムを利用している他のブログサービス)のコメントを、携帯向け掲示板風に変換表示するPHPスクリプトです。
シーサーのBlogServerシステムは、もちろん携帯端末での利用に対応しているわけですが、現時点のものは、コメントの表示に関しては、すべてのコメントを一度に表示してしまうため、携帯のキャッシュサイズ(メモリ容量)が充分でない場合、コメント数が多いとすべて表示されない場合があります。てなことで、これを分割し、指定件数分だけ表示できるように改竄するというもの。

なんでSeesaa Blogの利用者でもないおいらがこんなものを作ったかというと、コメント欄を掲示板的に利用しておられて、携帯でのコメント表示に困っておられたかたが、PCサイト->携帯変換スクリプトを発見して利用いただいていたのですが、あれはあくまで汎用のものなので、このような定型のドキュメントなら、より見やすく使いやすい表示を、簡単に用意できるだろうと。
てなことでこれは実は、今のところお蔵入りではなく、実際にここで利用できたりしますが、シーサーがBlogServerシステムの携帯向けコメント表示形式を変更すると(少なくともこのままでは)動作しなくなり、そもそもBlogServerシステムが、コメントの表示も携帯にきちんと対応しちゃえば用済みになっちゃうわけです。

利用可能なことを確認しているのは、以下のブログサービスを利用している各ブログ(独自ドメイン名での運用のものもOK)。

なお、シーサーのBlogServerシステムを利用しているブログサービスでも、Erog(blog.shard.jp/*)のように、ブログの識別子がホスト名ではなく、パス名に充てられているものは、このままでは利用できません。アダルトサイトを差別してるわけるではなく、こんなのもあるとは知らんかっただけ(そして、いまさらこのために修正するのもメンドーなだけ)。

注意点とか

このまま利用する場合は、ここにアップしているものとは異なり、設定画面とか端折ってるので、クエリー文字列を付与したスクリプトのURLに直接アクセスします。
クエリー文字列は、例えば「http://www.rcdtokyo.com/sc/sc.php?s=shiraishi.seesaa.net&d=7390945」のように、sキーワードにホスト名(「*.seesaa.net」の場合に限り「.seesaa.net」の部分は省略可で、この例なら「shiraishi」だけでもよい)、dキーワードにエントリー(記事)のID(個別のエントリーを表示するURLが「http://shiraishi.seesaa.net/article/7390945.html」なら「7390945」)を指定します。
さらにpキーワードで、1画面あたりの表示件数を(「p=20」とか。未指定の場合は10件)、fキーワードで表示範囲を(「f=1-100」とか。未指定の場合は最新のものまでを表示件数分)、それぞれ指定できます。fキーワードは「1」、「1-」、「1-100」、「-100」といった形式で、要するに2ちゃんねるのレス番号指定と同じ形式です(ただし「n」や「i」はナシ)。
そもそも以下にある表示画面のテンプレート自体がc.2ch.netのパクリで、accesskeyの割り当ても同じ。ただし、「省」はありません(常にコメントの全文を表示します)。

» 「Seesaa Blogなどのコメントを携帯向け掲示板風に変換」の続きを読む

Category: ウェブ制作
Posted 2006年01月20日 18:07

2006年01月13日

Yahoo Blogの画像付きエントリーをMovableTypeインポート形式に出力

新年お蔵入りPHPスクリプト集そのいち。

Yahoo Blog(とlivedoor Blog)の記事と画像を、このサイトに移転するのに作ったもので、二度と使うことはない筈なので、記念カキコ。
エントリーをMovableTypeのインポート形式に書き出すだけならさして面倒ではないわけですが、自分の場合、Yahoo Blogは(「2GBのディスク容量」という謳い文句にダマされて)写真置き場にしていたので、かなりの数の画像があり、それらをアップロードし直して、サムネイルを作って、本文のリンクを修正して、という気の遠くなる作業はやりたくねえや、ということで、その辺りを自動化するために作ったのがこれ。

注意点とか

Yahoo Blogの画像付きエントリーをMovableTypeインポート形式に出力 ウェブブラウザでスクリプトにアクセスして表示される画面で、「Next Entry」欄にエントリーのURLを入力して送信すると、そのエントリーのHTMLソースを読み込み、本文中にあるJPEG画像のオリジナル(最拡大版)を保存し、そのサムネイルを作成し、リンクなどを書き換えた本文、題名、日付、及び「次の」エントリーのURLを入力フォームと、現状でのプレビューを表示します。プレビューを確認し、必要に応じてフォームの各フィールドに編集を加えた上で、「Export Current Entry」をチェックして送信すると、MovableTypeのインポート形式ファイルを出力し、「次の」エントリーに移動します。以下繰り返し。
JPEG画像のファイル名は、日付+同日のエントリーの連番+同一エントリー内の画像の連番で、サムネイルには「-thumb」が付きます。
文章にすると判りづらいな、これ。つうかぶっちゃけ作ってから随分経つので、かなり忘れてるし。

» 「Yahoo Blogの画像付きエントリーをMovableTypeインポート形式に出力」の続きを読む

Category: ウェブ制作
Posted 2006年01月13日 23:06

引越し完了

他人様に伝えたいことなど微塵もありゃしない、ホントに単なる日記エントリー。

xrea/value-domainでドメイン名を取得すると、50MBのウェブスペース(広告は強制表示)の使用権が付いてくる。ここのドメイン名を取得して、しかし50MBではあまり使い道がないので放置していたのだけど、PHPが使えるということで、PHPスクリプティングのお勉強で作り始めたPCサイト->携帯変換スクリプトの実験場にすることにして(開発だけならローカルホストでいんだけど、それではケータイからアクセスできない)、後日に、ドキュメントの管理にMovable Typeを設置したりしていた。
このスクリプト、所詮お勉強で作り始めたものなので、当初は公開する気なんてさらさらなかったのだけど、それなりに動くようになり、一方世の中には、これを作り始めたときのおいらのように、自身のサイトに設置できる同種のソフトが意外にもないことに困惑しているひとがいる気がするので、方針を変更して配布しちゃうことに。
さて、しかしそうなると広告がウザイ。この手のレンタルサーバの仕組みを知らないひとには広告収入目当てのサイトに見えてもしょうがないし、そもそも独自ドメインなのでパっと見ではxreaとかわからない。てなことでxreaの思うツボで、有料の広告免除オプションを検討し始めたのだけど、広告免除にするとディスク容量も1GBに増える。トータルでも数千行のスクリプトとそのドキュメントだけじゃあ1GBも要るわけない。
一方、exblogとYahoo Blogに不満で引っ越した筈のlivedoor Blogは、開設した当初は許容範囲だった使い勝手が、以降何度かの仕様変更を経て最悪な感じになっていたので、ディスク容量が増えるなら、日記もここに移転するかと。Movable Typeも設置済みだし(無料版の使い勝手を最悪にしておいて有料版に移行させようという、livedoorの思うツボにははまらず)。

で、さすがにこれ以上の移転はないだろうから、以前のエントリーも全てここに移すかと。しかし、livedoorとYahooは画像を多用している、というか画像がメインのエントリーが大半で、画像をアップし直して各エントリーのリンクなどを書き直すのはシャレにならない作業なわけで。地道にせっせと精進すればいいわけだけど、B型にそんなことができるわけはなく。
てなことでB型はなにをするかというと、移転を自動化するプログラムを組むのである。B型の皆さまには容易にお察しいただける通り、それで移転に要する時間が短縮されるかというとそんなわけはなく。むしろ余計に時間がかかったりするのだが、いいんです、B型だから。

てなことで、livedoorとYahooについては、画像をここにコピーしてリネームして、リンクなどを修正したエントリーをエクスポートするプログラムを作り。一方exblogは画像もエントリーも少ないので、こちらはlog2mtでエクスポートしたものを手作業で修正し。全てのデータをマージしてMovable Typeにインポートし、細部を調整して終了。
てなことで無事に引越しが完了すますた。といっても、一部のエントリーは闇の彼方に葬ってたりしますが。
Movable Typeでは、カテゴリーに階層構造を持たせ、ひとつのエントリーに複数のカテゴリーを指定できるので、目次はカテゴリーをフィーチャーしたものにしてみました。検索フォームと併せて過去記事は見つけやすい筈。
トップページの写真は、そのうちランダムとかになるでしょうよ。

Category: ウェブ制作
Posted 2006年01月13日 21:09

2005年12月27日

RightFields Plugin for Movable Type

備忘録。

MovableTypeをCMSとして用いてサイトを構築しようとする際の最大の制約は、通常は汎用データベースを用いるような、定型のカタログ的ページにあると思う。
例えば会社案内系のサイトに、その会社の商品カタログを用意しようとしたとき、汎用データベースを利用するパターンであれば、商品名とか価格とかのデータをそれぞれ個別のフィールドに登録していくわけだけど、いかんせんMTには、このような任意のフィールドを提供する機能がないわけで、仕方なく本文部分に全てのデータを羅列するしかなかった。もちろん、カテゴリー分類を除けば、個々の登録データに関連付けなんてありゃしない。

で、Kevin Shayさん作のRightFieldsというプラグインは、MTに任意のフィールドを追加できるというもので、これを使えば、MTを汎用データベース風に利用できるようになるのだと思われ(試してないので多分なんだけど)。
いや、別に別途にDB組みゃいいじゃん、というのはあるわけだけど、全てがMTの中で完結するというのは、構築する側も楽だし、なによりサイトの管理者にとって、全ての操作を同じ(MTの)インタフェースで行えるというのは、非常に大きなメリットだと思うのですよ。

Category: ウェブ制作
Posted 2005年12月27日 16:45

2005年10月21日

Yahoo検索

今月の初めにsearch.yahoo.co.jp(Yahooの検索ね)が従来のベータ版から昇格してリニューアルを果たした際に、制作中のPCサイト->携帯変換スクリプトでsearch.yahoo.co.jpにアクセスすると、日本語文字が全く表示されないという事態が起きた。FirefoxやIEからだと問題なしで、ふと思いついてiモード端末で(直接)見てみたらやはり同様だったので、こりゃ多分HTTPヘッダを見てるなと思って調べてみたら、Accept-Charset(HTTP_ACCEPT_CHARSET)にUTF-8かEUC-JPが含まれていなければ、日本語を解釈するクライアントだとは見做さないという強気な仕様(多分ワールドワイドで共通)になってやがることがわかり、さっそくPHPスクリプトにヘッダ出力を追加して無事に表示されるようになったのでありました。
そうですか、Netscape 3とかとは遂におさらばですか、天下のYahoo様が見限ったんなら、俺らもこれからは堂々と気にかけずに済むよな(とっくに気にかけてないけどな)、そりゃあいいことだ、とか思ってたわけです(仕様の異なるウェブブラウザがあれこれ存在するのはウェブサイトの制作側からすると甚だ迷惑。いや、ウンコ仕様のウェブブラウザが市場を寡占してるのも迷惑なんだけどさ)。

で、今日たまたま所用で、Accept-Charsetをナシにしてsearch.yahoo.co.jpにアクセスしてみたら、なにごともなかったようにちゃんと日本語文字が表示されるように変わってやんの。
さては天然記念物のネスケ3保存協会とかから圧力がかかったかとググってみたら(ググるのである、Yahooではなく(笑)、おいらと同様に困っていたかたが当時それなりにいらした模様。どうやら一部タブブラウザ方面とかも困ったことになってたらしい。
結構苦情があったのやら。いやもちろん、直前のベータ版からいきなり仕様を変更して正式版ですとかヌかしちゃったYahooは、少なくともその点では非難されてもしょうがないんだけどさ。なんにせよ、せっかく時代遅れのウェブブラウザを殲滅するよいきっかけだったのに、残念。

Category: ウェブ制作
Posted 2005年10月21日 22:20

2005年10月20日

PHP4とPHP5を切り替える

特にローカルの開発 & テスト環境では、時折(あるいはしばしば)異なるバージョンのPHPに切り替える必要が出てくるわけですが。以下はxamppなどを使わずに、ベタにインストールしたWindowsのApache 2.0.xモジュール版PHPで、異なるバージョンを切り替える手順。まとまった解説が見当たらず、また未だに「iniとdllはWindowsのシステムフォルダへ」と書いてあるドキュメントもあるので、自分用のメモ。


PHP4では、php.iniやDLLをWindowsのシステムフォルダにコピーして使用する方法が推奨されていましたが、この方法ではファイルが分散するため管理が煩雑になり、例えばバージョンアップ時の作業が面倒であったり(どのファイルをどのフォルダにコピーしたかいちいち覚えてられないっつうの)、異なるバージョンのPHPを切り替えて運用しようとすると、その都度php.iniや拡張モジュール用の外部DLLをコピーし直さなければなりません。
一方PHP5では、これらのファイルもPHPのインストール先のフォルダにまとめて運用する方法が推奨されています。PHP4とPHP5を共にこの方法で運用できるように設定することで、異なるバージョンのPHPを、より簡単に切り替えて運用することができます(必然的にバージョンアップも容易になります)。

以下は、フォルダのリネームとhttpd.confの修正だけで、PHP4とPHP5を切り替える例です。
具体的には、「C:\php」で運用するように設定したPHP4とPHP5を別の名前のフォルダに用意しておいて、使用する側を「C:\php」にリネームし、httpd.confのLoadModuleディレクティブのコメントを付け替えて、Apache 2.0.xを再起動することで切り替えます。

PHP5のインストール

  1. php.netのダウンロードページからダウンロードしたPHP5のZIPパッケージ版(インストーラ版の使用は相変わらず推奨されていません)をC:\phpフォルダに展開し、作成されたファイルのうち、php.iniの推奨設定版であるphp.ini-recommendedファイルをphp.iniにリネームします。
  2. Windowsのシステム環境変数「PATH」に、C:\phpを追加します。これは、PHPのコアDLLと拡張モジュール用の外部DLLを、Windowsのシステムフォルダではなく、C:\phpフォルダに置いておくために必要な設定です。
    Windowsのシステム環境変数を設定するには、例えばWindows XPの場合は、マイコンピュータをマウスの右ボタンでクリックして表示されるメニューから「プロパティ」を選ぶか、コントロールパネルの「システム」をダブルクリックして表示される「システムのプロパティ」で、「詳細設定」タブの「環境変数」ボタンをクリックします。表示される画面で、システム環境変数の項目の中から「PATH」を探し、現在の値に「C:\php」を付け加えてください。
  3. Apache 2.0.xのhttpd.confに以下の行を追加します。
    LoadModule php5_module c:/php/php5apache2.dll
    PHPIniDir "C:/php"
    AddType application/x-httpd-php .php
    肝は「PHPIniDir」ディレクティブで、この指定によって、php.iniをWindowsのシステムフォルダにコピーしないで、任意のフォルダに置いておくことができます。

必要な設定は以上です。Apache 2.0.xを起動し、phpinfoの「Configuration File (php.ini) Path」項目が「C:\php\php.ini」となっているか確認してみてください(phpinfoを表示するには、「<?php phpinfo() ?>」と書いた、拡張子が「.php」のファイルをApache 2.0.xの公開フォルダに作成し、ウェブブラウザでそのファイルのURLにアクセスします)。

PHP4のインストール

PHP4のインストール手順はPHP5とほぼ同じですが、フォルダの構成を、ZIPパッケージを展開した初期状態から若干変更する必要があります。

  1. Apache 2.0.xを停止し、PHP5をインストールしたC:\phpフォルダを、C:\php5にリネームします。
  2. 新たにC:\phpフォルダを作成し、PHP5の場合と同様に、PHP4のZIPパッケージ版をphp.netのダウンロードページからダウンロードして、C:\phpフォルダに展開し、php.ini-recommendedファイルをphp.iniにリネームします。
  3. C:\phpフォルダ内にある「dlls」フォルダと「sapi」フォルダ内の全てのファイルをC:\phpフォルダに移動し、空になった「dlls」フォルダと「sapi」フォルダは削除します。
  4. PHP5のインストールの際に追加したhttpd.confの行を、以下のように修正し、PHP4用のLoadModuleディレクティブを追加し、一方PHP5用のLoadModuleディレクティブをコメントアウトします。
    #LoadModule php5_module c:/php/php5apache2.dll
    LoadModule php4_module c:/php/php4apache2.dll
    PHPIniDir "C:/php"
    AddType application/x-httpd-php .php
    PHP4モジュールのパスが「c:/php/sapi/~」ではないことに注意してください。

必要な設定は以上です。Apache 2.0.xを起動し、phpinfoで、PHPのバージョンと「Configuration File (php.ini) Path」を確認してみてください。

PHP4とPHP5を切り替える

例えば、PHP4からPHP5に切り替えるには以下のようにします。

  1. Apache 2.0.xを停止し、C:\phpフォルダをC:\php4に、C:\php5フォルダをC:\phpに、それぞれリネームします。
  2. Apache 2.0.xのhttpd.confで、PHP4用のLoadModuleディレクティブとPHP5用のLoadModuleディレクティブのコメントを付け替えます。
  3. Apache 2.0.xを起動します。

なお、メジャーバージョンが同じPHP同士ならhttpd.confの修正は不要なので、フォルダのリネームとApache 2.0.xの再起動だけで切り替えられます。

Category: ウェブ制作
Posted 2005年10月20日 19:49

2005年08月24日

Sumibi ~ RCDラ・コルーニャのインタートト決勝敗退に寄せて(ウソ)

昨年の今頃アコルーニャに旅行したときには、日本語IMEがインストールされていない現地のインターネットカフェでは、romaji.netのサービスを利用して、アルファベットのローマ字入力をかな漢字に変換していた(このサービスは、当時はまだ無料で利用できたのだけど、その後間もなく有料化された)。
その後、主にajaxの実装例として、アルファベットのローマ字入力をかな漢字に変換する試みを幾つか見かけたのだけど、今しがた、SourceForge.jpのプロジェクトをだらだら眺めていて、Sumibiというプロジェクトを知った。面白いのは、変換エンジンが「Internet上のドキュメントを読み込んでひとりでに賢くなる」んだそうな。へええ。肝心の使い勝手や変換速度も、先達に比較してとても良好。
安直に思いつく用途は、やはり海外のネットカフェでの利用なんだけど、そのときには自分の利用状況に合わせたクライアントを用意してみると楽しいかもね。

Category: ウェブ制作
Posted 2005年08月24日 17:33

Aoaka Style Valid Aoaka