Module: CGI::Util

Included in:
CGI, CGI
Defined in:
lib/cgi/core.rb,
lib/cgi/util.rb,
lib/cgi/util.rb,
escape/escape.c

Constant Summary collapse

TABLE_FOR_ESCAPE_HTML__ =

The set of special characters and their escaped values

{
  "'" => ''',
  '&' => '&',
  '"' => '"',
  '<' => '&lt;',
  '>' => '&gt;',
}
RFC822_DAYS =

Abbreviated day-of-week names specified by RFC 822

%w[ Sun Mon Tue Wed Thu Fri Sat ]
RFC822_MONTHS =

Abbreviated month names specified by RFC 822

%w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
@@accept_charset =

:nodoc:

"UTF-8"

Instance Method Summary collapse

Instance Method Details

#escape(string) ⇒ Object

URL-encode a string.

url_encoded_string = CGI.escape("'Stop!' said Fred")
   # => "%27Stop%21%27+said+Fred"


12
13
14
15
16
17
# File 'lib/cgi/util.rb', line 12

def escape(string)
  encoding = string.encoding
  string.b.gsub(/([^ a-zA-Z0-9_.\-~]+)/) do |m|
    '%' + m.unpack('H2' * m.bytesize).join('%').upcase
  end.tr(' ', '+').force_encoding(encoding)
end

#escapeElement(string, *elements) ⇒ Object Also known as: escape_element

Escape only the tags of certain HTML elements in string.

Takes an element or elements or array of elements. Each element is specified by the name of the element, without angle brackets. This matches both the start and the end tag of that element. The attribute list of the open tag will also be escaped (for instance, the double-quotes surrounding attribute values).

print CGI.escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
  # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"

print CGI.escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
  # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"


140
141
142
143
144
145
146
147
148
149
# File 'lib/cgi/util.rb', line 140

def escapeElement(string, *elements)
  elements = elements[0] if elements[0].kind_of?(Array)
  unless elements.empty?
    string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
      CGI.escapeHTML($&)
    end
  else
    string
  end
end

#escapeHTML(string) ⇒ Object Also known as: escape_html, h

Escape special characters in HTML, namely ‘&"<>

CGI.escapeHTML('Usage: foo "bar" <baz>')
   # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/cgi/util.rb', line 41

def escapeHTML(string)
  enc = string.encoding
  unless enc.ascii_compatible?
    if enc.dummy?
      origenc = enc
      enc = Encoding::Converter.asciicompat_encoding(enc)
      string = enc ? string.encode(enc) : string.b
    end
    table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
    string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
    string.encode!(origenc) if origenc
    return string
  end
  string.gsub(/['&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
end

#pretty(string, shift = " ") ⇒ Object

Prettify (indent) an HTML string.

string is the HTML string to indent. shift is the indentation unit to use; it defaults to two spaces.

print CGI.pretty("<HTML><BODY></BODY></HTML>")
  # <HTML>
  #   <BODY>
  #   </BODY>
  # </HTML>

print CGI.pretty("<HTML><BODY></BODY></HTML>", "\t")
  # <HTML>
  #         <BODY>
  #         </BODY>
  # </HTML>


211
212
213
214
215
216
217
218
219
220
# File 'lib/cgi/util.rb', line 211

def pretty(string, shift = "  ")
  lines = string.gsub(/(?!\A)<.*?>/m, "\n\\0").gsub(/<.*?>(?!\n)/m, "\\0\n")
  end_pos = 0
  while end_pos = lines.index(/^<\/(\w+)/, end_pos)
    element = $1.dup
    start_pos = lines.rindex(/^\s*<#{element}/i, end_pos)
    lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/, "\n" + shift) + "__"
  end
  lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/, '\1')
end

#rfc1123_date(time) ⇒ Object

Format a Time object as a String using the format specified by RFC 1123.

CGI.rfc1123_date(Time.now)
  # Sat, 01 Jan 2000 00:00:00 GMT


187
188
189
190
191
192
# File 'lib/cgi/util.rb', line 187

def rfc1123_date(time)
  t = time.clone.gmtime
  return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
                RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
                t.hour, t.min, t.sec)
end

#unescape(string, encoding = @@accept_charset) ⇒ Object

URL-decode a string with encoding(optional).

string = CGI.unescape("%27Stop%21%27+said+Fred")
   # => "'Stop!' said Fred"


22
23
24
25
26
27
# File 'lib/cgi/util.rb', line 22

def unescape(string,encoding=@@accept_charset)
  str=string.tr('+', ' ').b.gsub(/((?:%[0-9a-fA-F]{2})+)/) do |m|
    [m.delete('%')].pack('H*')
  end.force_encoding(encoding)
  str.valid_encoding? ? str : str.force_encoding(string.encoding)
end

#unescapeElement(string, *elements) ⇒ Object Also known as: unescape_element

Undo escaping such as that done by CGI.escapeElement()

print CGI.unescapeElement(
        CGI.escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
  # "&lt;BR&gt;<A HREF="url"></A>"

print CGI.unescapeElement(
        CGI.escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
  # "&lt;BR&gt;<A HREF="url"></A>"


160
161
162
163
164
165
166
167
168
169
# File 'lib/cgi/util.rb', line 160

def unescapeElement(string, *elements)
  elements = elements[0] if elements[0].kind_of?(Array)
  unless elements.empty?
    string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
      unescapeHTML($&)
    end
  else
    string
  end
end

#unescapeHTML(string) ⇒ Object Also known as: unescape_html

Unescape a string that has been HTML-escaped

CGI.unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
   # => "Usage: foo \"bar\" <baz>"


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cgi/util.rb', line 65

def unescapeHTML(string)
  enc = string.encoding
  unless enc.ascii_compatible?
    if enc.dummy?
      origenc = enc
      enc = Encoding::Converter.asciicompat_encoding(enc)
      string = enc ? string.encode(enc) : string.b
    end
    string = string.gsub(Regexp.new('&(apos|amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
      case $1.encode(Encoding::US_ASCII)
      when 'apos'                then "'".encode(enc)
      when 'amp'                 then '&'.encode(enc)
      when 'quot'                then '"'.encode(enc)
      when 'gt'                  then '>'.encode(enc)
      when 'lt'                  then '<'.encode(enc)
      when /\A#0*(\d+)\z/        then $1.to_i.chr(enc)
      when /\A#x([0-9a-f]+)\z/i  then $1.hex.chr(enc)
      end
    end
    string.encode!(origenc) if origenc
    return string
  end
  return string unless string.include? '&'
  charlimit = case enc
              when Encoding::UTF_8; 0x10ffff
              when Encoding::ISO_8859_1; 256
              else 128
              end
  string.gsub(/&(apos|amp|quot|gt|lt|\#[0-9]+|\#[xX][0-9A-Fa-f]+);/) do
    match = $1.dup
    case match
    when 'apos'                then "'"
    when 'amp'                 then '&'
    when 'quot'                then '"'
    when 'gt'                  then '>'
    when 'lt'                  then '<'
    when /\A#0*(\d+)\z/
      n = $1.to_i
      if n < charlimit
        n.chr(enc)
      else
        "&##{$1};"
      end
    when /\A#x([0-9a-f]+)\z/i
      n = $1.hex
      if n < charlimit
        n.chr(enc)
      else
        "&#x#{$1};"
      end
    else
      "&#{match};"
    end
  end
end