sync blead with Update Archive::Extract 0.34
[p5sagit/p5-mst-13.2.git] / lib / CGI / Util.pm
CommitLineData
3d1a2ec4 1package CGI::Util;
2
3use strict;
ac734d8b 4use vars qw($VERSION @EXPORT_OK @ISA $EBCDIC @A2E @E2A);
3d1a2ec4 5require Exporter;
6@ISA = qw(Exporter);
f8a128a9 7@EXPORT_OK = qw(rearrange rearrange_header make_attributes unescape escape
2ed511ec 8 expires ebcdic2ascii ascii2ebcdic);
3d1a2ec4 9
8c32f149 10$VERSION = '1.5_01';
3d1a2ec4 11
12$EBCDIC = "\t" ne "\011";
13548fdf 13# (ord('^') == 95) for codepage 1047 as on os390, vmesa
14@A2E = (
ac734d8b 15 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 21, 11, 12, 13, 14, 15,
16 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
17 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97,
18 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111,
19 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214,
20 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109,
21 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150,
22 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7,
23 32, 33, 34, 35, 36, 37, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
24 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255,
25 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188,
26 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171,
27 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119,
28 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89,
29 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87,
30 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223
31 );
13548fdf 32@E2A = (
ac734d8b 33 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15,
34 16, 17, 18, 19,157, 10, 8,135, 24, 25,146,143, 28, 29, 30, 31,
35 128,129,130,131,132,133, 23, 27,136,137,138,139,140, 5, 6, 7,
36 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26,
37 32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124,
38 38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94,
39 45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63,
40 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34,
41 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177,
42 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164,
43 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174,
44 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215,
45 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245,
46 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255,
47 92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213,
48 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159
49 );
13548fdf 50
51if ($EBCDIC && ord('^') == 106) { # as in the BS2000 posix-bc coded character set
ac734d8b 52 $A2E[91] = 187; $A2E[92] = 188; $A2E[94] = 106; $A2E[96] = 74;
53 $A2E[123] = 251; $A2E[125] = 253; $A2E[126] = 255; $A2E[159] = 95;
54 $A2E[162] = 176; $A2E[166] = 208; $A2E[168] = 121; $A2E[172] = 186;
55 $A2E[175] = 161; $A2E[217] = 224; $A2E[219] = 221; $A2E[221] = 173;
56 $A2E[249] = 192;
13548fdf 57
ac734d8b 58 $E2A[74] = 96; $E2A[95] = 159; $E2A[106] = 94; $E2A[121] = 168;
59 $E2A[161] = 175; $E2A[173] = 221; $E2A[176] = 162; $E2A[186] = 172;
60 $E2A[187] = 91; $E2A[188] = 92; $E2A[192] = 249; $E2A[208] = 166;
61 $E2A[221] = 219; $E2A[224] = 217; $E2A[251] = 123; $E2A[253] = 125;
62 $E2A[255] = 126;
ac734d8b 63 }
13548fdf 64elsif ($EBCDIC && ord('^') == 176) { # as in codepage 037 on os400
65 $A2E[10] = 37; $A2E[91] = 186; $A2E[93] = 187; $A2E[94] = 176;
66 $A2E[133] = 21; $A2E[168] = 189; $A2E[172] = 95; $A2E[221] = 173;
67
68 $E2A[21] = 133; $E2A[37] = 10; $E2A[95] = 172; $E2A[173] = 221;
69 $E2A[176] = 94; $E2A[186] = 91; $E2A[187] = 93; $E2A[189] = 168;
3d1a2ec4 70}
71
72# Smart rearrangement of parameters to allow named parameter
f8a128a9 73# calling. We do the rearrangement if:
3d1a2ec4 74# the first parameter begins with a -
f8a128a9 75
3d1a2ec4 76sub rearrange {
f8a128a9 77 my ($order,@param) = @_;
78 my ($result, $leftover) = _rearrange_params( $order, @param );
79 push @$result, make_attributes( $leftover, defined $CGI::Q ? $CGI::Q->{escape} : 1 )
80 if keys %$leftover;
81 @$result;
82}
83
84sub rearrange_header {
85 my ($order,@param) = @_;
86
87 my ($result,$leftover) = _rearrange_params( $order, @param );
88 push @$result, make_attributes( $leftover, 0, 1 ) if keys %$leftover;
89
90 @$result;
91}
92
93sub _rearrange_params {
3d1a2ec4 94 my($order,@param) = @_;
f8a128a9 95 return [] unless @param;
3d1a2ec4 96
97 if (ref($param[0]) eq 'HASH') {
98 @param = %{$param[0]};
99 } else {
f8a128a9 100 return \@param
3d1a2ec4 101 unless (defined($param[0]) && substr($param[0],0,1) eq '-');
102 }
103
104 # map parameters into positional indices
105 my ($i,%pos);
106 $i = 0;
107 foreach (@$order) {
6b4ac661 108 foreach (ref($_) eq 'ARRAY' ? @$_ : $_) { $pos{lc($_)} = $i; }
3d1a2ec4 109 $i++;
110 }
111
112 my (@result,%leftover);
113 $#result = $#$order; # preextend
114 while (@param) {
6b4ac661 115 my $key = lc(shift(@param));
3d1a2ec4 116 $key =~ s/^\-//;
117 if (exists $pos{$key}) {
118 $result[$pos{$key}] = shift(@param);
119 } else {
120 $leftover{$key} = shift(@param);
121 }
122 }
123
f8a128a9 124 return \@result, \%leftover;
3d1a2ec4 125}
126
127sub make_attributes {
128 my $attr = shift;
129 return () unless $attr && ref($attr) && ref($attr) eq 'HASH';
29ddc2a4 130 my $escape = shift || 0;
f8a128a9 131 my $do_not_quote = shift;
132
133 my $quote = $do_not_quote ? '' : '"';
134
3d1a2ec4 135 my(@att);
136 foreach (keys %{$attr}) {
137 my($key) = $_;
138 $key=~s/^\-//; # get rid of initial - if present
69c89ae7 139
140 # old way: breaks EBCDIC!
141 # $key=~tr/A-Z_/a-z-/; # parameters are lower case, use dashes
142
143 ($key="\L$key") =~ tr/_/-/; # parameters are lower case, use dashes
144
3d1a2ec4 145 my $value = $escape ? simple_escape($attr->{$_}) : $attr->{$_};
f8a128a9 146 push(@att,defined($attr->{$_}) ? qq/$key=$quote$value$quote/ : qq/$key/);
3d1a2ec4 147 }
148 return @att;
149}
150
151sub simple_escape {
6b4ac661 152 return unless defined(my $toencode = shift);
153 $toencode =~ s{&}{&}gso;
154 $toencode =~ s{<}{&lt;}gso;
155 $toencode =~ s{>}{&gt;}gso;
156 $toencode =~ s{\"}{&quot;}gso;
157# Doesn't work. Can't work. forget it.
158# $toencode =~ s{\x8b}{&#139;}gso;
159# $toencode =~ s{\x9b}{&#155;}gso;
3d1a2ec4 160 $toencode;
161}
162
13548fdf 163sub utf8_chr {
69c89ae7 164 my $c = shift(@_);
8c32f149 165 if ($] >= 5.006){
166 require utf8;
167 my $u = chr($c);
168 utf8::encode($u); # drop utf8 flag
169 return $u;
170 }
69c89ae7 171 if ($c < 0x80) {
172 return sprintf("%c", $c);
173 } elsif ($c < 0x800) {
174 return sprintf("%c%c", 0xc0 | ($c >> 6), 0x80 | ($c & 0x3f));
175 } elsif ($c < 0x10000) {
176 return sprintf("%c%c%c",
177 0xe0 | ($c >> 12),
178 0x80 | (($c >> 6) & 0x3f),
179 0x80 | ( $c & 0x3f));
180 } elsif ($c < 0x200000) {
181 return sprintf("%c%c%c%c",
182 0xf0 | ($c >> 18),
183 0x80 | (($c >> 12) & 0x3f),
184 0x80 | (($c >> 6) & 0x3f),
185 0x80 | ( $c & 0x3f));
186 } elsif ($c < 0x4000000) {
187 return sprintf("%c%c%c%c%c",
188 0xf8 | ($c >> 24),
189 0x80 | (($c >> 18) & 0x3f),
190 0x80 | (($c >> 12) & 0x3f),
191 0x80 | (($c >> 6) & 0x3f),
192 0x80 | ( $c & 0x3f));
193
194 } elsif ($c < 0x80000000) {
195 return sprintf("%c%c%c%c%c%c",
cff99809 196 0xfc | ($c >> 30),
69c89ae7 197 0x80 | (($c >> 24) & 0x3f),
198 0x80 | (($c >> 18) & 0x3f),
199 0x80 | (($c >> 12) & 0x3f),
200 0x80 | (($c >> 6) & 0x3f),
201 0x80 | ( $c & 0x3f));
202 } else {
13548fdf 203 return utf8_chr(0xfffd);
69c89ae7 204 }
205}
206
3d1a2ec4 207# unescape URL-encoded data
208sub unescape {
29ddc2a4 209 shift() if @_ > 0 and (ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass));
3d1a2ec4 210 my $todecode = shift;
211 return undef unless defined($todecode);
212 $todecode =~ tr/+/ /; # pluses become spaces
213 if ($EBCDIC) {
214 $todecode =~ s/%([0-9a-fA-F]{2})/chr $A2E[hex($1)]/ge;
215 } else {
8c32f149 216 # handle surrogate pairs first -- dankogai
217 $todecode =~ s{
218 %u([Dd][89a-bA-B][0-9a-fA-F]{2}) # hi
219 %u([Dd][c-fC-F][0-9a-fA-F]{2}) # lo
220 }{
221 utf8_chr(
222 0x10000
223 + (hex($1) - 0xD800) * 0x400
224 + (hex($2) - 0xDC00)
225 )
226 }gex;
69c89ae7 227 $todecode =~ s/%(?:([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/
228 defined($1)? chr hex($1) : utf8_chr(hex($2))/ge;
3d1a2ec4 229 }
230 return $todecode;
231}
232
233# URL-encode data
ad6402bd 234#
235# We cannot use the %u escapes, they were rejected by W3C, so the official
236# way is %XX-escaped utf-8 encoding.
237# Naturally, Unicode strings have to be converted to their utf-8 byte
238# representation. (No action is required on 5.6.)
239# Byte strings were traditionally used directly as a sequence of octets.
240# This worked if they actually represented binary data (i.e. in CGI::Compress).
241# This also worked if these byte strings were actually utf-8 encoded; e.g.,
242# when the source file used utf-8 without the apropriate "use utf8;".
243# This fails if the byte string is actually a Latin 1 encoded string, but it
244# was always so and cannot be fixed without breaking the binary data case.
245# -- Stepan Kasal <skasal@redhat.com>
246#
3d1a2ec4 247sub escape {
ac734d8b 248 shift() if @_ > 1 and ( ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass));
3d1a2ec4 249 my $toencode = shift;
250 return undef unless defined($toencode);
ad6402bd 251 utf8::encode($toencode) if ($] > 5.007 && utf8::is_utf8($toencode));
92dffb52 252 if ($EBCDIC) {
8869a4b7 253 $toencode=~s/([^a-zA-Z0-9_.~-])/uc sprintf("%%%02x",$E2A[ord($1)])/eg;
92dffb52 254 } else {
8869a4b7 255 $toencode=~s/([^a-zA-Z0-9_.~-])/uc sprintf("%%%02x",ord($1))/eg;
92dffb52 256 }
3d1a2ec4 257 return $toencode;
258}
259
260# This internal routine creates date strings suitable for use in
261# cookies and HTTP headers. (They differ, unfortunately.)
262# Thanks to Mark Fisher for this.
263sub expires {
264 my($time,$format) = @_;
265 $format ||= 'http';
266
267 my(@MON)=qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
268 my(@WDAY) = qw/Sun Mon Tue Wed Thu Fri Sat/;
269
270 # pass through preformatted dates for the sake of expire_calc()
271 $time = expire_calc($time);
272 return $time unless $time =~ /^\d+$/;
273
274 # make HTTP/cookie date string from GMT'ed time
275 # (cookies use '-' as date separator, HTTP uses ' ')
276 my($sc) = ' ';
277 $sc = '-' if $format eq "cookie";
278 my($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime($time);
279 $year += 1900;
280 return sprintf("%s, %02d$sc%s$sc%04d %02d:%02d:%02d GMT",
281 $WDAY[$wday],$mday,$MON[$mon],$year,$hour,$min,$sec);
282}
283
284# This internal routine creates an expires time exactly some number of
285# hours from the current time. It incorporates modifications from
286# Mark Fisher.
287sub expire_calc {
288 my($time) = @_;
289 my(%mult) = ('s'=>1,
290 'm'=>60,
291 'h'=>60*60,
292 'd'=>60*60*24,
293 'M'=>60*60*24*30,
294 'y'=>60*60*24*365);
295 # format for time can be in any of the forms...
296 # "now" -- expire immediately
297 # "+180s" -- in 180 seconds
298 # "+2m" -- in 2 minutes
299 # "+12h" -- in 12 hours
300 # "+1d" -- in 1 day
301 # "+3M" -- in 3 months
302 # "+2y" -- in 2 years
303 # "-3m" -- 3 minutes ago(!)
304 # If you don't supply one of these forms, we assume you are
305 # specifying the date yourself
306 my($offset);
307 if (!$time || (lc($time) eq 'now')) {
8869a4b7 308 $offset = 0;
3d1a2ec4 309 } elsif ($time=~/^\d+/) {
8869a4b7 310 return $time;
311 } elsif ($time=~/^([+-]?(?:\d+|\d*\.\d*))([smhdMy])/) {
312 $offset = ($mult{$2} || 1)*$1;
3d1a2ec4 313 } else {
8869a4b7 314 return $time;
3d1a2ec4 315 }
316 return (time+$offset);
317}
318
2ed511ec 319sub ebcdic2ascii {
320 my $data = shift;
321 $data =~ s/(.)/chr $E2A[ord($1)]/ge;
322 $data;
323}
324
325sub ascii2ebcdic {
326 my $data = shift;
327 $data =~ s/(.)/chr $A2E[ord($1)]/ge;
328 $data;
329}
330
3d1a2ec4 3311;
ba056755 332
333__END__
334
335=head1 NAME
336
337CGI::Util - Internal utilities used by CGI module
338
339=head1 SYNOPSIS
340
341none
342
343=head1 DESCRIPTION
344
345no public subroutines
346
347=head1 AUTHOR INFORMATION
348
349Copyright 1995-1998, Lincoln D. Stein. All rights reserved.
350
351This library is free software; you can redistribute it and/or modify
352it under the same terms as Perl itself.
353
354Address bug reports and comments to: lstein@cshl.org. When sending
355bug reports, please provide the version of CGI.pm, the version of
356Perl, the name and version of your Web server, and the name and
357version of the operating system you are using. If the problem is even
358remotely browser dependent, please provide information about the
359affected browers as well.
360
361=head1 SEE ALSO
362
363L<CGI>
364
365=cut