# Blosxom Plugin: cookies # Author(s): Rael Dornfest # Version: 2003-03-20 ## 3.0_+3i version by Stu MacKenzie ## Version: 2004-06-26 # Documentation: See the bottom of this file or type: perldoc cookies ## NOTE: the syntax to call cookies::add has changed!!! ## Read all the documentation for details and syntax examples ## NOTE: if you haven't guessed it yet, add'l notes from the porter ## are indicated by '##'. package Blosxom::Plugin::cookies; # --- Configurable variables ----- # What domain should I assign to cookies (e.g. .example.com, www.example.com)? # REQUIRED; if you don't fill in a domain, the plug-in won't work properly. $domain = '127.0.0.1'; # What path should I assign to cookies? $path = '/'; # How soon should cookies expire? # (e.g. +1d is 1 day, +3m is 3 months, and +10y is 10 years from now) # Leave this blank and the cookie will expire when the browser is closed $expires = '+1y'; # -------------------------------- use CGI qw/:standard/; %cookies = (); sub start { # In B2, this ran "for free"; in B3 we'll have to call it foreach ( cookie() ) { # CGI gets cookie() from the browser; I'm not sure my %hash = cookie($_); # if there's a better way to call this.... $cookies{$_} = \%hash; # load our %cookies var with refs to CGI's found cookies } 1; # superfulous for 3.0 (so far....) } # O.K. -- here's a big kludge to overcome a hole in B3... # In B2, fairly early on, we set up a hash to hold header information; # the "default" info is content-type. Just before the page is output, B2 # calls CGI::header() to turn this hash into a legit header; all we have # to do in the cookies plugin is add another hash item to include cookies # in the header (see below: sub foot()) # # In B3 +3i, everything changes. We no longer set up a "header hash" -- we just # read in a template and stuff the interpolated result into a scalar. I'm guessing # that when B3 calls CGI::header() to turn that scalar into a legit header, CGI makes # an assumption that the single item we're passing it is content-type. The upshot of this # is that all we've got work with is a scalar...and we seem to need a hash in order to # pass multiple items into CGI::header. # # So, this routine re-casts that "header scalar" ({response}->{content_type}->{rendered}) # as a "header hash" so's that we can add our cookie item(s). # # This routine should be called JUST _BEFORE_ 'Blosxom::output_header' sub add_cookies_to_header { my $self = shift; # right now, {response}->{content_type}->{rendered} is just 'text/html' -- unlike # B2, it's just a scalar; not a hash. We're going to make it a hash here: $self->{response}->{content_type}->{rendered} = {-type=>$self->{response}->{content_type}->{rendered}}; my @cookies = values %cookies; # now we can add a cookie item to the header hash $self->{response}->{content_type}->{rendered}->{'-cookie'} = \@cookies; 1; } sub add { foreach ( @_ ) { my($name) = $_ =~ /^(.+?)=/; $cookies{$name} = $_; } 1; } sub remove { foreach ( @_ ) { delete $cookies{$_}; } 1; } # unable to make this work...even in B2 sub clear { foreach ( @_ ) { $cookies{$_} = ''; } 1; } sub get { my($name) = @_; return $name ? $cookies{$name} : \%cookies; } sub list { return keys %cookies; } 1; __END__ =head1 NAME Blosxom Plug-in: cookies =head1 SYNOPSIS Provides basic cookie functionality for use by any number of Blosxom plug-ins. ## NOTE: There are important notes about changes in this B3-adapted version of cookies; ## read all of this information before using cookies.pm! =head1 INSTALLATION & CONFIGURATION Drop the cookies plug-in into your Blosxom plugins directory. # rename the plugin to 'cookies.pm' (no quotes) Add these lines to your handlers.flow file: * just _before_ Blosxom::find_entries, add this line: Blosxom::Plugin::cookies::start * _immediately after_ Blosxom::render_response, add these two lines: * just _before_ Blosxom::output_header, add this line: Blosxom::Plugin::cookies::add_cookies_to_header Be sure cookies is called last, giving all other plugins a chance to add, remove, and clear cookies before the the cookies plug-in returns the header to the browser. The easiest way to do this is to rename the plug-in 9999cookies or the like, assuring that is sorted last, alphanumerically. ## In B3, this means that you should position the 'start' line (as above) ## _just before_ the 'find_entries' line. Set a $domain for your cookies. I recommend using any host in your domain, e.g. .example.com, instead of just limiting to www, e.g. www.yourdomain. Assign a $path for your cookies. This should be the base path of your weblog. Use / if your weblog lives at the root of your domain (e.g. http://www.example.com/) or /weblog, for example, if it lives at a /weblog subpath (e.g. http://www.example.com/weblog). ## Note that the +3m form seems to set _minutes_, not months Set a time-out period for cookies. While there are various allowed forms for this expires piece (see perldoc CGI.pm), I like using +n(d,m,y) for n days, months, or years from now. For example: +1d is 1 day, +3m is 3 months, and +10y is 10 years from now. The default is 10 years from now. =head1 USAGE As an end-user, once you have the cookies plug-in installed and configured, you're done. =head1 DEVELOPMENT Plug-in developers may use the cookies module as a base for cookie-usage by your own Blosxom plug-in. An example may be found in the writeback plug-in's use of cookies to remember the name and url of a person leaving a comment. ## Eric Davis also uses cookies plugin in the 'css' plugin All cookies are kept on a stack (in a %cookies hash, actually). Incoming cookies sent by the browser are automagically added to the %cookies stack in the start() subroutine. ## NOTE: I had a buncha problems getting this to run under B3+3i; once I got it ## roughly working, I left it alone. No doubt there are plenty of little errors ## to be fixed.... And there may be a BIG error -- throughout my testing and this ## documentation, I did NOT prepend a '&' to calls to cookie.pm (that is, where ## you would expect to see '&Blosxom::Plugin::cookies::sub_name', I just used ## 'Blosxom::Plugin::cookies::sub_name' -- that may account for the extra two ## steps needed to call the add() subroutine from a plugin. I'm not that bright ## with Perl, and I've run out of appetite for cookies ;-) Whatever the "best" ## syntax is, the usage examples provided here work as noted. You have the following methods at your disposal: =item * add($cookie1, $cookie2, ...) adds a cookie to the stack to be sent to the client browser. Cookies should be well-formed; I suggest using the Perl CGI.pm module's cookie() subroutine to create each cookie. So that cookies can all be handled in the same manner by the cookies plug-in, you must use a hash as your cookie value, even if you only have one value to set. usage: &cookies::add( cookie( -name=>'plugin cookie 1' -value=>{ 'some key' => 'some value' } -path=>$cookies::path, -domain=>$cookies::domain ) cookie( -name=>'plugin cookie 2', -value=>{ 'first key' => 'first value', 'second key' => 'second value' } -path=>$cookies::path, -domain=>$cookies::domain ) ); ## NOTE: cookies.pm will not work using the above syntax. ## Here are two ways of calling 'add' that _do_ work: ### Method 1 -- ## - first, construct your cookie hash. ## Here's example syntax: ## my %cookie = (-name=>"$var_or_quotedliteral", -value=>{ 'literal_key' => "$var_or_quotedliteral_value" }, -path=>$Blosxom::Plugin::cookies::path, -domain=>$Blosxom::Plugin::cookies::domain, -expires=>$Blosxom::Plugin::cookies::expires); ## - second, call CGI to produce a cookie object. ## Here's example syntax: ## my $temp = $self->{cgi}->cookie(%cookie); ## - third, call the cookies plugin. ## Here's example syntax: ## Blosxom::Plugin::cookies::add($temp); ### Method 2 -- ### This method "does it all" in one line: Blosxom::Plugin::cookies::add( $self->{cgi}->cookie( -name=>'css', -value=>{ 'css' => "$css_name" }, -path=>$cookies::path, -domain=>$cookies::domain, -expires=>$cookies::expires ) ); =item * remove('cookie name') removes a previously added cookie named 'cookie name' from the stack. Note, this does not unset the cookie in the client browser. usage: &cookies::remove('plugin cookie 1'); ## NOTE: unknown whether this sub works or not; untested. ## Here's example syntax: ## Blosxom::Plugin::cookies::remove($var_or_quotedliteral); =item * clear('cookie name') sets a blank value for the 'cookie name' cookie, thereby clearing it in the client browser. usage: &cookies::clear('plugin cookie 2'); ## NOTE: Never was able to get this to work, even in B2. ## Here's example syntax: ## Blosxom::Plugin::cookies::clear($var_or_quotedliteral); =item * list() lists the names of all cookies on the stack. usage: my @cookie_names = &cookies::list(); =item * get() gets a reference to a hash {cookie name => cookie value} of all cookies on the stack. get('cookie name') gets a hash reference for the 'cookie name' cookie. usage: my $cookies = &cookies::get(); my @cookie_names = keys %$cookies; my $particular_cookie = &cookies::get('cookie name'); my $values = values %$particular_cookie; ## NOTE: Only tested getting a named cookie. ## Here's example syntax: ## my $particular_cookie = Blosxom::Plugin::cookies::get($var_or_quotedliteral); ## my $values = values %$particular_cookie; =head1 VERSION 2003-03-20 ## B3+3i port version 2004-06-26 =head1 AUTHOR Rael Dornfest , http://www.raelity.org/ ## ported by Stu MacKenzie =head1 SEE ALSO Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/ Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml =head1 BUGS Address bug reports and comments to the Blosxom mailing list [http://www.yahoogroups.com/group/blosxom]. =head1 LICENSE Blosxom and this Blosxom Plug-in Copyright 2003, Rael Dornfest Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.