<a href=”xxx”>や、<param name=”FlashVars” value=”xxx”>のxxxに&(ampersand アンパサンド)が含まれる場合、正しい書き方ができていますでしょうか?
追記(2016/8/31)
最近ではAccelerated Mobile Pages(AMP)を有効にするパラメータとして本当にampが使われてamp=1とかを利用するプラグインなどが出てきました。今時ではXHTMLも使わないでしょうし& + ;以外の記号 でもエラー部分を消さずに &amp + ;以外の記号 相当とみなしてパースが進行するようになっているので気にする必要もないかもしれません。
- <link rel=”amphtml” href=”/hoge?amp=1″ /> OK
- <link rel=”amphtml” href=”/hoge?param1=1&amp=1″ /> OK
- <link rel=”amphtml” href=”/hoge?param1=1&=1″ /> NG
とはいえ、amphtml以外のpathが/ampで終わらないようにできるのであれば、 /amp を query string の amp=1 に、例えばmod_rewriteならば
1 |
RewriteRule ^/?(.*)/amp$ /$1?amp=1 [QSA,L] |
のようにwebサーバ側でrewiteする方が気にすることも減って無難かもしれません。
追記終了
複数の変数/パラメータを渡したい場合、その変数/パラメータの名前がampだったり、値に&が含まれている場合を考えていきます。
書くまでも無い当たり前なネタなのかもしれませんが、AdobeサイトのFlashVars解説にも誤記が あったり、「表示」⇒「ページのソース」だけで学んでいる人は気づかなかったりするかもしれないので、関連仕様書を一まとめにしておく意味でも書いておき ます。大きな問題であるわけでもなく気にしなければしないですませられますが、実体参照と同じ名前の変数を使いたい場合のように機能的に困る場合があります。
クイズです。次のHTMLをノートパッドなどのテキストエディタで作成してhoge.html等適当な名前で保存します。
1 2 3 4 5 6 7 8 |
<html> <head><title></title></head> <body> <p> <a href="/?hoge=123&=567">Copy me!</a><!-- Wrong version --> </p> </body> </html> |
次にこのファイルをお好きなwebブラウザでこのHTMLファイルを開き、アンカーのリンク先を右クリック等ででクリップボードにコピーし、テキストエディタにペーストします。どうなるか予想できましたでしょうか。
Windowsの実験機で試した結果は以下の通りです。
FF3⇒notepad | file:///?hoge=123&=567 |
Safari4⇒notepad | file:///?hoge=123&=567 |
Opera10⇒notepad | file://localhost/?hoge=123&=567 |
IE8⇒notepad | file:///D:/?hoge=123&=567 |
IE7⇒notepad | file:///D:/?hoge=123&=567 |
IE6⇒notepad | file:///D:/?hoge=123&=567 |
IE5.5⇒notepad | file:///D:/?hoge=123&=567 |
hostのあるものやpathにドライブのあるものなどいろいろ面白いですが、今回の本題は123の右です。どこにもampがありません。これは「不幸に も多くのHTMLユーザエージェントは変な実体参照でも適当に問題をシカトして先に進んでしまう。(下記参照)」からです。&=の部分を& amp;quot=や©=などに変えたり、先頭に
1 2 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
を付けたりして(ローカルのファイルでもXML宣言を見てこれをエラーにするブラウザは有りましたか?)いろいろ試してみてください。quotやcopy等では&すら出てこなくなるので間違いにすぐに気づくかもしれません。今まで気づいていなかった方にはとても違和感があるかもしれませんが、パラメータampに値567を渡したい場合の正解は
1 |
<a href="/?hoge=123&amp=567">Copy me!</a> |
になります。Flash PlayerにFlashVarsを<object>の中の<param>で渡したい場合はどうでしょうか。HTMLやXHTMLの世界での話なので、変数p1,p2,ampにそれぞれ値を渡したい場合は
1 |
HTML: <param name="FlashVars" value="p1=foo&p2=bar&amp=baz"> |
1 |
XHTML: <param name="FlashVars" value="p1=foo&p2=bar&amp=baz" /> |
といったものが正しい書き方になります。あとは=前後の%エンコード(Percent-Encoding)(FlashVarsの説明ではURL encodingと書かれていますが、各種のURLencode()のような関数やapplication/x-www-form-urlencodedで使われるエンコードではあの記号はそのまま、この記号は%エンコードという奇々怪々な仕組みも含まれる場合があるので素直に%エンコードと呼び、かつFlashVarsの値はECMAScriptのencodeURIComponent()相当の符号化、つまりUTF-8以外の場合はUTF-8に変換をしてから英数以外は積極的に%エンコードする、というのがさまざまな場合で無難だと思います)もお忘れなく。具体的にはもしFlashVarsで変数p1,p2,ampに&が含まれている値を渡したい場合は次のようになります。(%26はUS- ASCIIのスーパーセットの文字セット-文字符号化では&になります。)
1 |
HTML: <param name="FlashVars" value="p1=H%26M&p2=H%26M&amp=H%26M"> |
1 |
XHTML: <param name="FlashVars" value="p1=H%26M&p2=H%26M&amp=H%26M" /> |
変数側に記号を入れてみたりするのも面白いかもしれません(例外的にNULは文字列終端扱いである模様で、例えば
1 |
<param name="FlashVars" value="hoge%00hoge=hero%00hero"> |
ではswfのhogeにheroが渡されました。実装された詳細仕様は不明です)。href=での%エンコードの話は、サーバ側、アプリケーション側がどうなっているかに依存する、つまりwebサーバやアプリケーションサーバ、CGIもからんできて、単純にこうだとは書くことができません。
では
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> ... <body> ... <object ...> <param name="FlashVars" value="p1=foo&p2=bar&=baz"><!-- Wrong version --> </object> ... </body> <html> |
のように、HTMLとしては期待されていない処理を誘発し、XHTMLとしてはエラーになる属性値(value=の部分)の場合、swfに何が渡ってくるでしょうか(IEはobject要素がparam以外の要素を持てないのでコメント要素は取り除きます)。Flash Player 10.0.42.34との組み合わせで以下の通りです。もっとも、HTMLを解釈してFlash Playerに渡すまでの作業はwebブラウザ(HTMLユーザエージェント、HTMLパーサ)の仕事であり、もしFlash Playerのバージョンで変わるとすればそれはFlashVars自体の仕様の変化となります。また、XHTMLとしてちゃんとエラー扱いになった場合はそもそもFlash Playerが起動しません。
FF3 | swfのampの内容は空 |
Safari4 | swfのampの内容は空 |
Opera10 | swfのampの内容は空 |
IE8 | swfのampの内容は空 |
同時に&amp=bazで正しくswfのampにbazが渡ってくること、そして残念ながら世の中に氾濫している&xxx=bazでも、エラー扱いではなくかつxxxが文字実体参照や数値文字参照にぶつかっていないものはbazが渡ってくることも確認しました。上の href=と同じ状況で予想通りです。
ところでこれはHTMLやXHTMLの世界での話なので、HTML内での記述ではなくて別の外部ファイル(.js等)に分けて、
1 |
Content-Type: application/JavaScript (text/JavaScriptとか。機会があればエントリ作成) |
などで提供される分にはまったく当てはまりません。パラメータhoge,p1,p2,ampにそれぞれ値を渡したい場合はそのまま
1 |
"/?hoge=123&p1=foo&p2=bar&=baz" |
というような文字リテラルでOKです。
HTML内でのonclick=などの属性値ではContent-Script-Typeがapplication/javascript(text/javascript)の場合
1 2 3 |
<... onclick="x="/?hoge=123&amp=567"">とか <... onclick="x='/?hoge=123&amp=567';">とか <... onclick='x="/?hoge=123&amp=567";'> |
のようになります。<script>で記述する場合は内容モデルがHTMLではCDATA, XHTMLでは#PCDATA(下記参照)という別な話が登場して終わらなくなってしまいますので機会があれば別途。とにかく外部ファイルにしてしまうと 決めていれば稀な場合でも大きな問題にならないはずです。
優れたバリデータは文法エラーは当然のこと、誤った処理をさせる部分を検出して警告してくれるので活用されると良いかもしれません。
なお、弊社遊び場の中のFlashアプリの ページでは、ActiveX用とNetscape式plugin用さらにはSWFObject用に同じパラメータを何度も書かなければいけないという問題 とSWFObjectだけではJavaScript依存にしてしまうという問題を解決し、かつActiveXでなくても古いFlash Playerが入っていればExpress Installationが起動するというちょっと素敵なやり方をしています。機会があればご紹介します。
長くなりましたが、以下に根拠となる仕様書(一部ですが)のリンクと、簡単な説明をまとめてみました。ぜひご自身でも読み解いて、上に書かれていることが本当か確認してください。間違いがあったらぜひコメントをお願いします。
<param>要素のvaue=属性の値に関する仕様書の一部の超訳
- HTML 4.01:CDATAです。: http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#edef-PARAM
- XHTML 1.0 Strict:CDATAです。: http://www.w3.org/TR/2002/REC-xhtml1-20020801/dtds.html#dtdentry_xhtml1-strict.dtd_param
<a>要素,<link>要素のhref=属性の値に関する仕様書の一部の超訳
-
- <a>要素のhref=属性
- HTML 4.01:%URIです。: http://www.w3.org/TR/1999/REC-html401-19991224/struct/links.html#edef-A
- <link>要素のhref=属性
- HTML 4.01:%URIです。: http://www.w3.org/TR/1999/REC-html401-19991224/struct/links.html#edef-LINK
- HTML 4.01:%URIはCDATAです。: http://www.w3.org/TR/1999/REC-html401-19991224/sgml/dtd.html#URI
- XHTML 1.0 Strict:%URIです。: http://www.w3.org/TR/2002/REC-xhtml1-20020801/dtds.html#dtdentry_xhtml1-strict.dtd_a
- XHTML 1.0 Strict:%URIはCDATAです。: http://www.w3.org/TR/2002/REC-xhtml1-20020801/dtds.html#dtdentry_xhtml1-strict.dtd_URI
属性値の場合のCDATAに関連する仕様書の一部の超訳
- HTML 4.01:CDATAは文書文字集合のシーケンスで、文字実体を含むことができる。ユーザエージェントは属性値を次のように解釈するべきである。文字実体を文字で置きかえる。LFを無視する。CRやTABは各々SPに置き換える。: http://www.w3.org/TR/1999/REC-html401-19991224/types.html#h-6.2
- HTML 4.01(SGML tutorial):属性値はダブルクォートかシングルクォートで括る。決められた文字だけの場合は括らなくてもいいけど。数値文字参照を利用し て"でダブルクォート、'でシングルクォートを値に含められるし、ダブルクォートで括られている場合は文字実体参照を利 用して"でシングルクォートを値に含められる。: http://www.w3.org/TR/1999/REC-html401-19991224/intro/sgmltut.html#h-3.2.2
- XML 1.0: ダブルクォートかシングルクォートで括る。<と&と括り始めのクォート以外の文字、あるいは「参照」で構成される。: http://www.w3.org/TR/2008/REC-xml-20081126/#NT-AttValue
- XML 1.0: 参照は、実体参照(例:")か、文字参照(例:",")である。: http://www.w3.org/TR/2008/REC-xml-20081126/#NT-Reference
- XHTML 1.0: SGMLでもXMLでも&(ampersand character)は実体参照の開始宣言であるが、不幸にも多くのHTMLユーザエージェントは変な実体参照でも問題をシカトして先に進んでしまう。 XMLユーザエージェントはこの不正な使用を認められない: http://www.w3.org/TR/2002/REC-xhtml1-20020801/#C_12
- HTML 5 (右は訳ではなくて注釈):今までのHTMLではそのものすばりと書かれていなかったようだけど、ついにどうやって間違った文法(前出のHTMLの場合で は&=を&y=にしたり、©=を©dayo=にするといった悲しくも不正な回避方法が使わ れてしまった場合)をパースし続けるかが定義(恐るべし膨大なレガシー資産パワー!)される模様。: (このリンク先はレンダリングするのに結構リソース消費します。クリックするときは注意してください)http://dev.w3.org/html5/spec/Overview.html#tokenizing-character-references
<script>要素に関する仕様書の一部の超訳(参考)
- HTML 4.01:「内容モデル(要は<script>と</script>の間)」は%Scriptです。: http://www.w3.org/TR/1999/REC-html401-19991224/interact/scripts.html#h-18.2.1
- HTML 4.01:%ScriptはCDATAです。: http://www.w3.org/TR/1999/REC-html401-19991224/sgml/dtd.html#Script
- XHTML 1.0 Strict:内容モデルは#PCDATAです。: http://www.w3.org/TR/2002/REC-xhtml1-20020801/dtds.html#dtdentry_xhtml1-strict.dtd_script
要素内容の場合のCDATAに関連する仕様書の一部の超訳(参考)
- HTML 4.01:<style>と<script>では、</が登場するまでを生のまま(数字文字参照や文字実体参照は解釈されません)でアプリケーションに渡してね。: http://www.w3.org/TR/1999/REC-html401-19991224/types.html#h-6.2
- XML 1.0 (参考。CDATA自体の説明ではありません): CDATA sectionは<![CDATA[で始まって、]]>が出てくるまでの中身をマークアップと解釈しない。: http://www.w3.org/TR/2008/REC-xml-20081126/#sec-cdata-sect
- XML 1.0 (参考。CDATA自体の説明でありません): 文字データとマークアップについて: http://www.w3.org/TR/2008/REC-xml-20081126/#syntax
Adobe.comでの説明(頻繁にURLが変わりpermalinkも無いのでたまに修正していますがリンク切れの場合がしょちゅうあります)(参考) (サンプルは適切でないです。修正されることはなさそうです。)
- TechNote (Knowledge Base): <PARAM NAME=FlashVars VALUE=”foo=Hello%20Worldgraph=first+line%0Dsecond+line”> の部分はおそらく
VALUE="foo=Hello%20World&paragraph=first+line%0Dsecond+line"
の意図で書かれたものと思われますが、graphの前に&すらなくなってしまっているのでサンプルの意味がとてもあいまいになってしまっています(2010/1/14時点)。Macromediaからのお引っ越しの際にでも発生したエラーでしょうか: Using FlashVars to pass variables to a SWF - Flex 4: この説明文の<param>等のHTMLでFlashVarsを使用しているもののうち、&lastname=の部分(2010/1 /14時点)は、勝手にlastnameが文字実態参照に使われないことを暗黙のうちにリザーブしています。lastname部分をampやquotやcopyやnbspやltやgtや…にした場合は動作しないことを記載するか、あるいは普通にXHTMLでもHTMLでもampやquotやcopyという変数を渡したいときでも百万が一にも文字実体参照に&lastname;が追加された場合も使えるサンプルにするためにも、
&lastname=
を使用するのが妥当と考えられます: Passing request data with flashVars properties – Communicating with the wrapper - Developer Connection: ユーザの入力を動的にFlashVarsに渡すような場合、%エンコードすることの重要性やURLのような場合はスキーマやホストの確認なども重要であることが書かれています。一読をお勧めします。: Creating more secure SWF web applocations
2010/4/13 文章校正(項目の順序入れ替え)