近年、Webではページの切り替えを行わずに、ページ内を動的に変更するサービスが増えている。動的にページを変更することにより、ユーザに対して以前よりスムーズにサービスを提供できることや、今まで無かったサービスを提供することができるためである。
本研究はこのページ内を動的に変更するサービスを使ったシステムとしてWebページ上にコメントを貼り付けるシステムを作成した。これは普段見ているページ上に誰もがコメントを貼り付けることができ、さらに誰もがそれを見ることができるシステムである。
以下に実際にシステムを使用した際の画面の図を示す。
○コメント貼り付け処理
○コメント表示処理
コメント貼り付け処理は図1(a)のように書き込みフォームにコメントを書き込み、insertボタンを押す事によって図1(b)のようにコメントをWebページ上に貼り付けることができる。コメント表示に関しては(図2)、本研究で作成したシステムが導入されていればページを表示した際に自動的にコメントも表示される。
システムの原理は、Webページ表示する際にリアルタイム(動的)にコメントデータを外部サーバから取得し、それをWebページに適応させることによって行っている。このようにページ内を動的に変更を加えることができる技術のことをAjax(Asyncronous JavaScript+XML)と言う。これは今までのようなサーバ側とホスト側が同期して通信を行う方法とは違い、非同期通信を行う事によりユーザ側が操作できない時間を作らずにサービスを提供することができる。
Ajaxという言葉は2005年2月18日にJesse James Garrett氏のエッセイ「Ajax: A New Approach to Web Applications(※1)」によって名付けられたものでありここ数年で発達した技術である。これまでにGoogleマップやGoogleカレンダー等のサービスがAjaxを使い作成されているが、より有用なサービスを提供できないかと考え今回のシステムを作成した。
※1 http://www.adaptivepath.com/ideas/essays/archives/000385.php
正式名称はECMAScriptであり、ヨーロッパのコンピューター関連技術の標準化団体であるECMA(European Computer Manufacturers' Association)により標準化されている。
Netscape Navigator 2.0より実装されたブラウザ上で動く言語であり、Webページ(HTML)を書き換えることができる。
プログラム言語としては以下のような特徴がある。
※2 2.3で解説
正式名称はPHP:Hypertext Preprocessorである。主に、サーバ側で動作する Web アプリケーションの開発に使われている。
プログラム言語としては以下のような特徴がある。
Document Object Modelの略称である。Webページの要素(HTMLやXML)を制御するための仕様である。ブラウザがこのDOMを実装している場合、JavaScriptがDOMを利用できるため、JavaScriptよりWebの内容を制御することが可能である。
Cascading Style Sheetsの略称である。Webページの要素をどうのように修飾するかの仕様である。例を挙げると、Webページ上のフォントやカラーの指定がそれにあたる。
JavaScript(主にDOM)やCSSを利用してリアルタイムにWebページの内容を変更する技術のことである。
JavaScript Object Notationの略称である。JavaScriptで使われるオブジェクトの表記法をベースとした書式である。このためJavaScriptではJSONを直接扱うことが出来る。以下に例を示す。
図3の(a)を実行すると図3の(b)のような結果が出力される。JSONとは(a)の2~5行目のような書式のことを指す。
2.7 HTML要素のstyle属性のpositionについて
HTML要素のstyle属性はHTMLやXML等の要素に対してスタイル(表示)を設定することができる。今回コメントを表示する際に、コメントを画面上に貼り付けたように表示するために、divタグにstyle属性でposition:absoluteの値をもたせ利用している。これは、styleの属性値をposition:absoluteと指定することにより、X座標Y座標を指定すれば画面上のその位置に表示され、貼り付けたように表示することができるためである。
XMLHttpRequeset(以下XHR)とはHTTPプロトコルを制御することができるJavaScriptのオブジェクトである。HTTPプロトコルを制御できるためHTTPリクエストに対応したWebサーバとのデータのやり取りに使用することが出来る。またサーバとの通信にはサーバからの応答を待つ同期通信と、サーバからの応答を待たずに、次の作業を行う非同期通信の両方に対応している。ただしXHRを使用するネットワークとサーバ側のネットワークが異なる場合XMLHttpRequestは使用することができない。
Asynchronous JavaScript + XMLの略称である。AjaxはJavaScript、CSS、XML、XHR、サーバのウェブアプリ(APIやPHP等)等を使い、非同期通信かつ画面遷移(ページの切り替え)せずにサーバとデータの送受信をすることができる技術のことである。サーバとの通信はJavaScript(XHR)で行う。
略称にXMLとあるがこれはデータを記述するための言語である。サーバからのデータの受け取りをXMLデータで行うことからこの名前がつけられている。しかし、最近ではXMLを使わない例(JSONを使用する等)が多く見られ、必ずしもXMLで無ければならないわけではない。また、サーバとの通信はXHRで行うため非同期通信ではなく同期通信でも可能である。
また、ここ数年でAjaxシステムが急激に増加したが、これはホスト側の、ネット回線、ブラウザ、PCの機能が向上したことが関係していると考えられる。
以下にどのようにして非同期通信で画面遷移することなくサーバとデータのやり取りをしているのかを、同期通信で画面遷移がある場合(従来の仕組み)と比較して説明する。
Ajaxを使用しない従来のWebシステムは下図のような流れで処理を行っている。
①HTTPリクエスト
ホスト側(データ受信側)がサーバ側(データ送信側)へデータを要求。
②DBよりデータ取得
サーバ側がホスト側に要求されたデータをサーバ内やDB(データベース)内より取得する。
③HTMLデータ
サーバ側がホスト側に要求されたデータ(HTMLデータ)を送信。
④ページを切り替えて結果を表示する。
ホスト側が受信したデータを表示して通信完了する。ページを表示する際、ページ内を全て一から書き換えるため画面遷移(画面の切り替え)がある。
このように従来のWebシステム①~④の流れで処理が行われている。また②でサーバがデータを作成している際、ホスト側はサーバからの返信が来るまで待機しており(同期している)ホスト側はサーバからの返信が来るまで次の作業へ移ることが出来ない。
Ajaxを使用したWebシステムは下図のような流れで処理を行っている。
図9を元にAjaxを使用したWebシステムの解説する。
①イベント発生時、JavaScriptに知らせる
ユーザからのイベントをJavaScriptに知らせる。
②XHRでHTTPリクエストを行う
①のイベントをJavaScriptで処理し、それに応じたHTTPリクエストをXHRにて行う。
③DBよりデータ取得
サーバ側がホスト側に送るデータをサーバ内やDBより取得する。通信を非同期通信で行った場合、サーバからの応答が来るまで他の作業を行う事ができる。
④データ(XML等)
サーバ側がホスト側にデータを送信する(書式はXML以外でも可)。
⑤、⑥Webページに反映させ、一部変更する。
JavaScriptが受け取ったデータをWebページに反映させる。ページの一部分を変えるため、画面遷移は無い。
このようにAjaxを使用した場合は、XHRが非同期通信をすることが可能であるため、従来のWebシステムとは違い、サーバが処理中でもホスト側は自由に処理を続ける事が可能である。また、サーバから受信したデータはJavaScriptが受け取るため、画面遷移することなくページ内を変更することが出来る。
クロスドメイン制限とは異なるドメイン間での通信をブラウザが制限することである。この制限により、Webページ内にこれとはドメインが異なるWebページを表示した場合、これらのWebページ間ではWebページ内のデータの変更や読み込み、が一切出来なくなる。何故このような制限があるのかは下図より示すことができる。
図15は、ログイン画面があるWebページ内に異なるドメインのWebページである広告ページが表示されている状態である。これでもし、ブラウザにクロスドメイン制限が無かった場合、広告ページからIDやPWを覗き見ることが可能になってしまう。これを避けるためにブラウザ側にはクロスドメイン制限が存在する。
GreasemonkeyとはFireFoxで使える拡張機能(アドオン)の1つである。これをインストールする事により、Webページ表示時にユーザサイドスクリプトを実行できる環境を構築できる。さらに、表示するWebページによって使用するスクリプトを選択することが可能である。
このユーザサイドスクリプトとは、ユーザ側が用意するスクリプトである。Gresemonkeyで使われるユーザサイドスクリプトはJavaScriptであるが、Gresemonkey独自のGresemonkeyAPIも使うことが可能である。
スクリプトを実行するタイミングはGreasemonkey場合、DOMContentLoadedの時である。このDOMContentLoadedとは、ブラウザがDOMによってWebページの各要素を読み込んだ時を表す。
本研究に関連したシステムとしてドワンゴ社のニコニコブックマークというWebページが2007年に存在した。このニコニコブックマークとはWebページのスクリーンショット上にコメントを貼り付けるシステムである。実際の画面を以下に示す。
図16はニコニコブックマークからGoogleページを表示した場合である。この図よりコメントを貼り付けるシステムには以下の2点について問題があると考えられる。
まずコメントの収集がつかないということだが、これは図16より明らかである。また同一性保持権だが、これは著作物に対して著者者の意に反した改変を禁止することができる権利のことである。コメントを貼り付ける行為が改変と考えることができるため同一性保持権の問題があると考えられる。本研究でもこの2点については解決できていない。
しかし、本研究でのシステムはニコニコブックマークと比べ、スクリーンショットではなくWebページそのものであるため、リンク先へ移動することや動画を見るといったWebの機能を損なうことが無い。
ブラウザで表示しているページにコメントを貼り付けることができ、さらにそのコメントを自分だけではなく他人からも見ることができるシステムを作成する。
システムを作成した際に、設計自体が間違っていたため(クロスドメイン制限にひっかかってしまった)うまく動作しないといったことが起こった。これについて説明する。まずシステム設計は下図のようにして行った。
ここのコメントサーバとはコメントを保存しておくためのサーバである。
システム設計は、コメント処理ページが表示する一般ページに対応したコメントを表示するといった方法で行った。サーバとのデータの送受信は2.9.2のAjaxの例と同様である。2.9.2との違いとしては1つのページ内にコメント処理ページと一般ページの2つが存在している部分である。
システム設計が失敗した原因は図17の②である。一般ページがページを取得したことをJavaScriptに伝えたかったのだが、2.10で説明したとおりブラウザにはクロスドメイン制限があり異なるドメイン間のデータの受け渡しが制限されているため、一般ページがページを取得してもコメント処理ページがそれを知ることができなかったため、②を行うことが出来なかった。
4.2の方法では動作させることができないため、解決策としてGresemonkeyを使用した。Gresemonkeyを使用すれば、ブラウザがWebページを読み込んだ際に自動的にスクリプトを実行することができる。このため、4.2で失敗した原因である「②ページを取得したことを伝える」といったことをしなくて良い。
作成するシステムは主に以下の2つの機能から成り立つ。
この1と2についてそれぞれ説明していく。尚、プログラムのソースは巻末の付録に示す。
ユーザがページを表示する際にGresemonkeyによってコメントを取得する関数が実行される。システムの流れを下図に示す。
システムの流れとしては2.9.2のAjaxを使用したWebシステムと同様である。違いとしてはサーバとのデータのやりとりをGreasemonkeyがユーザサイドスクリプトを使用して行っている事である。
次に実際にソースの説明を行う。
コメントを表示する関数のソースは以下の通りである(labo.user.jsより)。この関数で図18の③~⑥の処理を行っている(⑥に関してはコメントタグ(divタグ)を生成する関数であるsetCommentDivを使用している)。
このスクリプトはGM_xmlhttpRequestのみを実行している。
このGM_xmlhttpRequestとはGreasemonkey内部で使えるGreasemonkeyAPIの1つであり、Ajaxでの説明のXHRとほぼ同じ動作をする。今回使用する上での相違点はクロスドメインの制限が無いというところである。よって、外部ドメインとの通信に関して制限無く行うことが出来る。
GM_xmlhttpRequestについての説明。
「GM_xmlhttpRequest」
概要
非同期通信で、指定したURLのデータを取得できる。(xmlhttpRequestとは違い非同期通信のみに対応)
書式
GM_xmlhttpRequest({method, url, onload, [onerror],[header],[data]})
引数
以下に今回の場合について説明する。
method:図19の4行目
POSTを使用している。POSTを使う理由は文字数制限にある。GETの場合はOSの環境変数QUERY_STRINGの長さや、ブラウザのURLに文字数制限(HTML4では65536文字まで ※http://www.w3.org/TR/html4/sgml/sgmldecl.html)が存在するため。
url:図19の5行目
リクエスト先のURLを表している。CommentSRVAddはリクエストするファイルの保存場所を表し、comment_all.phpはサーバ側に存在するコメントを取得するためのPHPファイルである。
data:図19の6行目
コメントを取得したいURL(今開いているページのURL)を設定している。
headers:図19の7行目
サーバにアクセスする際のヘッダー情報。
onload:図19の8~24行目
ここでcomment_all.phpからコメントデータを受け取り、表示している。
コメントデータは8行目のfunction(resp)の引数であるrespに保存されており、中のデータはresp.responseTextでアクセスできる。今回comment_all.phpからのデータはJSONで渡されるようになっており、eval関数(文字列をJavaScriptのコードとして認識させる関数)を実行するだけでJavascriptが受け取ったデータを解釈することができる。
このevalの作業を10~15行目で行い、さらにevalが失敗した際(comment_all.phpがエラーをして、値がJSON形式で無い場合等)処理を終了させるようにしている。
次にコメントを表示する処理を16~23行目のfor文で行っている。comment_all.phpから受け取ったJSONデータはres変数に入っており、res.item.lengthでコメントの数を表している。今回コメントで使用するJSONのデータは「comment、x_val、y_val、color」であり、それぞれres.item[i].commentの様にres.item[i]の後ろに記述することによって表すことができる。
実際にコメントを表示する際にはdivタグをレイヤーとしてその中に表示させる。その際のdivタグの属性であるIDやz-indexの値を18行目のdiv_numによって表している。現在div_numはdivタグの総数に100を加えた値になっている。
100を加えている理由はz-indexにある。このz-indexとはHTMLで表示する際の深さにあたるもので、表示が重なった場合この値が高いほどページ上で上に表示される(z-indexを設定してない場合はデフォルト値の0が設定される)。このためコメントをレイヤーで貼り付ける際、そもそものページに設定されているz-indexよりも高い値を設定する必要がある(そうしなければ、重なった場合コメントがそれよりも下に表示されてしまう)。しかし、現在は取得したページのz-indexの最大値を知る機構が作れていないため、不完全ではあるが100を加える事により対処している。
実際に貼り付けるdivの作成を19行目のsetCommentDivで行っている。SetCommentDivのソースは以下に示す通りである。
引数はdivId、divLeft、divTop、divCommentの4つで、divIdは属性name、id、z-indexで使用、divLeftとdivTopは属性left、topで使用、divCommentはコメントと属性sytleのカラー設定で使用する。
今回カラーを設定するにはコメントの最後に「**」を付けた後に指定する事によって設定できるようにする。そのためコメントにカラー設定がされているか判断する必要があり、それを3行目のcheckColor関数で行っている。
checkColor関数のソースは以下に示す通りである
引数のcolorStrを対象にコメントにカラー設定がされているかの処理を行う。カラー設定がされているかの判断は正規表現を使って行っている。正規表現はmatchメソッドによって使うことができ、3行目の部分である。この正規表現とは設定したパターンに文字列が合うかどうかを判断できるものであり、match( パターン , 対象の文字列)とすることにより実行できる。今回パターンには英単語での色指定とrgbによる書式2通り(#xxxxxx 、 rgb(xxx, xxx, xxx))に対応した。このパターンにマッチした場合はtrueを返し、マッチしなかった場合はfalseを返すようになっている。(checkColor関数の説明終了)
setCommentDiv関数ではcheckColor関数で判断した後、カラー設定されている場合は文字列をコメント部分とカラー部分で切り離し、それぞれdivComment、divColorに値を入れ、カラー設定されていない場合は、DEF_COLOR(デフォルトで設定しているカラー)の値をdivColorに入れる。この後にそれぞれの値を元にDOMにてdivタグを作成し、それを返す。(setCommentDiv関数の説明終了)
setCommentAll関数はsetCommentDivより貼り付けるdivエレメントを受け取りbodyタグが存在すればbodyタグに、無い場合はhtmlタグにdivエレメントを加えている。これをコメントの数だけ行う事によりコメントすべてをページ上に表示している。
comment_all.phpについて
comment_all.phpは指定されたURLを対象にコメントをすべて返すPHPプログラムである。このプログラムはURLに対応したコメントをデータベースから取得している。このため、coment_all.phpの説明の前にデータベースの構造について説明する。
データベースの2つのテーブルから構成されている。テーブルの仕様を以下に示す。
comment_listテーブルはコメントに関する情報に、url_listはurlに関する情報に使用する。すべてNOT NULLにしているのはデータベースへの負荷を減らすためである。
次にそれぞれのカラム値がどのような意味を持っているかを以下に示す。
カラム名 | 使用目的 |
id | 各コメントを識別するため |
comment | コメント本文 |
regist_time | コメントを登録した日時 |
url_id | URL番号。テーブルurl_listに対応するための番号で、この値とurl_listのidの値がURLとコメントを結び付けている。 |
x_val | コメントのX座標(HTMLのleft) |
y_val | コメントのY座標(HTMLのtop) |
color | コメントの背景カラー |
delete_flg(※1) | コメントの削除フラグ |
user_id(※1) | コメントを書き込んだ人のユーザID |
char_color(※1) | コメント文字のカラー |
font_size(※1) | コメント文字の大きさ |
※1:現在はテーブルの定義のみで未使用。
カラム名 | 使用目的 |
id | 各URLを識別するための番号 |
url | URL |
regist_time | URLを登録した日時 |
現在使用していないカラムが存在するが、これは今後拡張予定があるためである。
これらのテーブルよりcomment_all.phpは値を取得している。以下にcomment_all.phpのソースを示す
このプログラムはURLに対応したコメントデータすべてをJSON書式で出力することを目的としている。
手順としては、まず対象のURLのidを取得し、次にそのid(url_id)からコメントデータを取得し、最後にJSON書式の変換を行っている。
以下にソースではどのようになっているかを説明していく。
①テーブルurl_listよりid値の取得
これをソースでは3~9行目で行っている。3行目のpg_connectでデータベースの接続を行い、6行目の$_POSTでurlの値を受け取り、7~9行目でデータベースへクエリを送りurl対象のレコードを得ている。尚受け取ったレコードデータ(aryCol)はカラム名をハッシュとする連想配列になっている。
②、テーブルcomment_listより①で取得したid(url_id)を元にコメントデータを取得
これをソースでは11、12行目で行っており、方法は①と同様である。
テーブルurl_listのカラムidとテーブルcoment_listのカラムurl_idが一致するレコードすべてをcomment_listより取得している。
③、②で取得したデータをJSON書式で記述し出力する。
これをソースでは14行目以降で行っている。14行目でレコード数を数え、その回数だけループさせることによってJSON書式を生成している。尚23~32行目のEOSはヒアドキュメントを使いダブルクォーテーションやシングルクォーテーション等を自由に使えるようにしている。
生成した結果を41行目のechoで出力している。
・コメント表示した結果
例としてGoogleのトップページにコメントを表示した。コメントデータはあらかじめ書データベースに登録したものである。尚、左上の「insert」と書かれているボックスがあるが、これは書き込むときに使用するものであり、表示には関係無い。
ユーザがページを表示する際にGresemonkeyによって、コメントを書き込むためのボックスを設置する。このボックスはテキストエリアとinsertボタンがついており、ドラッグも可能な仕様にする。insertボタンを押す事により、ボックスのすぐ上の位置にコメントを登録する。このシステムの流れを下図に示す。
ページ表示時に書き込みフォームを登録する以外は、コメント表示のサイト流れは同じである。このボックスを設置する関数setMainLayerのソースは以下の通りである(labo.user.jsより)。
この関数は基本的にはボックスを作成して、それをページに貼り付けているだけだが、ドラッグやinsertボタンのイベントを付加している。
1行目のif文は、ページ内にframeやiframeタグがあった場合の対策である。もしページ内に別ページを表示することができるframeやiframeが使われていた場合、Greasemonkeyがその分動作してしまいSetMainLayer関数もその分呼ばれてボックスを設置してしまう。ページ内にボックスは2つ以上必要無いため、この関数が処理されるのはトップページのみにしている。
3~7行目でボックスの形のみをページ内に貼り付けている。(この状態ではドラッグもコメント登録もできない)
8行目以降でボックスに対してドラッグやコメント登録のイベントを登録している。
9~11行目でドラッグのイベントを登録している。ドラッグには3つのイベントをつかっており、mousedown(ボックスの上でマウスを動かしている時)、mousemove(マウスを押している時)、mouseup(マウスを離した時)でそれぞれ関数dragstart、dragmove、dragendを呼ぶようにしている。この3つの関数のソースを以下に示す。
これら3つ関数はdragFlagによってマウスが押されているか押されていないかを判断しており、マウス押した時にtrue、離した時にfalseになる。
まずボックスの上でマウスを押した時はdragFlagをtrueにして、ボックスの位置情報(正確にはボックスの左上の座標)をoffsetX、offsetYにそれぞれ保存する。次にマウスがボックスの上を動いているときだが、マウスを押した後、離していない場合は、押しっぱなしでありドラック状態であると判断し、常に押した時の座標との差分だけボックスの位置を移動するようにしている。最後にマウスを離した時dragFlagがfalseになりドラッグが終了する。
12、13行目でinserボタンが押された時の処理、すなわちコメント登録の関数をボックスに登録している。以下にコメント登録の関数setCommentのソースを示す。
この関数がやっていることは、コメントデータの値の取得とコメントデータ表示以外は4.5.1で説明したsetCommentAll関数と同じGM_xmlhttpRequestを実行しているだけである。
コメントの取得は3~5行目で行っており、コメントデータの表示6~12行目で行っている。尚、コメントデータの表示はsetCommentAllで使っていたsetCommentDiv関数を使っている。
13行目以降でコメントデータを登録するPHPプログラムcomment_set.phpにアクセスしてコメントをデータベースに登録している。GM_xmlhttpRequestはsetCommentAllの時と比べdataの値(POSTの値)が増えonloadでの処理が変わっている。onloadの処理内容はcomment_set.phpがデータベースの登録に成功したかどうかの判断で使用している。comment_set.phpは登録に成功した場合はsuccessの文字列を返すようになっており、success以外の文字列が返ってきた場合は、comment_set.phpがエラーを起こしたと判断できる。よってsuccess以外が返ってきた場合は保存に失敗したアラートを表示されるように処理をしている。
・comment_set.phpについて
comment_set.phpはPOSTで受け取った値をチェックし、問題がない場合はデータベースへ登録を行っている。ソースを以下に示す。
データベースのアクセスやクエリに関してはcomment_all.phpと同様である。
5~19行目でPOSTされたデータをチェックしている。14行目でカラーのチェックにcheckcolor関数を使っているが、これは3.3.1で使ったcheckcolorと同じことをPHPで行っている。
この関数はPOSTの値をチェック後、まずPOSTで取得したURLを元にテーブルurl_listよりidを取得する。方法はcomment_all.phpの時と同様である。次にidを取得できた場合はそのまま、コメントデータをテーブルcomment_listに登録する。もしidを取得できなかった場合はurl_listに新しく追加してからコメントデータの登録を行う。
最後に登録に問題が無ければsuccessの文字列を返し終了する。
コメントを貼り付けるシステムはこの4.5.1と4.5.2で解説したようにして、表示と書き込みを行っている。
・コメント書き込みの結果(書き込み前、書き込み後)
本研究では途中システム設計に失敗したことはあったが、Gresemonkeyを使用する事により、目標であるコメントを貼り付けるシステムを作成することができた。しかし問題点として、「コメントの収集がつかない」「同一性保持権」が依然解決できていない。
今後はこの問題を解決することを目標に本研究を続けていきたい。また、現在この問題点の「コメントの収集がつかない」件に関しては対応策がある。この対応策はユーザのグループ化である。ユーザ一人一人を管理し、またグループでの管理もすることができるようにする。これはコメントの収集がつかない原因が、どのユーザも書き込めてしまうというところにあり、特定のユーザ同士しか使わない環境であればコメントが乱雑になりにくくなると考えたためである。
本研究を通してAjaxを使ったシステムは様々な可能性あると感じられた。ただし、技術が発展したからといって需要がみたされるわけではない。技術を有効に使ってこそ実際の需要に繋がるため、常に何が重要かを見極める視点が今後は更に必要になってくるなと感じた。
[1] Dave Crane, Eric Pascarello, Darren James [著]柏原 正三、綱代 淳、星 睦 [訳] "Ajaxイン・アクション" インプレス
[2] David Flanagan [著]村上 列 [訳] "第5版 JavaScript" オライリー・ジャパン
[3] 高山 恭介 [著] "Greasemonkey スクリプティングTIPS&SAMPLES" 秀和システム