1 package CGI::Simple::Util;
3 use vars qw( $VERSION @EXPORT_OK @ISA $UTIL );
8 rearrange make_attributes expires
9 escapeHTML unescapeHTML escape unescape
13 my ( $order, @params ) = @_;
14 my ( %pos, @result, %leftover );
15 return () unless @params;
16 if ( ref $params[0] eq 'HASH' ) {
17 @params = %{ $params[0] };
20 return @params unless $params[0] =~ m/^-/;
23 # map parameters into positional indices
26 for ( ref( $_ ) eq 'ARRAY' ? @$_ : $_ ) { $pos{ lc( $_ ) } = $i; }
29 $#result = $#$order; # preextend
31 my $key = lc( shift( @params ) );
33 if ( exists $pos{$key} ) {
34 $result[ $pos{$key} ] = shift( @params );
37 $leftover{$key} = shift( @params );
40 push @result, make_attributes( \%leftover, 1 ) if %leftover;
46 my $escape = shift || 0;
47 return () unless $attref && ref $attref eq 'HASH';
49 for my $key ( keys %{$attref} ) {
50 ( my $mod_key = $key ) =~ s/^-//; # get rid of initial - if present
51 $mod_key = lc $mod_key; # parameters are lower case
52 $mod_key =~ tr/_/-/; # use dashes
54 = $escape ? escapeHTML( $attref->{$key} ) : $attref->{$key};
55 push @attrib, defined $value ? qq/$mod_key="$value"/ : $mod_key;
60 # This internal routine creates date strings suitable for use in
61 # cookies and HTTP headers. (They differ, unfortunately.)
62 # Thanks to Mark Fisher for this.
64 my ( $time, $format ) = @_;
66 my @MON = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
67 my @WDAY = qw( Sun Mon Tue Wed Thu Fri Sat );
69 # pass through preformatted dates for the sake of expire_calc()
70 $time = _expire_calc( $time );
71 return $time unless $time =~ /^\d+$/;
73 # make HTTP/cookie date string from GMT'ed time
74 # (cookies use '-' as date separator, HTTP uses ' ')
75 my $sc = $format eq 'cookie' ? '-' : ' ';
76 my ( $sec, $min, $hour, $mday, $mon, $year, $wday ) = gmtime( $time );
78 return sprintf( "%s, %02d$sc%s$sc%04d %02d:%02d:%02d GMT",
79 $WDAY[$wday], $mday, $MON[$mon], $year, $hour, $min, $sec );
82 # This internal routine creates an expires time exactly some number of
83 # hours from the current time. It incorporates modifications from Mark Fisher.
84 # format for time can be in any of the forms...
85 # "now" -- expire immediately
86 # "+180s" -- in 180 seconds
87 # "+2m" -- in 2 minutes
88 # "+12h" -- in 12 hours
90 # "+3M" -- in 3 months
92 # "-3m" -- 3 minutes ago(!)
93 # If you don't supply one of these forms, we assume you are specifying
102 'M' => 60 * 60 * 24 * 30,
103 'y' => 60 * 60 * 24 * 365
106 if ( !$time or lc $time eq 'now' ) {
109 elsif ( $time =~ /^\d+/ ) {
112 elsif ( $time =~ /^([+-]?(?:\d+|\d*\.\d*))([mhdMy]?)/ ) {
113 $offset = ( $mult{$2} || 1 ) * $1;
118 return ( time + $offset );
122 my ( $escape, $text ) = @_;
123 return undef unless defined $escape;
124 $escape =~ s/&/&/g;
125 $escape =~ s/"/"/g;
126 $escape =~ s/</</g;
127 $escape =~ s/>/>/g;
129 # these next optional escapes make text look the same when rendered in HTML
131 $escape =~ s/\t/ /g; # tabs to 4 spaces
132 $escape =~ s/( {2,})/" " x length $1/eg; # whitespace escapes
133 $escape =~ s/\n/<br>\n/g; # newlines to <br>
139 my ( $unescape ) = @_;
140 return undef unless defined( $unescape );
141 my $latin = $UTIL->{'charset'} =~ /^(?:ISO-8859-1|WINDOWS-1252)$/i;
142 my $ebcdic = $UTIL->{'ebcdic'};
144 # credit to Randal Schwartz for original version of this
145 $unescape =~ s[&(.*?);]{
151 /^#(\d+)$/ && $latin ? chr($1) :
152 /^#(\d+)$/ && $ebcdic ? chr($UTIL->{'a2e'}->[$1]) :
153 /^#x([0-9a-f]+)$/i && $latin ? chr(hex($1)) :
154 /^#x([0-9a-f]+)$/i && $ebcdic ? chr($UTIL->{'a2e'}->[hex $1]) :
162 my ( $toencode ) = @_;
163 return undef unless defined $toencode;
164 if ( $UTIL->{'ebcdic'} ) {
166 =~ s/([^a-zA-Z0-9_.-])/uc sprintf "%%%02x", $UTIL->{'e2a'}->[ord $1]/eg;
169 $toencode =~ s/([^a-zA-Z0-9_.-])/uc sprintf "%%%02x", ord $1 /eg;
174 # unescape URL-encoded data
176 my ( $todecode ) = @_;
177 return undef unless defined $todecode;
178 $todecode =~ tr/+/ /;
179 if ( $UTIL->{'ebcdic'} ) {
180 $todecode =~ s/%([0-9a-fA-F]{2})/chr $UTIL->{'a2e'}->[hex $1]/ge;
183 $todecode =~ s/%(?:([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/
184 defined($1)? chr hex($1) : utf8_chr(hex($2))/ge;
192 return sprintf( "%c", $c );
194 elsif ( $c < 0x800 ) {
195 return sprintf( "%c%c", 0xc0 | ( $c >> 6 ), 0x80 | ( $c & 0x3f ) );
197 elsif ( $c < 0x10000 ) {
198 return sprintf( "%c%c%c",
200 0x80 | ( ( $c >> 6 ) & 0x3f ),
201 0x80 | ( $c & 0x3f ) );
203 elsif ( $c < 0x200000 ) {
204 return sprintf( "%c%c%c%c",
206 0x80 | ( ( $c >> 12 ) & 0x3f ),
207 0x80 | ( ( $c >> 6 ) & 0x3f ),
208 0x80 | ( $c & 0x3f ) );
210 elsif ( $c < 0x4000000 ) {
211 return sprintf( "%c%c%c%c%c",
213 0x80 | ( ( $c >> 18 ) & 0x3f ),
214 0x80 | ( ( $c >> 12 ) & 0x3f ),
215 0x80 | ( ( $c >> 6 ) & 0x3f ),
216 0x80 | ( $c & 0x3f ) );
219 elsif ( $c < 0x80000000 ) {
222 0xfc | ( $c >> 30 ), # was 0xfe patch Thomas L. Shinnick
223 0x80 | ( ( $c >> 24 ) & 0x3f ),
224 0x80 | ( ( $c >> 18 ) & 0x3f ),
225 0x80 | ( ( $c >> 12 ) & 0x3f ),
226 0x80 | ( ( $c >> 6 ) & 0x3f ),
231 return utf8( 0xfffd );
235 # We need to define a number of things about the operating environment so
236 # we do this on first initialization and store the results in in an object
239 $UTIL = new CGI::Simple::Util; # initialize our $UTIL object
243 $class = ref( $class ) || $class;
258 my ( $self, $charset ) = @_;
259 $self->{'charset'} = $charset if $charset;
261 ||= 'ISO-8859-1'; # set to the safe ISO-8859-1 if not defined
262 return $self->{'charset'};
266 my ( $self, $OS ) = @_;
267 $self->{'os'} = $OS if $OS; # allow value to be set manually
270 unless ( $OS = $^O ) {
272 $OS = $Config::Config{'osname'};
274 if ( $OS =~ /Win/i ) {
277 elsif ( $OS =~ /vms/i ) {
280 elsif ( $OS =~ /bsdos/i ) {
283 elsif ( $OS =~ /dos/i ) {
286 elsif ( $OS =~ /^MacOS$/i ) {
289 elsif ( $OS =~ /os2/i ) {
296 return $self->{'os'} = $OS;
301 return $self->{'ebcdic'} if exists $self->{'ebcdic'};
302 $self->{'ebcdic'} = "\t" ne "\011" ? 1 : 0;
303 if ( $self->{'ebcdic'} ) {
305 # (ord('^') == 95) for codepage 1047 as on os390, vmesa
307 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 21, 11,
308 12, 13, 14, 15, 16, 17, 18, 19, 60, 61, 50, 38,
309 24, 25, 63, 39, 28, 29, 30, 31, 64, 90, 127, 123,
310 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
311 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94,
312 76, 126, 110, 111, 124, 193, 194, 195, 196, 197, 198, 199,
313 200, 201, 209, 210, 211, 212, 213, 214, 215, 216, 217, 226,
314 227, 228, 229, 230, 231, 232, 233, 173, 224, 189, 95, 109,
315 121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146,
316 147, 148, 149, 150, 151, 152, 153, 162, 163, 164, 165, 166,
317 167, 168, 169, 192, 79, 208, 161, 7, 32, 33, 34, 35,
318 36, 37, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
319 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59,
320 4, 20, 62, 255, 65, 170, 74, 177, 159, 178, 106, 181,
321 187, 180, 154, 138, 176, 202, 175, 188, 144, 143, 234, 250,
322 190, 160, 182, 179, 157, 218, 155, 139, 183, 184, 185, 171,
323 100, 101, 98, 102, 99, 103, 158, 104, 116, 113, 114, 115,
324 120, 117, 118, 119, 172, 105, 237, 238, 235, 239, 236, 191,
325 128, 253, 254, 251, 252, 186, 174, 89, 68, 69, 66, 70,
326 67, 71, 156, 72, 84, 81, 82, 83, 88, 85, 86, 87,
327 140, 73, 205, 206, 203, 207, 204, 225, 112, 221, 222, 219,
331 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11,
332 12, 13, 14, 15, 16, 17, 18, 19, 157, 10, 8, 135,
333 24, 25, 146, 143, 28, 29, 30, 31, 128, 129, 130, 131,
334 132, 133, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
335 144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155,
336 20, 21, 158, 26, 32, 160, 226, 228, 224, 225, 227, 229,
337 231, 241, 162, 46, 60, 40, 43, 124, 38, 233, 234, 235,
338 232, 237, 238, 239, 236, 223, 33, 36, 42, 41, 59, 94,
339 45, 47, 194, 196, 192, 193, 195, 197, 199, 209, 166, 44,
340 37, 95, 62, 63, 248, 201, 202, 203, 200, 205, 206, 207,
341 204, 96, 58, 35, 64, 39, 61, 34, 216, 97, 98, 99,
342 100, 101, 102, 103, 104, 105, 171, 187, 240, 253, 254, 177,
343 176, 106, 107, 108, 109, 110, 111, 112, 113, 114, 170, 186,
344 230, 184, 198, 164, 181, 126, 115, 116, 117, 118, 119, 120,
345 121, 122, 161, 191, 208, 91, 222, 174, 172, 163, 165, 183,
346 169, 167, 182, 188, 189, 190, 221, 168, 175, 93, 180, 215,
347 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 173, 244,
348 246, 242, 243, 245, 125, 74, 75, 76, 77, 78, 79, 80,
349 81, 82, 185, 251, 252, 249, 250, 255, 92, 247, 83, 84,
350 85, 86, 87, 88, 89, 90, 178, 212, 214, 210, 211, 213,
351 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 179, 219,
354 if ( ord( '^' ) == 106 )
355 { # as in the BS2000 posix-bc coded character set
392 elsif ( ord( '^' ) == 176 ) { # as in codepage 037 on os400
411 $self->{'a2e'} = \@A2E;
412 $self->{'e2a'} = \@E2A;
423 CGI::Simple::Util - Internal utilities used by CGI::Simple module
427 $escaped = escapeHTML('In HTML you need to escape < > " and & chars');
428 $unescaped = unescapeHTML('<>"&');
429 $url_encoded = escape($string);
430 $decoded = unescape($url_encoded);
434 CGI::Simple::Util contains essentially non public subroutines used by
435 CGI::Simple. There are HTML and URL escape and unescape routines that may
438 An internal object is used to store a number of system specific details to
439 enable the escape routines to be accurate.
441 =head1 AUTHOR INFORMATION
443 Original version copyright 1995-1998, Lincoln D. Stein. All rights reserved.
444 Originally copyright 2001 Dr James Freeman E<lt>jfreeman@tassie.net.auE<gt>
445 This release by Andy Armstrong <andy@hexten.net>
447 This library is free software; you can redistribute it and/or modify
448 it under the same terms as Perl itself.
450 Address bug reports and comments to: andy@hexten.net