10Sstevel@tonic-gatepackage CGI::Util; 20Sstevel@tonic-gate 30Sstevel@tonic-gateuse strict; 40Sstevel@tonic-gateuse vars qw($VERSION @EXPORT_OK @ISA $EBCDIC @A2E @E2A); 50Sstevel@tonic-gaterequire Exporter; 60Sstevel@tonic-gate@ISA = qw(Exporter); 70Sstevel@tonic-gate@EXPORT_OK = qw(rearrange make_attributes unescape escape 80Sstevel@tonic-gate expires ebcdic2ascii ascii2ebcdic); 90Sstevel@tonic-gate 10667Sps156622$VERSION = '1.5'; 110Sstevel@tonic-gate 120Sstevel@tonic-gate$EBCDIC = "\t" ne "\011"; 13667Sps156622# (ord('^') == 95) for codepage 1047 as on os390, vmesa 14667Sps156622@A2E = ( 150Sstevel@tonic-gate 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 21, 11, 12, 13, 14, 15, 160Sstevel@tonic-gate 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, 170Sstevel@tonic-gate 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, 180Sstevel@tonic-gate 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, 190Sstevel@tonic-gate 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, 200Sstevel@tonic-gate 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, 210Sstevel@tonic-gate 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, 220Sstevel@tonic-gate 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, 230Sstevel@tonic-gate 32, 33, 34, 35, 36, 37, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, 240Sstevel@tonic-gate 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, 250Sstevel@tonic-gate 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, 260Sstevel@tonic-gate 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, 270Sstevel@tonic-gate 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, 280Sstevel@tonic-gate 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, 290Sstevel@tonic-gate 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, 300Sstevel@tonic-gate 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223 310Sstevel@tonic-gate ); 32667Sps156622@E2A = ( 330Sstevel@tonic-gate 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, 340Sstevel@tonic-gate 16, 17, 18, 19,157, 10, 8,135, 24, 25,146,143, 28, 29, 30, 31, 350Sstevel@tonic-gate 128,129,130,131,132,133, 23, 27,136,137,138,139,140, 5, 6, 7, 360Sstevel@tonic-gate 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, 370Sstevel@tonic-gate 32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124, 380Sstevel@tonic-gate 38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94, 390Sstevel@tonic-gate 45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63, 400Sstevel@tonic-gate 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34, 410Sstevel@tonic-gate 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177, 420Sstevel@tonic-gate 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164, 430Sstevel@tonic-gate 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174, 440Sstevel@tonic-gate 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215, 450Sstevel@tonic-gate 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245, 460Sstevel@tonic-gate 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255, 470Sstevel@tonic-gate 92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213, 480Sstevel@tonic-gate 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159 490Sstevel@tonic-gate ); 50667Sps156622 51667Sps156622if ($EBCDIC && ord('^') == 106) { # as in the BS2000 posix-bc coded character set 520Sstevel@tonic-gate $A2E[91] = 187; $A2E[92] = 188; $A2E[94] = 106; $A2E[96] = 74; 530Sstevel@tonic-gate $A2E[123] = 251; $A2E[125] = 253; $A2E[126] = 255; $A2E[159] = 95; 540Sstevel@tonic-gate $A2E[162] = 176; $A2E[166] = 208; $A2E[168] = 121; $A2E[172] = 186; 550Sstevel@tonic-gate $A2E[175] = 161; $A2E[217] = 224; $A2E[219] = 221; $A2E[221] = 173; 560Sstevel@tonic-gate $A2E[249] = 192; 57667Sps156622 580Sstevel@tonic-gate $E2A[74] = 96; $E2A[95] = 159; $E2A[106] = 94; $E2A[121] = 168; 590Sstevel@tonic-gate $E2A[161] = 175; $E2A[173] = 221; $E2A[176] = 162; $E2A[186] = 172; 600Sstevel@tonic-gate $E2A[187] = 91; $E2A[188] = 92; $E2A[192] = 249; $E2A[208] = 166; 610Sstevel@tonic-gate $E2A[221] = 219; $E2A[224] = 217; $E2A[251] = 123; $E2A[253] = 125; 620Sstevel@tonic-gate $E2A[255] = 126; 630Sstevel@tonic-gate } 64667Sps156622elsif ($EBCDIC && ord('^') == 176) { # as in codepage 037 on os400 65667Sps156622 $A2E[10] = 37; $A2E[91] = 186; $A2E[93] = 187; $A2E[94] = 176; 66667Sps156622 $A2E[133] = 21; $A2E[168] = 189; $A2E[172] = 95; $A2E[221] = 173; 67667Sps156622 68667Sps156622 $E2A[21] = 133; $E2A[37] = 10; $E2A[95] = 172; $E2A[173] = 221; 69667Sps156622 $E2A[176] = 94; $E2A[186] = 91; $E2A[187] = 93; $E2A[189] = 168; 700Sstevel@tonic-gate} 710Sstevel@tonic-gate 720Sstevel@tonic-gate# Smart rearrangement of parameters to allow named parameter 730Sstevel@tonic-gate# calling. We do the rearangement if: 740Sstevel@tonic-gate# the first parameter begins with a - 750Sstevel@tonic-gatesub rearrange { 760Sstevel@tonic-gate my($order,@param) = @_; 770Sstevel@tonic-gate return () unless @param; 780Sstevel@tonic-gate 790Sstevel@tonic-gate if (ref($param[0]) eq 'HASH') { 800Sstevel@tonic-gate @param = %{$param[0]}; 810Sstevel@tonic-gate } else { 820Sstevel@tonic-gate return @param 830Sstevel@tonic-gate unless (defined($param[0]) && substr($param[0],0,1) eq '-'); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate # map parameters into positional indices 870Sstevel@tonic-gate my ($i,%pos); 880Sstevel@tonic-gate $i = 0; 890Sstevel@tonic-gate foreach (@$order) { 900Sstevel@tonic-gate foreach (ref($_) eq 'ARRAY' ? @$_ : $_) { $pos{lc($_)} = $i; } 910Sstevel@tonic-gate $i++; 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate my (@result,%leftover); 950Sstevel@tonic-gate $#result = $#$order; # preextend 960Sstevel@tonic-gate while (@param) { 970Sstevel@tonic-gate my $key = lc(shift(@param)); 980Sstevel@tonic-gate $key =~ s/^\-//; 990Sstevel@tonic-gate if (exists $pos{$key}) { 1000Sstevel@tonic-gate $result[$pos{$key}] = shift(@param); 1010Sstevel@tonic-gate } else { 1020Sstevel@tonic-gate $leftover{$key} = shift(@param); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 106667Sps156622 push (@result,make_attributes(\%leftover,defined $CGI::Q ? $CGI::Q->{escape} : 1)) if %leftover; 1070Sstevel@tonic-gate @result; 1080Sstevel@tonic-gate} 1090Sstevel@tonic-gate 1100Sstevel@tonic-gatesub make_attributes { 1110Sstevel@tonic-gate my $attr = shift; 1120Sstevel@tonic-gate return () unless $attr && ref($attr) && ref($attr) eq 'HASH'; 113667Sps156622 my $escape = shift || 0; 1140Sstevel@tonic-gate my(@att); 1150Sstevel@tonic-gate foreach (keys %{$attr}) { 1160Sstevel@tonic-gate my($key) = $_; 1170Sstevel@tonic-gate $key=~s/^\-//; # get rid of initial - if present 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate # old way: breaks EBCDIC! 1200Sstevel@tonic-gate # $key=~tr/A-Z_/a-z-/; # parameters are lower case, use dashes 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate ($key="\L$key") =~ tr/_/-/; # parameters are lower case, use dashes 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate my $value = $escape ? simple_escape($attr->{$_}) : $attr->{$_}; 1250Sstevel@tonic-gate push(@att,defined($attr->{$_}) ? qq/$key="$value"/ : qq/$key/); 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate return @att; 1280Sstevel@tonic-gate} 1290Sstevel@tonic-gate 1300Sstevel@tonic-gatesub simple_escape { 1310Sstevel@tonic-gate return unless defined(my $toencode = shift); 1320Sstevel@tonic-gate $toencode =~ s{&}{&}gso; 1330Sstevel@tonic-gate $toencode =~ s{<}{<}gso; 1340Sstevel@tonic-gate $toencode =~ s{>}{>}gso; 1350Sstevel@tonic-gate $toencode =~ s{\"}{"}gso; 1360Sstevel@tonic-gate# Doesn't work. Can't work. forget it. 1370Sstevel@tonic-gate# $toencode =~ s{\x8b}{‹}gso; 1380Sstevel@tonic-gate# $toencode =~ s{\x9b}{›}gso; 1390Sstevel@tonic-gate $toencode; 1400Sstevel@tonic-gate} 1410Sstevel@tonic-gate 142667Sps156622sub utf8_chr { 1430Sstevel@tonic-gate my $c = shift(@_); 144667Sps156622 return chr($c) if $] >= 5.006; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if ($c < 0x80) { 1470Sstevel@tonic-gate return sprintf("%c", $c); 1480Sstevel@tonic-gate } elsif ($c < 0x800) { 1490Sstevel@tonic-gate return sprintf("%c%c", 0xc0 | ($c >> 6), 0x80 | ($c & 0x3f)); 1500Sstevel@tonic-gate } elsif ($c < 0x10000) { 1510Sstevel@tonic-gate return sprintf("%c%c%c", 1520Sstevel@tonic-gate 0xe0 | ($c >> 12), 1530Sstevel@tonic-gate 0x80 | (($c >> 6) & 0x3f), 1540Sstevel@tonic-gate 0x80 | ( $c & 0x3f)); 1550Sstevel@tonic-gate } elsif ($c < 0x200000) { 1560Sstevel@tonic-gate return sprintf("%c%c%c%c", 1570Sstevel@tonic-gate 0xf0 | ($c >> 18), 1580Sstevel@tonic-gate 0x80 | (($c >> 12) & 0x3f), 1590Sstevel@tonic-gate 0x80 | (($c >> 6) & 0x3f), 1600Sstevel@tonic-gate 0x80 | ( $c & 0x3f)); 1610Sstevel@tonic-gate } elsif ($c < 0x4000000) { 1620Sstevel@tonic-gate return sprintf("%c%c%c%c%c", 1630Sstevel@tonic-gate 0xf8 | ($c >> 24), 1640Sstevel@tonic-gate 0x80 | (($c >> 18) & 0x3f), 1650Sstevel@tonic-gate 0x80 | (($c >> 12) & 0x3f), 1660Sstevel@tonic-gate 0x80 | (($c >> 6) & 0x3f), 1670Sstevel@tonic-gate 0x80 | ( $c & 0x3f)); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate } elsif ($c < 0x80000000) { 1700Sstevel@tonic-gate return sprintf("%c%c%c%c%c%c", 1710Sstevel@tonic-gate 0xfc | ($c >> 30), 1720Sstevel@tonic-gate 0x80 | (($c >> 24) & 0x3f), 1730Sstevel@tonic-gate 0x80 | (($c >> 18) & 0x3f), 1740Sstevel@tonic-gate 0x80 | (($c >> 12) & 0x3f), 1750Sstevel@tonic-gate 0x80 | (($c >> 6) & 0x3f), 1760Sstevel@tonic-gate 0x80 | ( $c & 0x3f)); 1770Sstevel@tonic-gate } else { 178667Sps156622 return utf8_chr(0xfffd); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate} 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate# unescape URL-encoded data 1830Sstevel@tonic-gatesub unescape { 184667Sps156622 shift() if @_ > 0 and (ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass)); 1850Sstevel@tonic-gate my $todecode = shift; 1860Sstevel@tonic-gate return undef unless defined($todecode); 1870Sstevel@tonic-gate $todecode =~ tr/+/ /; # pluses become spaces 1880Sstevel@tonic-gate $EBCDIC = "\t" ne "\011"; 1890Sstevel@tonic-gate if ($EBCDIC) { 1900Sstevel@tonic-gate $todecode =~ s/%([0-9a-fA-F]{2})/chr $A2E[hex($1)]/ge; 1910Sstevel@tonic-gate } else { 1920Sstevel@tonic-gate $todecode =~ s/%(?:([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ 1930Sstevel@tonic-gate defined($1)? chr hex($1) : utf8_chr(hex($2))/ge; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate return $todecode; 1960Sstevel@tonic-gate} 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate# URL-encode data 1990Sstevel@tonic-gatesub escape { 2000Sstevel@tonic-gate shift() if @_ > 1 and ( ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass)); 2010Sstevel@tonic-gate my $toencode = shift; 2020Sstevel@tonic-gate return undef unless defined($toencode); 2030Sstevel@tonic-gate # force bytes while preserving backward compatibility -- dankogai 204*6287Sps156622# $toencode = eval { pack("C*", unpack("U0C*", $toencode))} || pack("C*", unpack("C*", $toencode)); 205*6287Sps156622 $toencode = eval { pack("U*", unpack("U0C*", $toencode))} || pack("C*", unpack("C*", $toencode)); 2060Sstevel@tonic-gate if ($EBCDIC) { 207*6287Sps156622 $toencode=~s/([^a-zA-Z0-9_.~-])/uc sprintf("%%%02x",$E2A[ord($1)])/eg; 2080Sstevel@tonic-gate } else { 209*6287Sps156622 $toencode=~s/([^a-zA-Z0-9_.~-])/uc sprintf("%%%02x",ord($1))/eg; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate return $toencode; 2120Sstevel@tonic-gate} 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate# This internal routine creates date strings suitable for use in 2150Sstevel@tonic-gate# cookies and HTTP headers. (They differ, unfortunately.) 2160Sstevel@tonic-gate# Thanks to Mark Fisher for this. 2170Sstevel@tonic-gatesub expires { 2180Sstevel@tonic-gate my($time,$format) = @_; 2190Sstevel@tonic-gate $format ||= 'http'; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate my(@MON)=qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/; 2220Sstevel@tonic-gate my(@WDAY) = qw/Sun Mon Tue Wed Thu Fri Sat/; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate # pass through preformatted dates for the sake of expire_calc() 2250Sstevel@tonic-gate $time = expire_calc($time); 2260Sstevel@tonic-gate return $time unless $time =~ /^\d+$/; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate # make HTTP/cookie date string from GMT'ed time 2290Sstevel@tonic-gate # (cookies use '-' as date separator, HTTP uses ' ') 2300Sstevel@tonic-gate my($sc) = ' '; 2310Sstevel@tonic-gate $sc = '-' if $format eq "cookie"; 2320Sstevel@tonic-gate my($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime($time); 2330Sstevel@tonic-gate $year += 1900; 2340Sstevel@tonic-gate return sprintf("%s, %02d$sc%s$sc%04d %02d:%02d:%02d GMT", 2350Sstevel@tonic-gate $WDAY[$wday],$mday,$MON[$mon],$year,$hour,$min,$sec); 2360Sstevel@tonic-gate} 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate# This internal routine creates an expires time exactly some number of 2390Sstevel@tonic-gate# hours from the current time. It incorporates modifications from 2400Sstevel@tonic-gate# Mark Fisher. 2410Sstevel@tonic-gatesub expire_calc { 2420Sstevel@tonic-gate my($time) = @_; 2430Sstevel@tonic-gate my(%mult) = ('s'=>1, 2440Sstevel@tonic-gate 'm'=>60, 2450Sstevel@tonic-gate 'h'=>60*60, 2460Sstevel@tonic-gate 'd'=>60*60*24, 2470Sstevel@tonic-gate 'M'=>60*60*24*30, 2480Sstevel@tonic-gate 'y'=>60*60*24*365); 2490Sstevel@tonic-gate # format for time can be in any of the forms... 2500Sstevel@tonic-gate # "now" -- expire immediately 2510Sstevel@tonic-gate # "+180s" -- in 180 seconds 2520Sstevel@tonic-gate # "+2m" -- in 2 minutes 2530Sstevel@tonic-gate # "+12h" -- in 12 hours 2540Sstevel@tonic-gate # "+1d" -- in 1 day 2550Sstevel@tonic-gate # "+3M" -- in 3 months 2560Sstevel@tonic-gate # "+2y" -- in 2 years 2570Sstevel@tonic-gate # "-3m" -- 3 minutes ago(!) 2580Sstevel@tonic-gate # If you don't supply one of these forms, we assume you are 2590Sstevel@tonic-gate # specifying the date yourself 2600Sstevel@tonic-gate my($offset); 2610Sstevel@tonic-gate if (!$time || (lc($time) eq 'now')) { 262*6287Sps156622 $offset = 0; 2630Sstevel@tonic-gate } elsif ($time=~/^\d+/) { 264*6287Sps156622 return $time; 265*6287Sps156622 } elsif ($time=~/^([+-]?(?:\d+|\d*\.\d*))([smhdMy])/) { 266*6287Sps156622 $offset = ($mult{$2} || 1)*$1; 2670Sstevel@tonic-gate } else { 268*6287Sps156622 return $time; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate return (time+$offset); 2710Sstevel@tonic-gate} 2720Sstevel@tonic-gate 2730Sstevel@tonic-gatesub ebcdic2ascii { 2740Sstevel@tonic-gate my $data = shift; 2750Sstevel@tonic-gate $data =~ s/(.)/chr $E2A[ord($1)]/ge; 2760Sstevel@tonic-gate $data; 2770Sstevel@tonic-gate} 2780Sstevel@tonic-gate 2790Sstevel@tonic-gatesub ascii2ebcdic { 2800Sstevel@tonic-gate my $data = shift; 2810Sstevel@tonic-gate $data =~ s/(.)/chr $A2E[ord($1)]/ge; 2820Sstevel@tonic-gate $data; 2830Sstevel@tonic-gate} 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate1; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate__END__ 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate=head1 NAME 2900Sstevel@tonic-gate 2910Sstevel@tonic-gateCGI::Util - Internal utilities used by CGI module 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate=head1 SYNOPSIS 2940Sstevel@tonic-gate 2950Sstevel@tonic-gatenone 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate=head1 DESCRIPTION 2980Sstevel@tonic-gate 2990Sstevel@tonic-gateno public subroutines 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate=head1 AUTHOR INFORMATION 3020Sstevel@tonic-gate 3030Sstevel@tonic-gateCopyright 1995-1998, Lincoln D. Stein. All rights reserved. 3040Sstevel@tonic-gate 3050Sstevel@tonic-gateThis library is free software; you can redistribute it and/or modify 3060Sstevel@tonic-gateit under the same terms as Perl itself. 3070Sstevel@tonic-gate 3080Sstevel@tonic-gateAddress bug reports and comments to: lstein@cshl.org. When sending 3090Sstevel@tonic-gatebug reports, please provide the version of CGI.pm, the version of 3100Sstevel@tonic-gatePerl, the name and version of your Web server, and the name and 3110Sstevel@tonic-gateversion of the operating system you are using. If the problem is even 3120Sstevel@tonic-gateremotely browser dependent, please provide information about the 3130Sstevel@tonic-gateaffected browers as well. 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate=head1 SEE ALSO 3160Sstevel@tonic-gate 3170Sstevel@tonic-gateL<CGI> 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate=cut 320