############################################################################## # HTTP Cookie Library Version 2.1 # # Copyright 1996 Matt Wright mattw@worldwidemart.com # # Created 07/14/96 Last Modified 12/23/96 # # Script Archive at: http://www.worldwidemart.com/scripts/ # # Extensive Documentation found in README file.# ############################################################################## # COPYRIGHT NOTICE # # Copyright 1996 Matthew M. Wright. All Rights Reserved. # # # # HTTP Cookie Library may be used and modified free of charge by anyone so # # long as this copyright notice and the comments above remain intact. By # # using this code you agree to indemnify Matthew M. Wright from any # # liability that might arise from it's use. # # # # Selling the code for this program without prior written consent is # # expressly forbidden. In other words, please ask first before you try and # # make money off of my program. # # # # Obtain permission before redistributing this software over the Internet or # # in any other medium. In all cases copyright and header must remain intact.# ############################################################################## # Define variables for this library. # # This is an optional variable. If not defined, the cookie will expire # # when a user's session ends. # # Should be defined as: Wdy, DD-Mon-YYYY HH:MM:SS GMT # $Cookie_Exp_Date = ''; # By default this will be set to the same path as the document being # # described by the header which contains the cookie. # $Cookie_Path = ''; # By default this will be set to the domain host name of the server # # which generated the cookie response. # $Cookie_Domain = ''; # This should be set to 0 if the cookie is safe to send across over # # unsecured channels. If set to 1 the cookie will only be transferred # # if the communications channel with the host is a secure one. Currently # # this means that secure cookies will only be sent to HTTPS (HTTP over # # SSL) servers. According to Netscape docs at least. # $Secure_Cookie = '0'; # These are the characters which the HTTP Cookie Library will translate # # to url encoded (hex characters) when it sets individual or compressed # # cookies. The array holds the order in which these should be # # translated (as we wouldn't want to translate spaces into pluses and # # then pluses into the URL encoded form, but rather the other way # # around) and the associative array holds the values to translate # # characters into. The decoded set will reverse the process. Feel free # # to add any other characters here, but it shouldn't be necessary. # # This is a correction in version 2.1 which makes this library adhere # # more to the Netscape specifications. # @Cookie_Encode_Chars = ('\%', '\+', '\;', '\,', '\=', '\&', '\:\:', '\s'); %Cookie_Encode_Chars = ('\%', '%25', '\+', '%2B', '\;', '%3B', '\,', '%2C', '\=', '%3D', '\&', '%26', '\:\:', '%3A%3A', '\s', '+'); @Cookie_Decode_Chars = ('\+', '\%3A\%3A', '\%26', '\%3D', '\%2C', '\%3B', '\%2B', '\%25'); %Cookie_Decode_Chars = ('\+', ' ', '\%3A\%3A', '::', '\%26', '&', '\%3D', '=', '\%2C', ',', '\%3B', ';', '\%2B', '+', '\%25', '%'); # Done # ############################################################################## ############################################################################## # Subroutine: &GetCookies() # # Description: This subroutine can be called with or without arguments. If # # arguments are specified, only cookies with names matching # # those specified will be set in %Cookies. Otherwise, all # # cookies sent to this script will be set in %Cookies. # # Usage: &GetCookies([cookie_names]) # # Variables: cookie_names - These are optional (depicted with []) and # # specify the names of cookies you wish to set.# # Can also be called with an array of names. # # Ex. 'name1','name2' # # Returns: 1 - If successful and at least one cookie is retrieved. # # 0 - If no cookies are retrieved. # ############################################################################## sub GetCookies { # Localize the variables and read in the cookies they wish to have # # returned. # local(@ReturnCookies) = @_; local($cookie_flag) = 0; local($cookie,$value); # If the HTTP_COOKIE environment variable has been set by the call to # # this script, meaning the browser sent some cookies to us, continue. # if ($ENV{'HTTP_COOKIE'}) { # If specific cookies have have been requested, meaning the # # @ReturnCookies array is not empty, proceed. # if ($ReturnCookies[0] ne '') { # For each cookie sent to us: # foreach (split(/; /,$ENV{'HTTP_COOKIE'})) { # Split the cookie name and value pairs, separated by '='. # ($cookie,$value) = split(/=/); # Decode any URL encoding which was done when the compressed # # cookie was set. # foreach $char (@Cookie_Decode_Chars) { $cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g; $value =~ s/$char/$Cookie_Decode_Chars{$char}/g; } # For each cookie to be returned in the @ReturnCookies array:# foreach $ReturnCookie (@ReturnCookies) { # If the $ReturnCookie is equal to the current cookie we # # are analyzing, set the cookie name in the %Cookies # # associative array equal to the cookie value and set # # the cookie flag to a true value. # if ($ReturnCookie eq $cookie) { $Cookies{$cookie} = $value; $cookie_flag = "1"; } } } } # Otherwise, if no specific cookies have been requested, obtain all # # cookied and place them in the %Cookies associative array. # else { # For each cookie that was sent to us by the browser, split the # # cookie name and value pairs and set the cookie name key in the # # associative array %Cookies equal to the value of that cookie. # # Also set the coxokie flag to 1, since we set some cookies. # foreach (split(/; /,$ENV{'HTTP_COOKIE'})) { ($cookie,$value) = split(/=/); # Decode any URL encoding which was done when the compressed # # cookie was set. # foreach $char (@Cookie_Decode_Chars) { $cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g; $value =~ s/$char/$Cookie_Decode_Chars{$char}/g; } $Cookies{$cookie} = $value; } $cookie_flag = 1; } } # Return the value of the $cookie_flag, true or false, to indicate # # whether we succeded in reading in a cookie value or not. # return $cookie_flag; } ############################################################################## # Subroutine: &SetCookieExpDate() # # Description: Sets the expiration date for the cookie. # # Usage: &SetCookieExpDate('date') # # Variables: date - The date you wish for the cookie to expire, in the # # format: Wdy, DD-Mon-YYYY HH:MM:SS GMT # # Ex. 'Wed, 09-Nov-1999 00:00:00 GMT' # # Returns: 1 - If successful and date passes regular expression check # # for format errors and the new ExpDate is set. # # 0 - If new ExpDate was not set. Check format of date. # ############################################################################## sub SetCookieExpDate { # If the date string is formatted as: Wdy, DD-Mon-YYYY HH:MM:SS GMT, set # # the $Cookie_Exp_Date to the new value and return 1 to signal success. # # Otherwise, return 0, as the date was not successfully changed. # # The date can also be set null value by calling: SetCookieExpDate(''). # if ($_[0] =~ /^\w{3}\,\s\d{2}\-\w{3}-\d{4}\s\d{2}\:\d{2}\:\d{2}\sGMT$/ || $_[0] eq '') { $Cookie_Exp_Date = $_[0]; return 1; } else { return 0; } } ############################################################################## # Subroutine: &SetCookiePath() # # Description: Sets the path for the cookie to be sent to. # # Usage: &SetCookiePath('path') # # Variables: path - The path to which this cookie should be sent. # # Ex. '/' or '/path/to/file' # # Returns: Nothing. # ############################################################################## sub SetCookiePath { # Set the new Cookie Path, assuming it is correct. No error checking is # # done. # $Cookie_Path = $_[0]; } ############################################################################## # Subroutine: &SetCookieDomain() # # Description: Sets the domain for the cookie to be sent to. You can only # # specify a domain within the current domain. Must have 2 or # # 3 periods, depending on type of domain. e.g., .domain.com # # or .k12.co.us. # # Usage: &SetCookieDomain('domain') # # Variables: domain - The domain to set the cookie for. # # Ex. '.host.com' # # Returns: 1 - If successful and value of $Cookie_Domain was set. # # 0 - If unsuccessful and value was not changed. # ############################################################################## sub SetCookieDomain { # Following Netscape specifications, if the domain specified is one of 7 # # top level domains, only require it to contain two periods, and if it # # is not, require that there be three. If the new domain passes error # # checking, set the new domain and return a true value. Otherwise, # # return 0. Trying to set a domain other than the current one is futile,# # since the browser won't allow it. But if people may be accessing the # # page from www.host.xxx or host.xxx, you may wish to set it to .host.xxx# # so that either host the access will have access to the cookie. # if ($_[0] =~ /(.com|.edu|.net|.org|.gov|.mil|.int)$/i && $_[0] =~ /\..+\.\w{3}$/) { $Cookie_Domain = $_[0]; return 1; } elsif ($_[0] !~ /(.com|.edu|.net|.org|.gov|.mil|.int)$/i && $_[0] =~ /\..+\..+\..+/) { $Cookie_Domain = $_[0]; return 1; } else { return 0; } } ############################################################################## # Subroutine: &SetSecureCookie() # # Description: This subroutine will set the cookie to be either secure, # # meaning the cookie will only be passed over a secure HTTP # # channel, or unsecure, meaning it is safe to pass unsecured. # # Usage: &SetSecureCookie('flag') # # Variables: flag - 0 or 1 depending whether you want it secure or not # # secure. By default, it is set to unsecure, unless # # $Secure_Cookie was changed at the top. # # Ex. 1 # # Returns: 1 - If successful and value of $Secure_Cookie was set. # # 0 - If unsuccessful and value was not changed. # ############################################################################## sub SetSecureCookie { # If the value passed to this script is a 1 or 0, set $Secure_Cookie # # accordingly and return a true value. Otherwise, return a false value. # if ($_[0] =~ /^[01]$/) { $Secure_Cookie = $_[0]; return 1; } else { return 0; } } ############################################################################## # Subroutine: &SetCookies() # # Description: Sets one or more cookies by printing out the Set-Cookie # # HTTP header to the browser, based on cookie information # # passed to subroutine. # # Usage: &SetCookies(name1,value1,...namen,valuen) # # Variables: name - Name of the cookie to be set. # # Ex. 'count' # # value - Value of the cookie to be set. # # Ex. '3' # # n - This is tacked on to the last of the name and value # # pairs in the usage instructions just to show you # # you can have as many name/value pairs as you wish. # # ** You can specify as many name/value pairs as you wish, and # # &SetCookies will set them all. Just string them out, one # # after the other. You must also have already printed out # # the Content-type header, with only one new line following # # it so that the header has not been ended. Then after the # # &SetCookies call, you can print the final new line. # # Returns: Nothing. # ############################################################################## sub SetCookies { # Localize variables and read in cookies to be set. # local(@cookies) = @_; local($cookie,$value,$char); # While there is a cookie and a value to be set in @cookies, that hasn't # # yet been set, proceed with the loop. # while( ($cookie,$value) = @cookies ) { # We must translate characters which are not allowed in cookies. # foreach $char (@Cookie_Encode_Chars) { $cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g; $value =~ s/$char/$Cookie_Encode_Chars{$char}/g; } # Begin the printing of the Set-Cookie header with the cookie name # # and value, followed by semi-colon. # print 'Set-Cookie: ' . $cookie . '=' . $value . ';'; # If there is an Expiration Date set, add it to the header. # if ($Cookie_Exp_Date) { print ' expires=' . $Cookie_Exp_Date . ';'; } # If there is a path set, add it to the header. # if ($Cookie_Path) { print ' path=' . $Cookie_Path . ';'; } # If a domain has been set, add it to the header. # if ($Cookie_Domain) { print ' domain=' . $Cookie_Domain . ';'; } # If this cookie should be sent only over secure channels, add that # # to the header. # if ($Secure_Cookie) { print ' secure'; } # End this line of the header, setting the cookie. # print "\n"; # Remove the first two values of the @cookies array since we just # # used them. # shift(@cookies); shift(@cookies); } } ############################################################################## # Subroutine: &SetCompressedCookies # # Description: This routine does much the same thing that &SetCookies does # # except that it combines multiple cookies into one. # # Usage: &SetCompressedCookies(cname,name1,value1,...,namen,valuen) # # Variables: cname - Name of the compressed cookie to be set. # # Ex. 'CC' # # name - Name of the individual cookie to be set. # # Ex. 'count' # # value - Value of the individual cookie to be set. # # Ex. '3' # # n - This is tacked on to the last of the name and value # # pairs in the usage instructions just to show you # # you can have as many name/value pairs as you wish. # # Returns: Nothing. # ############################################################################## sub SetCompressedCookies { # Localize input into the compressed cookie name and the cookies to be # # set. # local($cookie_name,@cookies) = @_; local($cookie,$value,$cookie_value); # While there is a cookie and a value to be set in @cookies, that hasn't # # yet been set, proceed with the loop. # while ( ($cookie,$value) = @cookies ) { # We must translate characters which are not allowed in cookies, or # # which might interfere with the compression. # foreach $char (@Cookie_Encode_Chars) { $cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g; $value =~ s/$char/$Cookie_Encode_Chars{$char}/g; } # Prepare the cookie value. If a current cookie value exists, use # # an ampersand (&) to separate the cookies and instead of using = to # # separate the name and the value, use double colons (::), so it # # won't confuse the browser. # if ($cookie_value) { $cookie_value .= '&' . $cookie . '::' . $value; } else { $cookie_value = $cookie . '::' . $value; } # Remove the first two values of the @cookies array since we just # # used them. # shift(@cookies); shift(@cookies); } # Use the &SetCookies array to set the compressed cookie and value. # &SetCookies("$cookie_name","$cookie_value"); } ############################################################################## # Subroutine: &GetCompressedCookies() # # Description: This subroutine takes the compressed cookie names, and # # optionally the names of specific cookies you want returned # # and uncompressed them, setting the values into %Cookies. # # Specific names of cookies are optional and if not specified # # all cookies found in the compressed cookie will be set. # # Usage: &GetCompressedCookies(cname,[names]) # # Variables: cname - Name of the compressed cookie to be uncompressed. # # Ex. 'CC' # # names - Optional names of cookies to be returned from the # # compressed cookie if you don't want them all. The # # [] depict a list of optional names, don't use []. # # Ex. 'count' # # Returns: 1 - If successful and at least one cookie is retrieved. # # 0 - If no cookies are retrieved. # ############################################################################## sub GetCompressedCookies { # Localize variables used in this subroutine as well as the compressed # # cookie name and the cookies to retrieve from the compressed cookie. # local($cookie_name,@ReturnCookies) = @_; local($cookie_flag) = 0; local($ReturnCookie,$cookie,$value); # If we can get the compressed cookie, proceed. # if (&GetCookies($cookie_name)) { # If there are specific cookies which we should set, rather than all # # cookies found in the compressed cookie, then only retrieve them. # if ($ReturnCookies[0] ne '') { # For each cookie that was found in the compressed cookie: # foreach (split(/&/,$Cookies{$cookie_name})) { # Split the cookie name and value pair. # ($cookie,$value) = split(/::/); # Decode any URL encoding which was done when the compressed # # cookie was set. # foreach $char (@Cookie_Decode_Chars) { $cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g; $value =~ s/$char/$Cookie_Decode_Chars{$char}/g; } # For each cookie in the specified cookies we should set, # # check to see if it matches the cookie we are looking at # # right now. If so, set that cookie in the %Cookies array # # and set the cookie flag to 1. # foreach $ReturnCookie (@ReturnCookies) { if ($ReturnCookie eq $cookie) { $Cookies{$cookie} = $value; $cookie_flag = 1; } } } } # Otherwise, if there are no specific cookies to set, we will set # # all cookies we find in the compressed cookie. # else { # Split the compressed cookie and split the cookie name/value # # pairs, setting them in %Cookies. Also set cookie flag to 1. # foreach (split(/&/,$Cookies{$cookie_name})) { ($cookie,$value) = split(/::/); # Decode any URL encoding which was done when the compressed # # cookie was set. # foreach $char (@Cookie_Decode_Chars) { $cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g; $value =~ s/$char/$Cookie_Decode_Chars{$char}/g; } $Cookies{$cookie} = $value; } $cookie_flag = 1; } # Delete the compressed cookie from the %Cookies array. # delete($Cookies{$cookie_name}); } # Return the cookie flag, which tells whether any cookies have been set. # return $cookie_flag; } # This statement must be left in so that when perl requires this script as a # # library it will do so without errors. This tells perl it has successfully # # required the library. # 1;