2009年10月02日
OpenSocialの入門記事を『システム開発ジャーナル』vol. 11に執筆しました
毎日コミュニケーションズ発行のシステム開発ジャーナル vol. 11の特集記事『OpenSocial Web & モバイル開発入門』を執筆しました。全7章、56ページに及ぶ特集で、mixiアプリを中心にOpenSocialアプリを精力的に開発されている空飛ぶの赤星琢哉さんと、mixiに先駆けて日本で初めてモバイル版のOpenSocialプラットフォームをスタートさせたgumiの酒徳千尋さんとの共同執筆です。これからOpenSocial/mixiアプリの開発を始めてみようかというかたにお読みいただければ幸いです。
毎日コミュニケーションズ
売り上げランキング: 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ピクセル幅で描画されないように)表示させることができます。
- ViewPortを記述する
- DOCTYPE宣言にXHTML Mobile Profileのものを採用する
- .mobiドメインでホストする
逆に.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テストを表示してみた図。
CSSソースがダラダラ表示され、肝心のスマイリーはまったく描画されなかった従来よりは、一歩前進ではないかと、無理やり前向きに評価してる。
Acid3はさすがに略。
参考までに、以下はiPhone実機のMobile Safariで、同じAcid2テストを表示してみた図。
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属性なんてないわけで、何らか新たな定義がない限り使えない。
で、ググってみると確かにドラフト仕様はあった。
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月に有効期限切れになってる。
案の定おんなじように思ってるひともいた。
結局この話はなかったということでFAなのかなー?
- シックスアパートのページに書かれてるまんま「x:media="handheld"」と書いちゃってるフィードも見受けられるけど、それはないわ。
- シックスアパートのページでは、RSS 2.0の例ではXHTMLを組み込んで済ませてる。これはもちろん仕様的にはOKなんだけど、キモい。RSS 2.0はそもそもの仕様がアレなのでしょうがないかもしれないけど、Atomでこれはやりたくないなー。
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)の仕様。
- デフォでは図のように、左側に構造図を、右側にRFC仕様を表示します。左上の「仕様の全文を表示」リンクをクリックすると、仕様の全文をダラダラと表示します。
- 構造図モードでは、クリックした箇所に応じた仕様のセクションを右側に表示します。右上の「戻る」と「進む」はブラウザのボタンと同じイメージ。
- 構造図中で名前の後ろに「?」と「*」がある要素や属性はオプションです(記号がないものは必須)。「?」はその場所に1個だけ、「*」は複数登場できます。ただしこれは原則で、オプションであっても条件次第で必須となるとか、あれこれ例外があるので要注意。例えばatom:authorはオプションですが、ドキュメントのどこかに少なくとも1個はないとダメです。あるいは例えば、atom:contentのないatom:entryには<link rel="alternate" href="~">が必須です。詳細は仕様を熟読してください(主なルールは仕様のセクション4.1.1と4.1.2にまとめられています)。
- 構造図中で「atomCommonAttributes」となっているブロックは、その中の属性がAtomの共通属性(仕様のセクション2)であることを表しています。決して<atomCommonAttributes xml:lang="ja"/>とか書けという意味ではありません(笑)。同様に「atomなんとかConstruct」となっているブロックは、共通の構造体(仕様のセクション3)です。
- RFC仕様の記述に合わせて、Atomの要素はすべて「atom」という接頭辞を付けて表記してますが、通常Atomの要素はデフォルトの名前空間に属することになる筈で、その場合接頭辞はもちろん不要です。
以下は余談。
最初はRSS 0.9x/2.0とRSS 1.0とAtomとの簡単な比較表を作ろうと思ってたのでした(そして、RSS 1.0やAtomの仕様は、杜撰な鷹揚なRSS 0.9x/2.0のそれと比べて厳格なので、各フォーマットを共通のデータソースから生成しようとする場合には、データソースの準備は厳格な側に合わせてやらないとワヤになりまっせ、という講釈を垂れようとしていた)。
で、しかしRFC4287を眺めてたら、Relax NG(のコンパクト構文)スキーマによるストラクチャー表現を、ブロック図に置き換えて操作できるようにしたら面白いかもと思い立ち(この時点で比較表を作ろうという当初の目的は潰える)。しかし要素を並べただけではアレなので説明を加えるにしても、RFC原文のコピペだけでは不親切かなということで、ついでに日本語訳も用意してみた次第。
既存のRFC4287の日本語翻訳
- http://blog.good-day.net/~iwai/wiki/wiki.cgi?page=Atom+Format+%CB%AE%CC%F5
- http://momdo.s35.xrea.com/spec/rfc4287j.html
- http://www.futomi.com/lecture/japanese/rfc4287.html
- http://www.7key.jp/rfc/4287/rfc4287.html
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位。
- 前略プロフィール
『前略プロフィール』は、誰でも手軽に携帯電話・パソコンの両方に対応した、自己 ...
pr.cgiboy.com/ - FC2プロフ - あなた専用のプロフィールを作ってみよう!!
あなた専用のプロフィールが簡単に作れちゃう!!プロフィールを作ってみよう!!
pr.fc2.com/ - Amazon.co.jp: プロフィール: デューク・ピアソン,ジーン・テイラー ...
Amazon.co.jp: プロフィール: デューク・ピアソン,ジーン・テイラー, ...
www.amazon.co.jp/プロフィール-デューク・ピアソン/d... - 佐野夏芽プロフィール
タレントプロフィール ・ フォトダイアリー ・ タレント募集 ・ メールマガジン登録 ...
www.metalbox.co.jp/work/sano/pcolum... - みんなのプロフィール
みんなのプロフィール 名前をクリックするとプロフィールを閲覧できます。 ...
www.yukinosake.com/cgi-bin/profile/...
しかし、少なくとも本日ただ今現在、「PREF」という名称のcookieを削除してから上記のモバイル版のアドレスを開いてみると、以下のようにまったく違う結果が表示される。1位は関西のデリヘル。ちなみにこのcookieがない状態で100位(10ページ)まで検索しても、前略プロフは出てこない(以下にもあるような、前略を騙るサイトは出てくる)。
- 大阪・兵庫・京都・奈良・和歌山巨乳ロリ・ギャル系専門デリバリーヘルス ...
プロフィール南大阪 ・ プロフィール京都 ・ プロフィール兵庫 ・ プロフィール奈良 ・ プロフィール和歌山 ...
www.pro-file.jp/m/ - 携帯(ケータイ)無料プロフ作成フリーサイト「My・ぷろふぃーる」
完全無料でマイプロフィール交換画面を作成できる携帯電話専用プロフ提供フリー ...
vl-o-l.jp/ - プロフィール
プロフィール. 名前:すぬーぴー. 種別:ビーグル犬の. ぬいぐるみ. 年齢:不明 ...
penguinmaru.fc2web.com/i/profile.html - 前略プロフィール by aimew
プロフガイドは数あるプロフィールサイトを厳選してご紹介!もちろんプロフを通じて新しい ...
aimew.jp/zennryaku/ - 前略プロフィール by aimew
JC、JKに人気のあるプロフィールサイト♪. 前略出会い系 ...
aimew.jp/zennryakud/ - 携帯無料プロフ作成 チェキ!プロフィール
チェキ!プロフィールでは簡単☆無料でプロフィールサイトを作成できます!
chpr.jp/ - プッチギャル
女の子コメント:いちゃx2楽しい時間を過ごしましょうねぇ(*^^)v ...
www.kobe-pucchigal.com/m/gal/k-view... - 京都デリヘル/プッチギャル
キャッチコピー:☆京都に渋谷系GAL誕生☆ドエロEカップに大興奮! ...
www.kyoto-pucchigal.com/m/gal/k-vie...
さて、cookieの有無で検索結果が変わるということは、cookieを喰わないドコモの端末ではどうなるかというと、もちろん上と同じ、1位がデリヘルという結果になる。
で、ドコモは4月1日からiMenuのトップ画面にGoogleと連携した検索機能を追加し、Googleの検索エンジンにより、携帯電話向け一般サイト、PCサイトの検索結果も表示されるようになったのだけど、そのiMenuの検索フォームから「プロフィール」を検索してみた結果が以下。
- 携帯(ケータイ)無料プロフ作成フリーサイト「My・ぷろふぃーる」
完全無料でマイプロフィール交換画面を作成できる携帯電話専用プロフ提供フリー ...
vl-o-l.jp/ - プロフィール
プロフィール. 名前:すぬーぴー. 種別:ビーグル犬の. ぬいぐるみ. 年齢:不明 ...
penguinmaru.fc2web.com/i/profile.html - 前略プロフィール by aimew
JC、JKに人気のあるプロフィールサイト♪. 前略出会い系 ...
aimew.jp/zennryakud/ - 京都デリヘル/プッチギャル
キャッチコピー:☆京都に渋谷系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」を検索した結果のページでそのブックマークレットを選択してみてください。下図のような表示が出てきたら正解。以上の操作がメンドクセーひとはここをクリック(笑)。

