scriptaculousは好きだけど
scriptaculous.js より WebFxのようが実用的だ。
scriptaculous.jsのD&Dは処理が重い。rubyを念頭に置いてる。XMLと連携が。。。
使ってみたけど実用には向かないかも。
なによりhatenaの人にあらされてない。WebFxのスクリプト集もかなり本命だと思います。
URLの符号化の話。
Ajaxを使うために避けて通れない、日本語をMIMEエンコードする話。
そもそもMIMEとは?
http://www.asahi-net.or.jp/~sd5a-ucd/rec-html401j/types.html#h-6.7
UTF-8とは?
3バイト文字のことである。UTF-8を明示するためにBOM を入れることがある。
MS932とは?
Windowsで使われるShift_JISの事である。一般的な2バイト文字である。
これは頭に入れてること。文字化けにハマった。
JavaScriptにおける符号化
escape &unescape
encodeURI & decodeURI
encodeURLComponent & decodeURIComponent
PHPにおける符号化
urlencode
rawurlencode
Javaにおける符号化
java.net.URLEncoder.encode( Stirng s, String ENCODING );
java.net.URLDecoder.decode( Stirng s, String ENCODING );
まずBOMの扱い。
BOMがあるとUTF-8と認識される? いまのところされていない様子。(Content-typeが優先)
BOM文字はほとんどの場合気づかない。
JavaにおけるBOM
余計な文字としてコンパイル時にエラー。基本的にJavaはUTF-8を受け付けない様子(06/02/28実験 javaSDK1.42 Tomcat5.0)
JSPをBOM付きUTFで書くとBOMがout.printされる。out.print()時に文字コード変換を行う。
そのため、UTF-8で書いたJSPソースをMS932で出力するとBOM文字を変換出来ずに「?」になる
JavaScriptとBOM
encodeURIComponent はBOMを上手に扱えないときがある。
PHPにおけるBOM
出力時にブラウザにBOMをつけて出力される。
include / require 関数を使うと IncludeしたファイルのすべてのBOMがブラウザに出力されている様子。
つまりしばらくはBOMをつけないほうが無難であると推察される。
JavaのURLEncoder.encode()をJavaScriptの decodeURI()でデコードはできない。符号化が違う
PHPのrawurlencodeを JavaScriptの decodeURLComponentでデコードはできる。ただし完璧にデコードが可能かというと疑問が残った。
Googlebotが読めないページ?
うちのPCには GoogleWebAccelerator を導入してる
こいつはなかなか賢いツールで先読みキャッシュがなかなかcoolに動作する。
このWebAcceleratorの動作をつぶさに観察してて気になったことがある
このツールは日本語MIMEエンコードされたURLを絶対に先読みしないのだ。
たとえばこのURLは先読みされない。
http://d.hatena.ne.jp/keyword/%A5%D5%A5%B5%A5%A4%A5%C1%A5%B8%A5%E3%A5%F3%A5%AF
一方で
http://d.hatena.ne.jp/keyworddiary/ajax#keyworddiary
このURLは先読みされる。
ここから導いた結論
GoogleWebAcceleratorは日本語のMIMEエンコードが入ったURLを取得できない。
まぁ英語版なので当然といえば当然なのですが。
GoogleWebAcceleratorは、MouseHoverイベントを監視しているらしい。
リンクの上にマウスカーソルが来ると、リンク先をGoogleネットワークが先読みした中から取得するらしい。
ここから推察してみる。
事実。
英語版のGoogleWebAcceleratorは日本語MIMEエンコードを取得できなかった。
仮定。
先読みキャッシュサーバーが使っている先読みプログラムがGoogleBot の応用だとする
推論+仮定から得られる結論
GoogleBot がWebページをクロールするときに日本語MIMEエンコードが含まれたURLを取得しない可能性。(英語版の話)
追加の仮定。
日本国内向けに はGoogleJPがカスタマイズしたGoogleBotを国内から国内へ走らせているはず。
とするとJPドメインは間違いなくGoogleJPが担当するはず。
追加の推論。
とするとJPドメインに置いてはMIMEエンコードされたURLは正しくクロールされるだろう。
ここから導き出される結論。
つまり日本語ページに置いてはJPドメインが有利だと思われる。
では、この仮説が正しいか?検証しなくては。。。
検索ワードにソーシャルブックマークで使われそうな単語を選んでみる
phpSpotでは?
http://s.phpspot.org/ のソーシャルブックマークはgoogleページランク4/10
http://s.phpspot.org/tag/all/%BB%B2%B9%CD%A5%B5%A5%A4%A5%C8%5Bl%A5%B5%A5%A4%A5%C8%5D
のページランクは2/10
http://s.phpspot.org/tag/all/%BB%B2%B9%CD%A5%B5%A5%A4%A5%C8 のページは2/10
はてなでは?
http://b.hatena.ne.jp/ のソーシャルブックマークはgoogleページランク 6/10
http://b.hatena.ne.jp/t/%e5%8f%82%e8%80%83%e3%82%b5%e3%82%a4%e3%83%88 のページは0/10
hatenaは検索順位50番。URLの表示は
b.hatena.ne.jp/t/参考サイト - 33k -
phpspot.orgは検索順位番125番 URLの表示は
ページランクの高いページの方が検索順位は下位ですね。2倍以上。
この差になるのは何だろう。やはりJPドメインだからだろうか。しっかりクロールされてるって事か?
もともとのドメインのページランクの差だろうか?
日本語をエンコードするときに使った符号化の差だろうか?
とくに注目すべきは[b.hatena.ne.jp/t/参考サイト]と検索結果に表示されるところ。
phpspotではこれが出来てない。
つまり符号化がGoogleに好かれてないということだろう。
やっぱJPドメインは強いと思われる。
------------------
1時間後。。。
同じ条件で検索したところ大幅に順位が変動してた。
Wikipediaが上位10だった。wikipediaのランクは7/10
エンコードもgoogleが解析できてる。
ん~やはりドメインは関係ないのかなぁ
今回の仮説は追跡調査します。
実際ウチのサイトにあるのようはURL/tag/%BB%B2%B9%CD%A5%B5%A5%A4%A5%C8 はgooglebotがクロールしないんですよ・・・・
追跡調査が必要。
Smartyのキャッシュで楽をする
Smartyは重い。DBの接続処理は重い。
サーバー管理者としては、何度も何度もDBに接続されたらたまらない。
ユーザーとしては、(←戻る 進む→)が遅いとイライラする。戻りたいときほどパッと戻りたい。
この相反する要望に応えるのがcache。
直前のデータをブラウザではなくサーバ側で持っておく。
そこでSmartyのキャッシュテクロノジが使える。
require_once('Smarty.class.php');
//インスタンス化
$smarty = new Smarty();
//初期設定
$smarty->template_dir = '/smarty/templates';
$smarty->compile_dir = '/smarty/templates_c';
$smarty->cache_dir = '/smarty/cache';
$smarty->config_dir = '/smarty/configs';
$smarty->caching = 2;
$smarty->cache_lifetime = 300;
if( $smarty->is_cached('index.tmpl.html', $_SERVER["REQUEST_URI"] ) ){
//キャッシュがあるので処理をスッ飛ばす
$smarty->display('index.tmpl.html', $_SERVER["REQUEST_URI"] );
return;
}
//規定の処理
・・・・・
$smarty->display('index.tmpl.html', $_SERVER["REQUEST_URI"] );
//キャッシュを使うための設定はこの部分
caching = 2//または 1 or 2 にセット、false or 0 はCacheしない
cache_lifetime = 60 (1分もあれば十分かと)
display(TEMPLATE_NAME, $cache_id);
キャッシュの識別には$cache_id 固有の値を与えて識別する。
区別できれば何でも良い。session_idとかユーザー番号。日付、現在時間などが使えそう。
時間+session_idをmd5にかけて固有値求めても良いだろう。
今回は、$_SERVER["REQUEST_URI"] をユニークキーにした。URLはサーバー内でたった一つだから。ユニークキーとして活用できる。
$cache_id を指定し忘れると。。。
index.php?hoge=foo と index.php?hoge=bar でキャッシュを共有してしまう。
出力が変化しなくて困る羽目になる。
もちろんキャッシュディレクトリとコンパイルディレクトリのパーミッションの設定を忘れると動かない。
パーミッションの設定にも注意する。
//Pear_Cacheは今度調べておく
// SessionCacheと相性問題無いか?
// E-tagはどうなってるか?
// LastModifed-Sinceとの対応はとれるのか?
// HTTP no-cache pragmaとの関係は?
疑問はつきないが、とりあえずSmartyのCacheで驚くほど快適になる。
・・・・寸感
重くて使えないXoopsには必須だな。
-------------------------
追記$_SERVER["REQUEST_URI"]は意外に長い文字列になるので
$smarty->display('index.tmpl.html', md5( $_SERVER["REQUEST_URI"] ));
または
$smarty->display('index.tmpl.html', sha1( $_SERVER["REQUEST_URI"] ));
にして文字数を減らした方がよいようだ。
(キャッシュファイル名がFTPのエスケープ文字含んでしまうバグがあった。)
Goolgeのcrawler
実験。
どんなサイトがGoogleのボットに追いかけてもらえるのか。
ドメインを取って、サイトを公開してからアクセスログを取ってる。
Googleのcrawlerの動きを毎日追跡してみた。
GoogleAlert グーグルアラートの機能を利用してGoogleのクローラーがウチのサイトを検索結果に追加したタイミングが分かるようにしておいた。
2か月程経って分かったこと。
Googleのbotの巡回周期は意外に頻繁。
同じようなサイトは一括りにしてしまう
ドメインごとにインデックスを作るようだ。
ページのdiffして閾値を超えたときだけ検索結果に反映させてる。
つまり
www1.hoge.comとw2.hoge.comは内容が同じでも別サイトとして認知されるくさい。
foo.hoge.com と hoge.com/foo だと圧倒的に前者が有利だ。
つまり、
デザインを統一すればするほど、GoogleのBotには同じページに見えるくさい
まぁ当たり前なんだけど。
ちなみに、php, jsp, asp, cgi などの拡張子はSEO的に不利だ。ってのは嘘だと思う。
そんなこと言うSEO業者は信用できない。
検索結果にはサイトがあるのに引っかかった部分が無かった。 つまり訪問者に優しくない。
そんなページの拡張子をJSP ⇒ htmlに変えたところでランクアップするわけ無い。
そこでMTが考えたのがpermalinkの仕組み。
MTは検索結果によく引っかかる。
ブログがSEO的に有利?
それも違う。
MTの技術者が優秀で、SEOのことをよく分かっていらっしゃるからだ。
すべてのブログがMT並みによいスコアを連発する訳じゃない。。
mod_rewrite
WgetでCMSをHTML化して
Dynamic ⇒ Static なページ
が個人的にはおすすめなのですが。
Static ⇒ Dynamic
という逆もまた可能。
逆をするにはmod_rewrite
こいつはナカナカに黒魔術なので、動作には注意が必要。
ウッカリすると無限ループにはまる
使うオプションはこれ。
これをhtaccessとかDirectiveに記述すればいい。
負荷分散に使えそうなのはRewrite Map をランダム切り替え。
www . hogehoge.com をランダムで www1, www2,に書き換えてやる。
実際試してみないと分からんけど。
ポートを切り替えればTomcatにリクエストをとばせるわけだ。ふむ
気が向いたら試してみよう。
URLの書き換えにPerlなどのスクリプトを指定できるようだ。何でもアリだな。これは
phpPgAdminで使ってるツリーは?
新作のphpPgAdminではツリーが動的にロードされる。すげー
これのソースコードを読んだところ
XloadTreeというらしい
http://webfx.eae.net/dhtml/xloadtree/xloadtree.html
xloadtree/xloadtree2.js / xloadtree/xtree2.js がコアのようだ
webFXTreeConfigというクラスに記述がありそうで。
XMLを使って動的にツリー描画をするみたい。調べてみましょう。
HTML_Ajaxの使い方ページを読んでみた。
基本的な使い方。
http://blog.joshuaeichorn.com/archives/2005/08/17/ajax-hello-world-with-html_ajax/
HTML_Ajax_Serverでリクエストを受け付ける&必要なJavaScriptのクラスファイルを作成する。
HTML_Ajax_Serverにインスタンスを足していく
ただし、HTML_Ajax_Serverに色々足すと、が大きくなりすぎる。
そんな心配があるなら、HTML_Ajax_Serverをextendsやdelegateなどして、$server->handleRequest();する。
CGIを呼ぶときにjavascript' src='auto_server.php?client=all&stub=helloworld'とすれば勝手に必要なソースコードが生成されてブラウザに読み込まれてくれる。
あとはHTML内でPHPのClass定義に従ってJavaScriptを使えばよい
callback関数群をオブジェクトにして初期値に渡してやると便利だが、都度都度渡しても良いようだ
だいたいこんな感じ。
使い方紹介したスライド
http://htmlajax.org/materials/HTML_AJAX_Presentation/HTMLAJAXPresentation.pdf
ま、ExampleはIE6.029で見たらエラーになったけど。。。IEで動かないんじゃhatenaの住民ぐらいしか使わんやん。。。
HTML_Ajax
HTML_AJAX 0.3.4 Examples
These are examples showing the basics of using HTML_AJAX
Pear_HTML_Ajaxの基本的利用例を以下に紹介します
These examples show off many of the features of HTML_AJAX, but you'll find them most useful as a learning tool. Reading through the commented code as you view the examples in your browser.
これはHTML_AJAXの各機能をかっこよく紹介するためのモノです。と同時に使い方を覚えるのにちょうど良いテキストでしょう?そのためには以下のサンプルのコードを読み進めると良いですよ。
These examples are available online at: http://bluga.net/projects/HTML_AJAX or in your local PEAR install in the documentation dir. On most Linux systems the location is /usr/share/pear/docs/HTML_AJAX/examples/ You can find the location of your PEAR documentation dir running pear config-get doc_dir
これらのサンプルはhttp://bluga.net/projects/HTML_AJAX で閲覧が可能ですし、Pearパッケージとしてインストールしたなら PEAR_HOME/docs/HTML_AJAX/examples/ に配置されてます。PEARのドキュメントのインストール場所が分からないときはコマンドラインからpear config-get doc_dir で確認できます。
The term proxy in these examples refers to a javascript class that is generated and has functions that map to the equivalent php class. These proxy classes work much in the same way as a SOAP proxy class that is generated from wsdl.
proxyの章ではphpが生成しブラウザに返すjavascript classと関数群について紹介しています。この自動生成されるJavaScriptはphpのClassとに関連付けられ動作が同等に設定されています。proxyClassはSOAP proxy classと同様に動作がWDSLの書式で定義させることが可能です。proxy クラスが生成するJavaScriptソースの定義方法はSOAP利用時にWDSLからクラスが自動生成されるかのように、簡単にPHPクラスがJavaScriptのClassになります
Front end files for examples, you can actually run these and see some example output
行頭のファイル名が、サンプルファイルのファイル名です。とにかく実際動かして出力を見てみましょう。
- proxyless_usage.php
- Using HTML_AJAX in standalone mode, possible doesn't require PHP or any backend HTML_AJAX classes
HTML_AJAX を動かしてDIVレイヤー書換え。この動作程度ならJavaScriptファイルも要らないし、他にphpクラスファイルも使っていません。HTML_AJAX クラスだけをつかって生成されたJavaScriptが動きますが動的にデータをサーバーに取得することはしていません - proxy_usage_inline_javascript.php
- Single file proxy style usage
単一ファイルでproxyを使う例 。javascriptがphpに値を取得する例。特にクラスを利用するわけではない。取得に行く先がいつも同じなのでsingel proxy - proxy_usage_server.php
- Multi-file proxy usage, either server file could be used with this example
server.phpからauto-server.phpに変わった模様 。サーバーにデータを取りにいくURLが複数ある(リクエスト先URLが変化する)のでmultiple - queue_usage.php - An example of using a queue to manage ajax calls, a simple live search example
- helper_usage.php
- An example showing the basics of the helper api
helper APIを使うシンプルな例 - form.php
- Basic AJAX form submission example
Ajaxを使ったフォームの送信&結果の取得。一番基本的な例。
Real Life Examples
実践的な例
- login/index.php
- An example creating an AJAX driven login
Ajaxで送信してログイン処理をしてみましょう - review/index.php
- A simple live review system, AJAX form submission and click to edit
シンプルなデモ。Ajaxでフォーム送信&送信済み情報をAjaxで再編集する例 - guestbook/index.php
- A simple guestbook system, uses action system so you never write a line of javascript
とても単純なBBSの例。action systemを使えばjavascriptのコードは書かずに済みますよ。 - shoutbox.php
- How to use AJAX form submission
Ajaxでフォーム送信をどうやるかの例。
2 server examples are provided, both provide the same output but the auto_server example has code to help you deal with managing multiple ajax classes
2つのサーバーサイドの動作例です。どちらも、同じ結果を返しますが、 auto_server.phpの例はコードを含みます。複数のAjaxClassを扱うために役立ててくれればよいと思います。
2つのサーバーサイドの動作例が例示されていますが、どちらも同じ結果を返します。ただ、auto_serverに注目してください。この動作例にではAjaxで複数のClassを利用するときの使い方の例として活用してください。
- server.php - Basic server operation, serving ajax calls and client lib requests
基本的なCGIのオペレーション。AjaxにCallされたりブラウザリクエストで動作する - auto_server.php - Advanced server operation, only create php classes as needed
高度なCGIを含む。php classを作成するときにこそ必要とされる - server.php?client=util,main
- server.php generating a javascript file with the main and util libs in it
server.php がjavascriptのファイルを作成してブラウザに送る。mainメソッドと各種ユーティリティー関数を含むソースコードを出力。 - auto_server.php?stub=test2
- auto_server.php generating a javascript file a which contains a generated proxy class for the test2 php class
auto_server.php がjavascriptのコードを出力する例。proxyの例で使ったtest2.class.phpをjavascriptのClassにして出力。 - auto_server.php?stub=all
- auto_server.php generating a javascript file which contains proxies for all the php classes registered with it
auto_server.php がjavascriptファイルを出力する。auto_serverに登録されたすべてのClassをjavascriptのソースコードにして返す。
Examples files showing howto use HTML_AJAX_Util javascript class
HTML_AJAX_Util で出来るjavascript class をどうやって使うかの例。
- js_utils_vardump.php
- Shows the output of HTML_AJAX_Util.varDump() and compares its against PHP's var_dump
var_dumpをAjax経由で呼び出す例。JavaScriptからHTML_AJAX_Util.varDump() を使った出力とPHPからvar_dump()関数を使った出力例を比べてみて欲しい。
Other Example files:
その他のサンプルファイル
- test_speed.php
- A basic setup for measuring the speed of calls
基本的なSetupの例。syncとansyncのスピードテスト - test_priority.php
- A basic test showing how Priority queue works
優先順位をつけたキューを発行するテスト ansyncでキューを出すので応答がまちまちになるのがAjaxっぽい - serialize.php.examples.php
- Internal tests for the php serialize format serializer
オブジェクトのシリアライズをAjaxを使って行うテスト phpでシリアライズしAjaxでオブジェクトのシリアライズに戻す。またその逆をデモンストレーション。negativesはワザとエラーを起こすテスト - serialize.url.examples.php
- Internal tests for the urlencoded format serializer
urlencodeを使ったオブジェクトのシリアライズ
Javascript and Html Examples:
JavaScriptとHTMLを合わせたイベント操作
- test_behavior.html
- A short overview of how to use behavior.js. Behavior uses css selectors to apply javascript behaviors without throwing lots of javascript handlers into your html.
behavior.jsを使った簡単な例。Behavior ClassはCSSセレクタをJavaScriptのイベント操作に利用できます。このおかげでhtml内に自由にイベントを埋め込めますよ.prototype.jsと同じだね。
DB_DataObject をつかってデータの更新
DB_DataObject はこうやって呼ぶと便利
//この呼び方は便利だwww
public function setProperty( $record, $keyColumn, $keyValue ){
$this->records = DB_DataObject::factory( $this->table );
$this->records->$keyColumn = $keyValue;
$this->records->find( true );
$this->records->limit(1);
$this->records->delete();
foreach( $record as $columnName => $fieldValue ){
$this->records->$columnName = $fieldValue;
}
$this->records->insert();
return;
}
抽象化をさらに抽象化するという暴挙 笑
でもこれでDBにすべて同じコードのコピペでデータをセットできる。
あぁなんて楽ちんなんだろう
可変変数という一見マニアックなものを使うことがポイントです。
まぁPearのsourceでもよく使われてる手法なので。