web-dev-qa-db-ja.com

Ruby / Railsでは、URLの特殊文字をどのようにエンコード/エスケープできますか?

OpenURIをopen(url)に使用する前に、URLをどのようにエンコードまたは「エスケープ」しますか?

OpenURIを使用してリモートURLを開き、XMLを返します。

getresult = open(url).read

問題は、URLに「+」、「&」、「?」などのスペースやその他の文字を含むユーザー入力テキストが含まれている可能性があるため、URLを安全にエスケープする必要があることです。 Net :: HTTPを使用するときに多くの例を見ましたが、OpenURIの例は見つかりませんでした。

また、セッション変数で受け取った同様の文字列をエスケープ解除できるようにする必要があるため、逆関数が必要です。

15
jpw

Rubyには、組み込み [〜#〜] uri [〜#〜] ライブラリ、および Addressable gem、特に Addressable :: URI があります=

私はAddressable :: URIを好みます。それは非常にフル機能であり、query_values=メソッドを使用するときにエンコードを処理します。

URIについていくつかの議論があり、これらの問題が解決するまで、エンコード/エスケープの処理はそのままにしておきます。

2
the Tin Man

URI.escapeは1.9で廃止されたため、使用しないでください。

Railsのアクティブサポートに Hash#to_query が追加されました:

 {foo: 'asd asdf', bar: '"<#$dfs'}.to_query
 # => "bar=%22%3C%23%24dfs&foo=asd+asdf"

また、ご覧のように、クエリパラメータを常に同じ方法で並べようとするため、HTTPキャッシュに適しています。

29
Ernest

Ruby標準ライブラリが助けになります:

require 'uri'
user_text = URI.escape(user_text)
url = "http://example.com/#{user_text}"
result = open(url).read

詳細は RI :: Escapeモジュールのドキュメント を参照してください。また、逆を行うメソッドもあります(unescape

14
Jacob

考慮しなければならない主なことは、キーと値を別々にエスケープする必要があるということですbefore完全なURLを作成します。

完全なURLを取得して後でエスケープしようとするすべてのメソッドは、&または=文字が区切り文字であると想定されていたか、値の一部である可能性があるかを判別できないため、機能しません(またはキーの一部)。

CGIライブラリは、従来は+としてエンコードされていたスペース文字を除いて、適切に機能しているようですが、現在は%20としてエンコードする必要があります。しかし、これは簡単な修正です。

以下を考慮してください。

require 'cgi'

def encode_component(s)
  # The space-encoding is a problem:
  CGI.escape(s).gsub('+','%20')
end

def url_with_params(path, args = {})
  return path if args.empty?
  path + "?" + args.map do |k,v|
    "#{encode_component(k.to_s)}=#{encode_component(v.to_s)}" 
  end.join("&")
end

def params_from_url(url)
  path,query = url.split('?',2)
  return [path,{}] unless query
  q = query.split('&').inject({}) do |memo,p|
    k,v = p.split('=',2)
    memo[CGI.unescape(k)] = CGI.unescape(v)
    memo
  end
  return [path, q]
end

u = url_with_params( "http://example.com",
                            "x[1]"  => "& ?=/",
                            "2+2=4" => "true" )

# "http://example.com?x%5B1%5D=%26%20%3F%3D%2F&2%2B2%3D4=true"

params_from_url(u)
# ["http://example.com", {"x[1]"=>"& ?=/", "2+2=4"=>"true"}]
8
Arsen7