LoginSignup
3

More than 5 years have passed since last update.

Delphi の URLEncode は罠が多い

Last updated at Posted at 2018-05-21

URLEncode の方法

URLEncode は2種類ある

ちょっと古い資料を見ると

System.Net.URLClient.TURI.URLEncode

を使うと出てたりします。
例えば、↓こんな感じです。

TURI.URLEncode
program Project1;

uses
  System.Net.URLClient;

begin
  Writeln(TURI.URLEncode('Hello, Delphi!'));
  // 出力:Hello%2C%20Delphi%21
  Readln;
end.

で、それに従って TURI.URLEncode を使うと

[dcc32 警告] Project1.dpr(7): W1000 シンボル 'URLEncode' を使用することは推奨されていません : 'Use TNetEncoding.URL.Encode'

と、警告が出ます。
警告は消した方がいいよなーということで、警告に従って TNetEncoding.URL.Encode を使うようにしてみます。

TNetEncoding.URL.Encode
program Project1;

uses
  System.NetEncoding;

begin
  Writeln(TNetEncoding.URL.Encode('Hello, Delphi!'));
  // 出力:Hello%2C+Delphi!
  Readln;
end.

警告も出ませんし、上手くいったように見えますが…
出力結果が変わっています!

TURI.URLEncode
Hello%2C%20Delphi%21
TNetEncoding.URL.Encode
Hello%2C+Delphi!

空白が「%20」ではなく「+」になっています。

ちなみに、Docwiki の System.NetEncoding.TURLEncoding の文章は完全に日本語がおかしく

TURLEncoding は、スペース(プラス記号 + として)と、次の予約された URL エンコード文字のみをサポートします: ;:&=+,/?%#[]。 TURLEncoding は、プラス記号(スペースとして)と、どんなパーセント エンコード文字(%2A や %41 など)のデコードもサポートします。

意味が通じません。
日本語に直すと「空白は + 記号になる。また、;:&=+,/?%#[] 文字もエンコードされる」と書いてあります。

しかし、空白を「+」とすると正しく動かない処理もあります。

できれば、空白を「%20」にするか「+」にするか選べるといいですよね。

本当は2種類どころか、もっとある

先ほどの、TNetEncoding.URL.Encode は TURLEncoding.DoEncode を呼び出しますが、そこでは決め打ちで空白は「+」に変換しています。
↓こうなっています。

else if Sp^ = ' ' then
begin
  Rp^ := '+';
  Inc(Rp)
end

では、どうすればいいかというと TURLEncoding.Encode の別バージョンを呼び出せばOKです。

program Project1;

uses
  System.NetEncoding;

begin
  Writeln(TNetEncoding.URL.Encode('Hello, Delphi!', [], []));
  Readln;
end.

TNetEncoding.URL.Encode は overload されたメソッドがあり、上記のように引数を指定すると別バージョンの Encode メソッドが呼ばれます。
別バージョンの TURLEncoding.Encode は第2引数に追加で %xx に変更する文字、第3引数で TEncodeOption を指定できます。
なお、TEncodeOption は下記の様に定義されています。

TEncodeOption = (SpacesAsPlus, EncodePercent);
  • SpacesAsPlus は、空白を「+」に変換します。
  • EncodeParcent は、「%」自身も変換するかどうかを示します。

今回は、空白を %20 にするだけだったので、第2, 第3引数は何も無しです。

また、先ほど「正しく動かない処理もある」と書きました。
なので、処理ごとにメソッドが用意されてればいいなあと思いますよね。
TURLEncoding には、ちゃんと用途ごとのメソッドも用意されています。
それがこちら

function EncodePath(const APath: string; const ExtraUnsafeChars: TUnsafeChars = []): string;
function EncodeAuth(const Auth: string; const ExtraUnsafeChars: TUnsafeChars = []): string; inline;
function EncodeQuery(const AQuery: string; const ExtraUnsafeChars: TUnsafeChars = []): string; inline;
function EncodeForm(const Input: string; const ExtraUnsafeChars: TUnsafeChars = []): string; inline;

です。
名前から何使うか解ると思います(DocWiki にはドキュメントが存在しません…)
コレを使って、先ほどのコードは、こうも書けます。

program Project1;

uses
  System.NetEncoding;

begin
  Writeln(TNetEncoding.URL.EncodeQuery('Hello, Delphi!'));
  Readln;
end.

まとめ

いついかなる時も TNetEncoding.URL.Encode は引数を指定するか、用途ごとの Encode メソッドを使うようにしよう!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3