「検索プラグインを追加」ボタンをクリックすると、確認ダイアログが表示され、プラグインを追加できるわけですが、お気に召さない項目があれば適宜編集していただければと存じます。各項目の説明は、その入力欄をクリックすると説明が出てくる筈。編集後には「確認・更新」ボタンをクリックしてください。
「名前」は、ウェブブラウザはこれでプラグインを管理してるので、既に登録済みのプラグインと同じ名前は付けられません。
「アイコン」は、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クラス
SimpleXML+HTMLParser or Tidy+HTTP_Request+Cache_Liteの組み合わせで、リモートサイトから取得したHTMLソースを整形して、SimpleXMLオブジェクトに変換するライブラリでございます。サーバサイドはもとよりクライアントサイドのAjaxでも、DOMやXPathなどを用いたオブジェクト操作によるScrapingが可能になります。要SimpleXMLなのでPHP5専用(もっとも、SimpleXMLをDOM XMLに置き換えればPHP4でも同じようなことはできますが)。
ええっと手っ取り早く、以下にアクセスしてフォームに適当なURLを入力してみてください。
下図のようにURLがダラダラとリストされれば正解。

ここでリストされる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」ボタンをクリックすると、プレイリストの内容とプレイヤーの見栄えが変わるという寸法です。
- ボリュームスライダーの左隣にあるフルスクリーンボタンをクリックすると、ビデオをPCの画面全体に拡大して再生します(ただし、バージョン9.0.28以降のAdobe Flash Playerがインストール済みであること)。
- プレイリストの各ビデオの右端にあるInfoボタンをクリックすると、YouTubeの、そのビデオのページに移動します。
- キーワード検索ではなく、自分の好きなビデオを再生したい場合には、まずはビデオをYouTubeのMy Favoritesに登録してください。そしてながらTubeで、入力フォームに自分のYouTube IDを入力して、その下のラジオボタンのうち「username (to play his/her favorites)」にチェックを付けてください。これで「Update」ボタンをクリックすると、My Favoritesに登録したビデオがリストされます。
これまで見てきた、ページの右側に出てくるヤツは、ウェブやブログに貼り付けることを想定した「バッジ」版なのですが、一方で下図のように、これをサブウィンドウで表示して、デスクトップで鑑賞する用途を想定した「バー」版もあります。
ながらTubeの、バーの説明にある「Nagara Tube Bar (Bookmarklet)」というリンクをクリックすると、バッジ版と同じ内容が、下図のようにサブウィンドウに表示されます(タブブラウザではポップアップウィンドウの設定を変更する必要があるかもしれません。IE7ではタブブラウズの設定中の、ポップアップの発生時の動作を確認してください)。このリンクはブックマークレットにもなるので、ブックマークやツールバーにこのリンクを登録しておくと、以降はそれを選択するだけで同じ設定のバーを表示できます。
さて。
とか書いときながら実際にブログとかに貼られまくられちゃったりするとそれなりの負荷になるわけで。いつものようにソースを晒してるので、ご利用は自鯖でどーぞ。ただし、自作の部分はいつも通りフリーソフトウェアですが、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
- オリジナルの歌詞は本家ファンサイトや日本のファンサイトに掲載されています。
- 日本盤のCDリリースはお馴染みの「歌詞・対訳つき」なわけですが、KISSファンクラブの初代会長であるらしい青柳つとむという御仁の手になるこの対訳がヤバイ。Pureヤバイ。誤訳とか意味が通じないとかそういうレベルじゃない。もう全然別モノ。適当な聞き取り起こしをあてがわれたのだとしても、英語習いたての厨にやらせても、こんな訳にはなるわけない。もはや神の御業。
- 日本盤のシングルCDのオビに書かれたキャッチコピーは、「輝きは 目映いばかり 北の空」。俳句かよっ。
Technical things
- 字幕の編集はSubtitle Workshop。ハードサブ作成はVirtualDub+VobSub。
- こちらで使ったFlash Media Playerがバージョンアップして、SubRip形式(.srt)などの字幕ファイルを表示する機能が追加されたので(flashvarsの「captions」パラメータで字幕ファイルのURLを指定する)、最初はそれを利用しようと思ったのだけど、どうにも字幕の表示がズレまくる。ズレ具合が一定ではないのでタイムコードをずらして済ませられるわけでもなく、とは言えこれにタイムコードを合わせたものを作ろうとしても、Subtitle Workshopのような編集ツールが利用できるわけではないので手間がかかるし、プレイヤーが改修されたら使い物にならなくなる。そんなことで、しかたなくハードサブで済ませることにしたわけですよ。無念。
- ちなみにFlash Media Playerが受け付ける日本語入りの字幕ファイルの文字エンコーディングはUTF-8で、一方Subtitle Workshopで作成した字幕ファイルの文字エンコーディングはShift_JISなので、プレイヤーに読み込ませる際は、あらかじめ文字エンコーディングを変換しておく必要がある。
Category: ウェブ制作
Posted 2007年03月09日 20:10
2007年03月06日
野菜小屋の地図をGoogle Maps APIで作ってみるテスト
飛田給駅の利用者なら、表通りでも派手に宣伝しているので大丈夫でしょうが、そうでなければ知らないひともいるかもしれないので、野菜小屋の地図を用意してみますた。
という口実で、GoogleマップのDOM APIで遊んでみたテスト。以下はトーキョーとは無関係。
» 「野菜小屋の地図をGoogle Maps APIで作ってみるテスト」の続きを読む
Category: FC東京, ウェブ制作
Posted 2007年03月06日 22:49
2007年01月12日
携帯JavaアプリのFlickrビューアがお蔵入りになった件
信頼すべき情報筋によれば、“ポケットflickr”というコードネームで昨年末にコソコソ製作されていた、携帯電話向けJava実行環境用の、Flickrのビューア・アプリケーションがお蔵入りになった模様。
製作者はお蔵入りの理由について、「飽きたから」と語っているという。参考までに、製作者の血液型は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」でした。以下のハナシは原則、その頃のものです。始まったばかりのサービスなので内容はどんどん変更されていく筈で、現状は違ってる可能性がたぶんにあることにご留意ください。
基本的な使い方はいたってシンプル。
- 変換したいビデオを、ローカルからアップロードするか、URLで指定する。
指定できるURLは:- ビデオファイルのURL。
- ビデオファイルのURLが書かれたウェブページのURL(複数ある場合はあらためて選択する)。
- YouTubeやGoogleビデオなど、対応している動画配信サービスのウェブページのURL。
- ビデオがいったんHey! Watchに転送されるので、完了するのを待つ(転送状況は随時確認できる)。
- 転送が完了したら、変換したいフォーマットを選んでエンコードする。
ただし、Hey! Watch全体で、同時に行えるエンコード数には制限がある。これは「スロット」という単位で表現されており、「空きスロット」があれば直ちにエンコードが行われるけれど、そうでなければ待たされる(エンコードの状況も随時確認できる)。
アカウントには、無料の「Free」と有料の「Watcher」(なんでそういう名前なのかは不明)があり、Watcherアカウントは$4.99/月で、「まとめて払えばお得」なプランもあり。ちなみに支払い方法は、現時点ではPayPalのみ(イケてないところ、その1)。
ふたつのアカウントの違いが具体的に書かれたページはログインしないと見れないので、以下にサクっとまとめてみた。
| 制限 | Free(無料) | Watcher($4.99/月) |
|---|---|---|
| 1ヶ月間に可能なエンコード回数 | 10回 | 100回 |
| エンコードフォーマットのカスタマイズ | NG | OK |
| 転送した(オリジナルの)ビデオの保存期間 | 6時間 | 12時間 |
| エンコードしたビデオの保存期間 | 12時間 | 24時間 |
| 同時に可能な転送数 | 1 | 3 |
| 同時に可能なエンコード数 | 1 | 3 |
| ビデオあたりの再生時間の制限 | 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日
第一次ハラ東京最後の日
天皇杯のハナシを書いてて思い出した、第一次ハラ東京最後の試合となった、松山での天皇杯レッズ戦で撮影していたビデオを公開しておこうかと。
- 以下のビデオは、少なくとも5年ほど前のPCでは、おそらくろくすっぽ再生されやしないと思われ。
- ファイルがバカデカく、YouTubeがクソ遅いので、いったんFLVをダウンロードして見たほうがいいと思われ。
試合後の挨拶
ガスサポの行進
というフリして、動画を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の2007/01/24版でも確認。
- こちらを参考に、本文にAタグやBBCodeが含まれる場合、及びメール欄に@が含まれる場合も弾く処理を追加。
# 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:29 | 103 | c-71-230-86-217.hsd1.pa.comcast.net | US | |||||
| 11/22 19:13 | 600 | bzq-84-110-225-57.red.bezeqint.net | IL | |||||
| 11/22 19:13 | 600 | bzq-84-110-236-82.red.bezeqint.net | IL | |||||
| 11/22 19:12 | 600 | bzq-84-110-231-119.red.bezeqint.net | IL | |||||
| 11/22 19:12 | 600 | bzq-84-110-233-25.red.bezeqint.net | IL | |||||
| 11/22 16:48 | 103 | 82.137.247.132 | yes | SY | ||||
| 11/22 15:00 | 103 | www.farmington.k12.mi.us | yes | US | ||||
| 11/22 13:22 | 103 | 84-123-102-217.onocable.ono.com | ES | |||||
| 11/22 12:11 | 600 | 200.29.137.217 | yes | yes | CL | |||
| 11/22 12:10 | 600 | 218.236.45.155 | yes | yes | yes | KR | ||
| 11/22 12:05 | 600 | S01060040ca37ccf6.cn.shawcable.net | yes | yes | CA | |||
| 11/22 12:05 | 600 | avquarantine.sec.kq.no | yes | yes | NO | |||
| 11/22 11:23 | 103 | proxy4-jan.integrity.com | yes | US | ||||
| 11/22 10:17 | 103 | 89-149-205-145.internetserviceteam.com | yes | DE | ||||
| 11/22 09:51 | 600 | 218.236.111.150 | yes | yes | yes | yes | KR | |
| 11/22 09:37 | 103 | 82.137.247.131 | yes | SY | ||||
| 11/22 07:50 | 103 | 94.190.189.72.cfl.res.rr.com | US | |||||
| 11/22 06:21 | 600 | ool-44c0fe41.dyn.optonline.net | US | |||||
| 11/22 06:02 | 103 | adsl-75-52-193-66.dsl.chcgil.sbcglobal.net | yes | US | ||||
| 11/22 04:11 | 600 | bzq-84-110-226-237.red.bezeqint.net | IL | |||||
| 11/22 02:27 | 103 | ulbcenter-04-b07.it-datacntr.louisville.edu | US | |||||
| 11/22 01:08 | 103 | riy01che02.ae.net.sa | yes | yes | yes | SA | ||
| 11/22 00:38 | 103 | 64.8.149.34 | US | |||||
| 11/21 23:56 | 600 | bzq-84-110-251-251.red.bezeqint.net | IL | |||||
| 11/21 23:56 | 600 | bzq-84-110-252-72.red.bezeqint.net | yes | IL | ||||
| 11/21 23:55 | 600 | bzq-84-110-241-44.red.bezeqint.net | IL | |||||
| 11/21 23:31 | 600 | 220.119.158.14 | yes | yes | yes | KR | ||
| 11/21 23:30 | 600 | 86.35.202.101 | yes | yes | RO | |||
| 11/21 23:29 | 600 | 211.207.215.84 | yes | yes | KR | |||
| 11/21 23:25 | 600 | 210.113.30.208 | yes | yes | yes | yes | yes | KR |
| 11/21 22:53 | 103 | 63-109-248-28.reverse.newskies.net | yes | yes | yes | US | ||
| 11/21 21:15 | 103 | 89-149-205-145.internetserviceteam.com | yes | DE |
上表の「#1~5」の欄は、各ホストについて以下の各DNSBLサービスでの登録の有無です。
- 2ちゃんねる BBQ - niku.2ch.net
- SpamLookup - bsb.spamlookup.net
- The Spamhouse Project - sbl-xbl.spamhaus.org
- SpamCop.net - bl.spamcop.net
- RBL.JP - all.rbl.jp
ご覧の通り、どのブラックリストにも登録されていないホストが結構あり、プロのスパム屋に狙われたら、やっぱしDNSBLでの規制だけでは不十分なんだよね、ということですな。
なお、2ちゃんねる BBQはDSBLでの登録状況も併せて応答するので、上表ではDSBLは端折ってます(なので、このふたつを併用するのは無意味です)。また、ちなみにどのホストも、2ちゃんねる BBX(bbx.2ch.net)には登録されていなかったので、こちらも上表では端折ってます。
参考になったり興味深く拝見したページ
- The Spamhouse Project: ROKSO(既知のスパム屋のリスト) - GIGAZINEの記事「世界中のスパムメールの80%がこの200人によって送信されている」の元ネタの元ネタ。
- The Spamhouse Project: Worst Countries - 本日現在のトップ10チャートでは、ニッポンがロシアを抑えて堂々3位!
- 自分自身のためのものづくりメモ: 掲示板spam対策
- 不正アクセスの発信地の国別統計をとろう!
- ぜろちゃんねる用BBQプラグイン
- opm.blitzed.org has shut down - DNSBLのひとつでしたが、鯖屋とトラブってお亡くなりになられたそうです。
» 「ぜろちゃんねる(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側に不具合があるための制限です。(追記参照)
コメントを投稿するとエラーになります。閲覧権限が「予定の時間枠のみ」のカレンダーは表示されません。
動作要件とか
- PHP 4.3.9/5.0.1以降。OpenSSLとXML(expat)とmbstring必須。.htaccessでphp_flagが使えないと困るかも。
- カスタマイズを想定しているファイル(設定ファイルとHTMLテンプレート)の文字エンコーディングはUTF-8(BOM無しのUTF-8N)なので、対応のテキストエディタが必要です。
- ウェブアプリなのに複数ユーザでの利用はできない建前になってます。設置者おひとりでご利用ください。
これは、ウェブアプリで使用すべきとされているGoogleアカウントの認証方式(AuthSub)がiモードやEZwebなどの携帯電話ブラウザでは利用できないので、しょうがなく、使用すべきではないとされている方式(ClientLogin)を用いているためです(Googleアカウントの認証方式の解説はアカウント認証の概要をご覧ください)。 - 簡単に設置できるように、アーカイブにはPEARの各ファイルも突っ込まれてたりするかもしれませんが、別途にインストール済みなら、もちろん削除してください。なお、PC2Mをご利用の皆さまにおかれましては、それ用に改変したHTTP_Request(pearpack.zipにあるHTTP/Request.php)は、こいつには使えませんのでご注意ください。
設置手順
このアプリ自体の認証は、携帯電話の端末ID(製造番号とかサブスクライバIDとかシリアル番号とか)とパスコード(暗証番号)で行います。(端末IDが送信される状態で)ログインフォームに暗証番号を入力するだけという、ケータイフレンドリーな認証ですね。
そういうわけで、最初に設定ファイル(Config.inc.php)に、端末IDとパスコード、そしてGoogleアカウントのメールアドレスとパスワードを登録しておく必要があります。
- アーカイブ内の各ファイルをサーバの任意のディレクトリにアップロードし、「data」ディレクトリのパーミッションを707など、書き込み可能なものに変更します。
- 携帯ブラウザで_check_auth.phpにアクセスし、パスコードを入力して表示される内容をメールなどでPCに送ります。この内容を、Config.inc.phpファイルの「$auth_db」とある箇所に登録してください。「SERIAL」と表示される内容を$auth_dbの「serial」欄に、「PASS」と表示される内容を$auth_dbの「password」欄に、それぞれ登録します。
- 引き続き$auth_dbの、「google_username」欄にGoogleアカウントのユーザ名(@記号以降のドメイン名までを含むメールアドレス)を、「google_password」欄にそのパスワードを登録し、Config.inc.phpファイルをサーバにアップロードします。
- PCや携帯のブラウザでgcal.phpにアクセスして、期待通りに動作するか確認してみてください。この時点ではまだ、認証はパスコードのみで、端末IDでの認証は行っていないので、PCのブラウザでもアクセスできる筈です。
- 最後に、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とは別にライセンスされる点ご注意ください。
- HTMLTemplate.class.phpファイルは、鮎川寛さんが制作された、HTMLテンプレートを操作するクラスライブラリ、HTML template for PHPです。
- XMLParseIntoStruct.phpファイルは、orbitphreak at yahoo dot comさんによる、XMLパーサ関数のドキュメントのUser Contributed Notesへの投稿が基になった、XMLをハッシュ構造に展開するクラスライブラリです。
- Googleディレクトリ内の各ファイルは、自前のGData API用クラスライブラリのものです。
- ClientDetect.class.phpファイルと_check_auth.phpファイルは、自前のPCサイト->携帯変換スクリプトの一部です。前者は携帯端末の判別を行うクラスライブラリで、DevInfo_DoCoMo.inc.phpファイルとIPRange.inc.phpファイルはこのクラスで使用する定義ファイルです。
- HTTPディレクトリとNetディレクトリ内の各ファイル、及びPEAR.phpファイルは、Richard HeyesさんとAlexey BorzovさんによるPEARのHTTP_Request、及びその依存パッケージです。
» 「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をご覧ください。
- アーカイブの内容
-
- 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
- Google
テストアプリその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
Google Calendar Data API
アカウント認証の概要
認証を要するGoogleの各サービスAPIへのリクエストを行うアプリケーションは、ユーザIDとパスワードそのものではなく、アカウント認証APIによって発行される、トークン(token)と呼ばれるその代替データを送信します。トークンはその有効範囲内で繰り返し利用可能なので、アプリケーションはアクセスの都度トークンを取得する必要はありません。
アカウント認証APIにはClientLoginとAuthSubがあります。
- ClientLoginはPCのデスクトップアプリケーションなどでの利用を想定したものです。ユーザIDとパスワードはアプリケーションが直接取り扱います。トークンは、アプリケーションがユーザIDとパスワードを送信して発行されます。
- AuthSubはウェブアプリケーションでの利用を想定したものです。アプリケーションはユーザIDとパスワードは扱いません。トークンは、ユーザがGoogleアカウントのウェブサイトで、そのアプリケーションに対してアクセスを許可する操作を行い発行されます。
AuthSubでは、ウェブアプリケーションは、ユーザをGoogleアカウントのウェブサイトに誘導して、アプリケーションに対するアクセスの許可を依頼します。このときのURLには、「next」パラメータに、AuthSubからのレスポンスを処理するURLを指定しておきます。
以下の画像は、ユーザに表示されるログインフォームとアクセス要求の確認フォームの例です。アクセス要求の確認フォームでユーザが「アクセスを許可」をクリックすると、「next」パラメータで指定したURLに対してリダイレクトが行われます。
注意
- 現在のGoogleアカウントは、セッション管理をCookieで行っているため、例えばiモードなどの携帯電話用ウェブブラウザのように、Cookieが利用できない環境ではGoogleアカウントにログインできず、AuthSubも利用できません。
- Googleアカウントではない独自のアカウントを提供していたサービス、例えばBloggerなどについては、AuthSubは独自アカウントでは利用できません(独自アカウントをGoogleアカウントに移行すれば利用できます)。
なお、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
ポストデータの内容は以下の通りです。
| キー | 値 |
|---|---|
| ユーザ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
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のアクセス要求時に、既に制限数を超えるトークンが発行されている場合は、その旨のメッセージが表示されます。
以下の画像は、制限数を超えるトークンが発行済みの場合のメッセージと、トークンの確認と廃棄の画面です。確認と廃棄の画面で「アクセスを取り消す」をクリックしたトークンは廃棄され、無効になります。
クラスライブラリを使ったサンプルプログラム
以下の例では、まずトークンが有効かどうかの確認を行い、有効な場合はそのトークンを廃棄しています。
<?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"]
- Authorizationヘッダの値は、トークンを取得した認証APIがClientLoginかAuthSubかで異なります。
- VisibilityやProjectionの詳細はUsing the Google Calendar Data APIの“Calendar feed types”を参照してください。
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
- GDataフィードの形式が、規定のAtom 1.0の場合、日時表現形式はRFC3339ですが、PHP5では、strtotime関数はタイムゾーン指定を含むRFC3339形式の日時表現に対応しており、また、新たに追加された定数などによって、date関数などでの日時表現の生成も容易です。一方、PHP4のstrtotime関数は、タイムゾーン指定を含むRFC3339形式の日時表現には対応していないので、これをUnixタイムスタンプに置き換える必要がある場合は、独自の処理を用意することになります。
- GDataフィードを取得するURLのクエリー文字列に「alt=rss」を追加すると、フィード形式が、規定のAtom 1.0からRSS 2.0に変更されます。RSS 2.0は比較的以前からある形式のため、フィード解析に既成のパーサを利用する場合に、選択肢が広がるかもしれません。また、RSS 2.0の日時表現形式はRFC822ですが、PHP4でもこの形式については、strtotime関数はタイムゾーン指定を含む日時表現に対応しており、また、date関数での日時表現の生成も、フォーマット文字列に「r」を指定するだけで行えます。ただし、RSS 2.0はフィードの取得時のみに利用できます。イベントの追加や変更はAtom 1.0を利用します。
Category: ウェブ制作
Posted 2006年10月04日 22:53
2006年08月17日
HTMLを整形式のXML文書に修正するPHPクラス
ガーロ解任記念(無関係)。夏休みの宿題(嘘)。
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クラス
仕様とか制限事項
- このクラスライブラリを利用するにはPEARのXML_HTMLSax3、及びバージョン4.3.0以降のPHPが必要です。また、XML_HTMLSax3が扱える文字エンコーディングはUTF-8のみなので、mbstringなどの文字エンコーディング変換機能が必要かもしれません。
- 要素の補完や親子関係の補正には限界があり、必ずしも望ましい結果が得られるとは限りません。
- XML宣言やDOCTYPE宣言、名前空間などの補正は行いません。
- コメントやCDATAセクション以外のマークアップ記号はすべて解析対象です。即ち、XMPやPLAINTEXT、そして子要素がコメントまたはCDATAセクションではないSCRIPTなどがパース対象のドキュメントに含まれる可能性がある場合は、事前の処理が必要かもしれません。
- 任意の構成ルールを指定できますが、省略はできません。リリースパッケージには、XHTML 1.0 TransitionalのDTDに基づいて作成した構成ルールのサンプルが付属しますが、HTML以外のマークアップに対して利用する場合は構成ルールを独自に用意する必要があります。
- パフォーマンスを考慮した結果、パース結果は構造体ではなく文字列に構築されます。そのため、例えばドキュメントツリーを操作するようなインタフェースはありません(ドキュメントツリーを操作する必要がある場合は、出力をDOMオブジェクトに読み込むなどしてください)。
リリース
» 1.2.1 (stable) released 2007/05/17
※バージョン1.1からは、それ以前のバージョンと異なり、HTML_Sax3クラスのオブジェクトを別途に作成する必要がなくなりました。
| ファイル名 | 概要 |
|---|---|
| HTMLParser.class.php | クラスライブラリ本体。 |
| xhtml1-transitional_dtd.inc.php | XHTML 1.0 TransitionalのDTDを基に作成した、サンプルの構成ルールを表す連想配列を返す外部PHPファイル。 |
| sample.php | HTMLを読み込み、補正結果を表示するサンプルアプリケーション。 ファイル中の、ターゲットの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');
このクラスのオプションを指定します。
- 要素の親子関係の補正を行う際には、構成ルールに定義される、各タグの「既定の親(default_parent)」が参照される場合があります。例えば、サンプルの構成ルールでは、「meta」の項には「'default_parent' => 'head'」という記述があり、上のsample.htmlで欠落しているHEAD要素は、この定義に従い補完されます。HTMLでは、多くのタグについてこの「既定の親」は「body」ですが、これらのタグについて構成ルールに逐次「既定の親」を記述するのは効率が悪いので、「既定の親」が未定義のタグの、既定の「既定の親」を指定するのがsetGenericParentメソッドです。
- setRootメソッドで指定する値はドキュメントのルート要素(HTMLの場合は「html」)の指定であり、パース対象のドキュメントに(上のsample.htmlのように)ルート要素が欠落している場合に補完されるものです。
パーサから開始タグのハンドラに最初に渡されるタグ名(上のsample.htmlでは「meta」)がsetRootメソッドで指定した名前と合致しない場合は、ここで指定した値に基づく要素が補完され、ハンドラから渡された要素は、その子要素として評価されます(なお、属性値は評価対象ではありません。名前さえ合致していれば、その属性値に関わらずハンドラから渡された要素がそのまま利用されます)。
以下の指定により、上のsample.htmlのパース結果にはまず「<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">」というタグが補完され、次いでMETAが、その子要素として評価されます(当然METAはHTMLの直接の子要素ではないので、さらに補完が行われますが)。
$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&Bar" />
</head>
<body>
<div align="CENTER">
<h1>Foo&Bar</h1>
</div>
<hr noshade="noshade" />
<p>Foo<br />Bar</p>
<table>
<tr><td>Foo&Bar</td></tr>
</table>
<ul>
<li>Foo</li>
<li>Bar</li>
</ul>
</body>
</html>
この例では以下のような処理が施されています。
- タグ書式の修正(要素名と属性名の小文字化、空要素の終了記号の追加)。
- 終了タグの補完。
- 欠落している要素の補完(HTML、HEAD、BODY、TR、UL)。
- 要素の親子関係の補正(H1とDIV)。
- 不正な要素の除去(「FOO」タグ)。
- 不正な属性の除去(TABLEの「FOO=BAR」)。
- HTMLでは最小化が可能な属性の補正(「NOSHADE」→「noshade="noshade"」)。
- 不適切に用いられている解析対象記号の置換(「&」→「&」)。
しかし一方、これを例えばXHTML 1.0 TransitionalのDTDで検証した場合、以下のような不備があり、これらは、このクラスライブラリの処理の限界の例です。
- XML宣言とDOCTYPE宣言の欠落。
- 必須要素の欠落(TITLE、及びContent-Typeを指定するMETA)。
- 必須属性の欠落(TABLEのsummary)。
- 不適切な属性値(「align="CENTER"」)
なお、ドキュメントのパース結果は文字列として返されますが、幾つかのタグについてはより利便性の高い形式でその属性値を取得したい場合があるかもしれません。例えば、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ごとの結果の一覧
| クラブ | URL | Another HTML lint得点 | W3C Validatorエラー数 | Firefox CSSエラー数 |
|---|---|---|---|---|
| 札幌 | http://www.consadole-sapporo.jp/ | -122 | 95 | 171 |
| 仙台 | http://www.vegalta.co.jp/ | -14 | 63 | 7 |
| 山形 | http://www.montedio.or.jp/index.htm | 36 | 12 | 0 |
| 鹿島 | http://www.so-net.ne.jp/antlers/ | 6 | 132 | 0 |
| 水戸 | http://www.mito-hollyhock.net/ | -25 | 52 | 1 |
| 草津 | http://www.thespa.co.jp/top.html | -15 | 11 | 0 |
| 浦和 | http://www.urawa-reds.tv/ | -107 | 22※3 | 6 |
| http://www.urawa-reds.co.jp/ (FRAMESET) | -180 | 4 | 0 | |
| http://www.urawa-reds.co.jp/cont.htm (FRAMESET) | -311 | 15 | 0 | |
| http://www.urawa-reds.co.jp/menu.htm | -29 | 27 | 0 | |
| http://www.urawa-reds.co.jp/ind_main.htm | -21 | 117 | 0 | |
| http://www.urawa-reds.co.jp/ind_sw.htm | -164 | 22 | 0 | |
| 大宮 | http://www.ardija.co.jp/ | 8 | 77 | 0 |
| 千葉 | http://www.so-net.ne.jp/JEFUNITED/ (FRAMESET) | -323 | 18 | 0 |
| http://www.so-net.ne.jp/JEFUNITED/head.html | -251 | 19 | 0 | |
| http://www.so-net.ne.jp/JEFUNITED/left.html | -22 | 75 | 0 | |
| http://www.so-net.ne.jp/JEFUNITED/contents.html | -106 | 72 | 0 | |
| 柏 | http://www.reysol.co.jp/ | -46 | 71 | 0 |
| 東京 | http://www.fctokyo.co.jp/ | -63 | 196 | 1 |
| ヴェルディ | http://www.verdy.co.jp/ | -10 | 48 | 3 |
| 川崎 | http://www.frontale.co.jp/ | -174 | 89 | 0 |
| 横浜FM | http://www.f-marinos.com/index_dist.php | -817 | 376 | 210 |
| 横浜FC | http://www.yokohamafc.com/ | 79 | 8 | 0 |
| 湘南 | http://www.bellmare.co.jp/ (FRAMESET) | -278 | 24※3 | 0 |
| http://www.bellmare.co.jp/header.htm | -146 | 17 | 0 | |
| http://www.bellmare.co.jp/left.htm | -30 | 29 | 2 | |
| http://www.bellmare.co.jp/main.htm | -18 | 68 | 0 | |
| http://www.bellmare.co.jp/footer1.htm | -145 | 6 | 0 | |
| http://www.bellmare.co.jp/footer2.htm | -288 | 26 | 0 | |
| 甲府 | http://www.ventforet.co.jp/ | -51 | 119 | 0 |
| 新潟 | http://www.albirex.co.jp/ (FRAMESET) | -358 | 18 | 0 |
| http://www.albirex.co.jp/menu1.htm | -87 | 6 | 0 | |
| http://www.albirex.co.jp/title1.htm | -140 | 7 | 0 | |
| http://www.albirex.co.jp/top.htm | -10 | 55 | 0 | |
| http://www.albirex.co.jp/left.htm | -76 | 27 | 0 | |
| 清水 | http://www.s-pulse.co.jp/ (FRAMESET) | -377 | 22※4 | 0 |
| http://www.s-pulse.co.jp/s-pulse/header2006.html | -99 | 8※4 | 0 | |
| http://www.s-pulse.co.jp/s-pulse/menu.html | -25 | 14※4 | 0 | |
| http://www.s-pulse.co.jp/s-pulse/home.html | -16 | 23※4 | 0 | |
| http://www.s-pulse.co.jp/s-pulse/footer.html | -142 | 5 | 0 | |
| 磐田 | http://www.jubilo-iwata.co.jp/ | -124 | 141 | 2 |
| 名古屋 | http://www.so-net.ne.jp/grampus/ (FRAMESET) | -241 | 14 | 0 |
| http://www.so-net.ne.jp/grampus/menu.html | -102 | 42 | 0 | |
| http://www.so-net.ne.jp/grampus/main.html | -67 | 50 | 0 | |
| 京都 | http://www.kyoto-purple-sanga.co.jp/ | -92 | 252 | 24 |
| G大阪 | http://www.gamba-osaka.net/ | -16 | 31 | 0 |
| C大阪 | http://www.cerezo.co.jp/index.html | -43 | 34 | 0 |
| 神戸 | http://www.vissel-kobe.co.jp/ | -165 | 12 | 7 |
| http://www.vissel-kobe.co.jp/index.html | -47 | 192 | 8 | |
| 広島 | http://www.sanfrecce.co.jp/ | -52 | 20 | 5 |
| 徳島 | http://www.vortis.jp/ | -15 | 14 | 4 |
| 愛媛 | http://www.ehimefc.com/p/index.html | -53 | -※5 | 1 |
| 福岡 | http://www.avispa.co.jp/ (FRAMESET) | -278 | 16 | 0 |
| http://www.avispa.co.jp/side.html | 26 | Valid | 0 | |
| http://www.avispa.co.jp/header.html | -212 | 17 | 0 | |
| http://www.avispa.co.jp/index_body.html | -64 | 56 | 5 | |
| 鳥栖 | http://www.sagantosu.jp/ | 39 | 30 | 5 |
| 大分 | http://www.oita-trinita.co.jp/ | -68 | 112 | 2 |
| Jリーグ | http://www.j-league.or.jp/ | -3 | 194※6 | 5 |
| JFA | http://www.jfa.or.jp/ | -20 | 41 | 1 |
幾つかの覚え書き
- 各URLのDOCTYPE宣言を見ると、宣言がある場合については、(DTD指定の有無の差はあれど)殆どのものがHTML 4.01 Transitionalを宣言している。例外は、大宮アルディージャと、浦和レッズの「.tv」でのXHTML 1.0 Transitionalである。
また、文字エンコーディングは大半がShift_JISを採用している。例外は、コンサドーレ札幌、ベガルタ仙台、ジュビロ磐田、京都サンガがEUC-JPを、横浜FCがUTF-8を採用している。 - 昨今のCSSでは、いわゆる「アンダースコアハック」のような、Internet Explorerを欺くための記述がしばしば行われる。これはMozilla Firefoxでは当然エラーとなり、ここで見られるCSSのエラーも、幾つかはこれであるが、しかし大半は単なる記述ミス、及びInternet Explorerの独自仕様に基づく記述である。
- コンサドーレ札幌と横浜F・マリノスはCSSに関するエラーが飛び抜けて多いが(あまりにも多いので勘定を間違えてるかもしれない(笑)、これはほぼ同じ内容の外部JSファイルに起因していると思われる。おそらく両サイトは同じ製作者によるものなのだろう。
注釈
- 確認対象とした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 であると思われるので、これについては両方を対象とした。
- W3CのWeb Content Accessibility Guidelines 1.0の、ZSPCに掲載されている日本語訳より抜粋。
- HTTPヘッダ及びMETA要素に文字エンコーディングが指定されていないため自動検出が試みられたが、UTF-8であるとされたので、文字エンコーディングを指定して評価した。
- META要素で指定された文字エンコーディングが「x-sjis」であるため、不正なエンコーディングであるとして解析に失敗したので、文字エンコーディングを指定して評価した。
- 機種依存文字が含まれているため、不正なエンコーディングであるとして解析に失敗した(対処不能)。
- 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のパクリも必要だろうということで作ってみますた。そりゃもう、ヒマなオフシーズンのなせる業さ。
ウェブページのテキストを解析し、その内容が青赤的に適切なものであるかどうかを判定させてみようというネタでございます。一応、その手のページを読ませると、それっぽいスコアが出てくる筈。インチキなんだけど。なお、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年度シーズン前半のデータしか登録してませんよ。
つまり現在は、以下にあるものにはなんの価値もありません。
シーズンオフにつき、大半のドメサカオタの皆さまにおかれましては、ブログの更新を停止してみたり、別の話題にカミングアウトしてみたりしながら、来るシーズンの妄想に励んでおられるかと存じます。
この時期の主な妄想のひとつに観戦スケジュールの立案があり、平均的なドメサカオタはリーグの日程表を眺めながら、愛するチームのホームゲームは当然全て観戦するとして、アウェイはどうしようか、遠方アウェイなら近場の他クラブのゲームをひやかそうか、などと思案されておられるかと存じますが、お気楽に妄想を拡げられるように、お好みの試合の日程一覧をサクっと表示するスクリプトを作ってみますた。
使い方
- まずはホームゲームを観戦するチームを選びます。
マイチームは当然として、近場なのでホームなら見に行ってもいいかなと思うチームも、とりあえずチェックしておきます。 - 同様にアウェイゲームを選びます。アウェイは、チームとスタジアムが一致したもののみ表示されます。マイチームのアウェイゲームはすべて観戦したいところですが、さすがにここは行けないや、というスタジアムはチェックしないでおきます。
- 表示された日程表から、観戦予定ではないゲームのチェックを外します。
日程表の下に表示される「CSV形式で表示」をクリックすると、チェックの付いているゲームのリストを、Excelなどで利用可能な、カンマ区切りのテキストで表示します。
- 現在2006年シーズンの、7月までの以下の日程が登録されています。
- J1/J2/サテライト
- ナビスコカップ一次リーグ
- ACL一次リーグ(国内開催分のみ)
- JFL
- お約束。ここで表示される内容が正しいものである保証は一切ありません。
更新履歴
- 2006/3/2
- あったほうが便利じゃまいかということで、日付範囲指定の機能を追加。なお、カレンダー表示には、川崎有亮さんが公開しておられるJKL.Calender - ポップアップするカレンダー表示クラスを利用させていただいております。※
- その他あれこれ細かい機能の追加と修正。
- 2006/2/24
- JFLの日程を登録。
- 中止が決まったACL一次リーグの日程を削除。てゆうかなんだよそれ。
- 明日に迫り、もはや需要のある筈もないゼロックス杯の日程を削除。
- 2006/2/20
- JサテライトとJFL前期1&2節の日程を登録。
Technical Stuff
- JavaScriptのみで作られており、FirefoxとIE6で動作を確認しています。旧型のInternet Explorerでも動作するように作ってる気がしますが、動作確認はしていません。
- JavaScriptのみで、ファイル構成も単純なので、お気軽にかっぱらっていただけます。ここでは登録されていないスケジュールを追加したり、ローカルでオフラインで実行してみたりできるかもね。
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クローンがあるでございます。
レスを画像に変換するニーズは、携帯端末などでAAを確認したい場合が主なわけで、これはPCサイト->携帯変換スクリプト(pc2m)との連携を前提にしていて、こいつ単独では、レスをPNG化する機能しかありません。
必要なパラメータを含む、こいつへのリクエストURLの生成や、こいつが吐き出したPNGを、携帯端末が対応している画像形式や画面サイズに応じて変換するあたりは、すべてpc2mに任せるという仕様で、pc2mを、これらの掲示板にアクセスした際に、こいつにリクエストして、そのレスポンスに再びpc2mでアクセスするようなリンクを付け足すように改造しておくという寸法になってます(URLから板とスレはわかるので、あとはレス番号ごとに、適当なところにリンクを付ける)。
負荷軽減をねらって、取得したDATと生成したPNGはローカルに一時保存しておくようになってます。
リクエストに合致するPNGが保存されていれば、それを単に表示して終了。なければ、該当のレスを含むDATがあればそこからPNGを生成し、それもなければDATの取得から始めます。
一定時間経過後のDATとPNGは、以下ではDAT取得時に掃除するようになってます。
注意点とか
- allow_url_fopenがONで、GD2とFreeTypeが利用可能なPHPが必要です。
- モナーフォントなど、MS Pゴシックと同じ文字幅のTrueTypeフォントが必要です(※)。
- 画像の横幅は固定ザマス。文字数次第で表示がスカスカだったり収まりきらなかったりするところが最悪ウンコ。
- 以下のままで対応するのは2ちゃんねるのみで、その他は要改造。
Category: ウェブ制作
Posted 2006年01月20日 21:32
Seesaa Blogなどのコメントを携帯向け掲示板風に変換
新年お蔵入りPHPスクリプト集そのに。
Seesaa Blog(及びシーサーのBlogServerシステムを利用している他のブログサービス)のコメントを、携帯向け掲示板風に変換表示するPHPスクリプトです。
シーサーのBlogServerシステムは、もちろん携帯端末での利用に対応しているわけですが、現時点のものは、コメントの表示に関しては、すべてのコメントを一度に表示してしまうため、携帯のキャッシュサイズ(メモリ容量)が充分でない場合、コメント数が多いとすべて表示されない場合があります。てなことで、これを分割し、指定件数分だけ表示できるように改竄するというもの。
なんでSeesaa Blogの利用者でもないおいらがこんなものを作ったかというと、コメント欄を掲示板的に利用しておられて、携帯でのコメント表示に困っておられたかたが、PCサイト->携帯変換スクリプトを発見して利用いただいていたのですが、あれはあくまで汎用のものなので、このような定型のドキュメントなら、より見やすく使いやすい表示を、簡単に用意できるだろうと。
てなことでこれは実は、今のところお蔵入りではなく、実際にここで利用できたりしますが、シーサーがBlogServerシステムの携帯向けコメント表示形式を変更すると(少なくともこのままでは)動作しなくなり、そもそもBlogServerシステムが、コメントの表示も携帯にきちんと対応しちゃえば用済みになっちゃうわけです。
利用可能なことを確認しているのは、以下のブログサービスを利用している各ブログ(独自ドメイン名での運用のものもOK)。
- Seesaa Blog(*.seesaa.net)
- NetLaputa Blog(*.paslog.jp)
- ブログ・ジー(*.269g.net)
- アセラ・ブログ(*.a-thera.jp)
- 仙台CATV CAT-V SQUARE BLOG(*.cat-v.ne.jp)
なお、シーサーのBlogServerシステムを利用しているブログサービスでも、Erog(blog.shard.jp/*)のように、ブログの識別子がホスト名ではなく、パス名に充てられているものは、このままでは利用できません。アダルトサイトを差別してるわけるではなく、こんなのもあるとは知らんかっただけ(そして、いまさらこのために修正するのもメンドーなだけ)。
注意点とか
- allow_url_fopenがONなPHPが必要です。
- 実際にここにアップしているものは、記事のURLを入力できるフォームや、設定と説明表示の画面などが用意されてたりしますが、以下ではこのへんは端折ってます(アップしてるものはファイルを分割してたりするので、そのまま掲載しちゃうと判り辛いと思われるため)。
このまま利用する場合は、ここにアップしているものとは異なり、設定画面とか端折ってるので、クエリー文字列を付与したスクリプトの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のディスク容量」という謳い文句にダマされて)写真置き場にしていたので、かなりの数の画像があり、それらをアップロードし直して、サムネイルを作って、本文のリンクを修正して、という気の遠くなる作業はやりたくねえや、ということで、その辺りを自動化するために作ったのがこれ。
注意点とか
- allow_url_fopenがONで、GD2が利用可能なPHPが必要です。
- エントリーの日付は、HTMLソース中に埋め込まれたRDF(RSS 1.0)データのdc:dateの値(W3C DTF形式)を、PHPのstrtotime()関数で整形していまが、PHP4のstrtotime()関数は、+9:00などのように、タイムゾーン指定のあるW3C DTF形式を正しく解釈しないようなので、PHP5が必要です(あるいは適宜改造してください)。
- これはあくまで、自分のYahoo Blogからこのサイトへの移転用に作ったもので、決して汎用のものではありません。
少なくともこのままでは、Yahoo Blogで画像をアップロードする際に、「サムネイルを表示する」にして「javascript:wiki_img_view()」リンクでオリジナル画像を表示するパターンのエントリーにしか使えませんし、そもそもJPEG以外には対応してません。もちろん、Yahoo BlogのHTMLテンプレート変更になっちゃたら動作しないし。
もっとも、単純なスクリプトなので改造は簡単だと思います。実際自分も、これから改造してlivedoor Blog版を作ってるし。 - エントリーを手動で編集することはできますが、編集後のエントリーをあらためてプレビューし直す機能はありません。編集後の見栄えが心配な場合は、onChangeハンドラなどでプレビュー部分が変化するクライアントサイドスクリプトとかを追加しとくといい感じだと思われ。
ウェブブラウザでスクリプトにアクセスして表示される画面で、「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のインストール
- php.netのダウンロードページからダウンロードしたPHP5のZIPパッケージ版(インストーラ版の使用は相変わらず推奨されていません)をC:\phpフォルダに展開し、作成されたファイルのうち、php.iniの推奨設定版であるphp.ini-recommendedファイルをphp.iniにリネームします。
- Windowsのシステム環境変数「PATH」に、C:\phpを追加します。これは、PHPのコアDLLと拡張モジュール用の外部DLLを、Windowsのシステムフォルダではなく、C:\phpフォルダに置いておくために必要な設定です。
Windowsのシステム環境変数を設定するには、例えばWindows XPの場合は、マイコンピュータをマウスの右ボタンでクリックして表示されるメニューから「プロパティ」を選ぶか、コントロールパネルの「システム」をダブルクリックして表示される「システムのプロパティ」で、「詳細設定」タブの「環境変数」ボタンをクリックします。表示される画面で、システム環境変数の項目の中から「PATH」を探し、現在の値に「C:\php」を付け加えてください。 - Apache 2.0.xのhttpd.confに以下の行を追加します。
LoadModule php5_module c:/php/php5apache2.dll
肝は「PHPIniDir」ディレクティブで、この指定によって、php.iniをWindowsのシステムフォルダにコピーしないで、任意のフォルダに置いておくことができます。
PHPIniDir "C:/php"
AddType application/x-httpd-php .php
必要な設定は以上です。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パッケージを展開した初期状態から若干変更する必要があります。
- Apache 2.0.xを停止し、PHP5をインストールしたC:\phpフォルダを、C:\php5にリネームします。
- 新たにC:\phpフォルダを作成し、PHP5の場合と同様に、PHP4のZIPパッケージ版をphp.netのダウンロードページからダウンロードして、C:\phpフォルダに展開し、php.ini-recommendedファイルをphp.iniにリネームします。
- C:\phpフォルダ内にある「dlls」フォルダと「sapi」フォルダ内の全てのファイルをC:\phpフォルダに移動し、空になった「dlls」フォルダと「sapi」フォルダは削除します。
- PHP5のインストールの際に追加したhttpd.confの行を、以下のように修正し、PHP4用のLoadModuleディレクティブを追加し、一方PHP5用のLoadModuleディレクティブをコメントアウトします。
#LoadModule php5_module c:/php/php5apache2.dll
PHP4モジュールのパスが「c:/php/sapi/~」ではないことに注意してください。
LoadModule php4_module c:/php/php4apache2.dll
PHPIniDir "C:/php"
AddType application/x-httpd-php .php
必要な設定は以上です。Apache 2.0.xを起動し、phpinfoで、PHPのバージョンと「Configuration File (php.ini) Path」を確認してみてください。
PHP4とPHP5を切り替える
例えば、PHP4からPHP5に切り替えるには以下のようにします。
- Apache 2.0.xを停止し、C:\phpフォルダをC:\php4に、C:\php5フォルダをC:\phpに、それぞれリネームします。
- Apache 2.0.xのhttpd.confで、PHP4用のLoadModuleディレクティブとPHP5用のLoadModuleディレクティブのコメントを付け替えます。
- 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


