ブックマークレット用のソースコードはエンコードしてから登録する - JavaScript プログラミング

PROGRAM


ブックマークレット用のソースコードはエンコードしてから登録する

ブックマークレット用の JavaScript コードはURI エンコードしてからブックマークに登録しないと動作不良を起こすことがあるので注意です。

特に注意したいのが、ソースコード内で '%' 記号を使っている場合です。

 

変数sourceにブックマークレットのソースコードが入っている場合は、次のようにすることで、エンコード済みのソースコードを変数encodedSourceに入れられます。

このとき、ソースコードは "javascript:" から始まっている全体が変数sourceに入っています。

var encodedSource = encodeURI(source);

このようにブックマークレットのソースコードをencodeURI関数に通すことで、安全に登録できるブックマークレットを取得できます。

 

エンコードの必要性

ところで、なぜこのようなエンコードが必要かについて見て行きます。

原因

たとえば Mac OS X の Safari 6.0.5 だと、ブックマークにブックマークレットのソースコードを登録したとき、登録済みのソースコードはエンコードされているように見えるのですけど、実際のところはエンコードが必要な文字だけがエンコードされます。

そのため、既にエンコード済みのテキストが混ざったコードを登録した場合に、元のコードと矛盾が生じて、動作しなくなってしまう場合があります。

矛盾が発生するケース

たとえば、次のようなコードで、エンコードをして登録した時とそうでない時とで矛盾が発生します。

javascript:

(

function ()

{

alert(unescape('it%27s sunny'));

}

)

();

このような "it's sunny" というメッセージを表示するコードがあったとします。

 

コードの中で "%27" というのは、単引用符 ( ' ) を文字コードで表現したもので、それを unescape 関数を通すことで、もともとの単引用符に戻しています。

このようにしている理由は、ここでは文字列を単引用符で括って表現しているため、その中では単引用符をそのままでは使えないため、ここでは文字コードを使って表現しています。

エンコードせずに登録した場合に発生する矛盾

このソースコードをそのまま Safari のブックマークに登録すると、次のようにエンコードされて登録されます。

javascript:(function%20(){alert(unescape('it%27s%20sunny'));})();

いっけん問題なさそうなんですが、これが実行前にデコードされると、次のコードに復元されます。

javascript:(function (){alert(unescape('it's sunny'));})();

ここで注目したいのが 'it's sunny' のところです。

 

この部分、もともとのソースコードでは 'it%27s sunny' になっていました。

それが違うものに復元されてしまっています。しかも今回の例では、単引用符で括った文字列内で単引用符が中途半端に含まれてしまうため、このプログラムはエラーで実行できません。

 

なぜ違うものに復元されてしまったかと言えば、ブックマークに登録した時に、エンコード済みの "%27" が「エンコード済み」として扱われてしまい【それ以外の部分】だけがエンコードされてしまったためです。

実行時に復元されるときは【全体】がデコードされるため、元と違うコードになってしまいました。

エンコードしておけば矛盾は生じない

予めencodeURI関数で全体をエンコードしたソースコードを Safari に登録すれば、この問題は回避できます。

javascript:%0A(%0Afunction%20()%0A%7B%0Aalert(unescape('it%2527s%20sunny'));%0A%7D%0A)%0A();

エンコードした時点で、改行文字や空白文字などの情報が "%文字コード" という形に置き換えられているのが判ります。

全体がエンコード済みなので、これを Safari のブックマークに登録しても、これ以上、どこかがエンコードされてしまうことはありません。

 

そして、注目したいのが 'it%2527s%20sunny' のところです。

少し複雑ですが、"%25" というのは文字 "%" を表しています。そして "%20" というのは空白文字です。つまり、もともとの 'it%27s sunny' という文字列がエンコードされた文字列です。

 

本来のソースコード【全体】がエンコードされたものになっているので、これをデコードすれば元のコードに正しく戻ります。

javascript:
(
function ()
{
alert(unescape('it%27s sunny'));
}
)
();

これなら、正しく実行できますね。


[ もどる ]