Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Alternatives to PerlTransHandler?

by SamQi (Beadle)
on Nov 01, 2001 at 08:02 UTC ( [id://122493]=perlquestion: print w/replies, xml ) Need Help??

SamQi has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to implement a system for skinnable websites. I currently have one set up where all of the content pages are CGI scripts and they use HTML::Template to apply the skins. However, an URL will always point to a .cgi file. For example: http://foo.bar.bah/~stesla/skinned.cgi

What I want to do is make it so that, rather than having a CGI for each individual page, I want to be able to just have a template of some variety (I haven't fully designed it since I know this technical issue is still in my way). So that I can have the URL be: http://foo.bar.bah/~stesla/skinned.html but still have it run through the Perl that does the templating.

Clearly this is a job for mod_perl, however, it seems that what I want is a PerlTransHandler, and the documentation tells me that I cannot put a PerlTransHandler into a .htaccess file. Since I don't have access to the server-wide Apache configuration, I have to do any configuring in an .htaccess file.

Any suggestions?

Replies are listed 'Best First'.
Re (tilly) 1: Alternatives to PerlTransHandler?
by tilly (Archbishop) on Nov 01, 2001 at 08:34 UTC
    A simple solution is to write your URLs as:
    http://foo.bar.bah/~stelsa/skinned.cgi/file.html
    and have your CGI file look at $ENV{PATH_INFO} to figure out what file it is now.
      tilly has a good suggestion there. Should be pretty easy to do it that way.

      'Path info' works like this: [After translation]...Apache attempts to divide the file path into two parts, a "filename" part which usually (but not always) corresponds to a physical file on the host's filesystem, and an "additional path information" part corresponding to additional stuff that follows the filename. Apache divides the path using a very simple-minded algorithm. It steps through the path components from left to right until it finds something that doesn't correspond to a directory on the host machine. The part of the path up to and including this component becomes the filename, and everything that's left over becomes the additional path information.

      - from Writing Apache Modules in Perl and C, p.86, an excellent book which I would thoroughly recommend to anyone using Perl with Apache.

      Another option might be to write a perl content handler. You can (I think) set this up in an .htaccess file if the permissions in Apache's main config files allow it. It's far easier than you would think - the Fierce Eagle Book goes into detail.

      andy.

      Update: ajt has set up Perl handlers in .htaccess files, so it is definitely possible.

        It may be simple, but you need to be very, very, careful to not be fooled by file names which look like %7C%20/path/to/evil/cmd. Caveat programmer...
Re: Alternatives to PerlTransHandler?
by kwoff (Friar) on Nov 01, 2001 at 08:19 UTC
    I'm not clear on the definition of "skinnable website". To me, skinnable implies that the look (template) can be changed on a per-user basis. By skinnable, do you just mean to be able to change the look, say if the HTML developers want to change the look of the site as a whole? If the latter, and you can't use some system like mod_perl, HTML::Mason, or Java Beans, then you might just want to use server-side includes, like
    <--#include virtual="/section/header.html"--> content here <--#include virtual="/section/footer.html"-->

      To get a feel for what I'm talking about, go check out what I've already hacked out for my wife Erica. Basically, the CGI sets a cookie with a skinID, and then it changes the look (yes just like you thought) based on what the value of that cookie is. Erica is fairly content with the system I've already created for her (although I need to go add some more robust errorhandling...it was 5AM and I was tired), I'm interested in going further with it.

      Namely I want to do some cool things with frames. But I just don't know if I can do it without access to the server-wide httpd.conf.

      Another good example of website skinning is domesticat.net. However, she uses PHP to do her skinning, and can't handle the URI mangling that I want to do.

        I see, so it is per-user skinnable. Those links you gave use cookies. If that's acceptable, then I offer the following solution (only tried on Mozilla). It sets a cookie, then uses a Server-side includes to choose which skin to display. The sample CGI script uses CGI.pm. It's not the best solution I guess, but it's somewhat amusing at least. :)

        ssi-cookie.html

        <HTML> <BODY> <A HREF="/cgi-bin/skin-cookie.pl">Skin this</A><BR> <!--#if expr="${HTTP_COOKIE} = /skin\=wacky/"--> wacky <!--#elif expr="${HTTP_COOKIE} = /skin\=goth/"--> goth <!--#else --> minimal <!--#endif --> </BODY> </HTML>

        /cgi-bin/skin-cookie.pl

        #!/usr/local/bin/perl -Tw # set 'skin' cookie then redirect where we came from use strict; use CGI; use vars qw($q $cookie $location $status @skin_names); $q = new CGI; @skin_names = qw(minimal wacky goth); main(); sub main { if (defined $q->param('skin')) { # user selected a skin my $skin_param = $q->param('skin'); for my $valid_skin (@skin_names) { if ($skin_param eq $valid_skin) { skin_cookie_page($skin_param); } } # fall through if invalid } pick_skin_page(); } sub get_old_url { return $q->param('old_url') || $q->referer() || 'http://perlmonks.org/'; } sub skin_cookie_page { my $skin_param = shift; my $cookie = $q->cookie( -name => 'skin', -value => $skin_param, -expires => '+30d', ); print $q->header(-cookie => $cookie, -status => '302 Moved', -location => get_old_url()); exit; } sub pick_skin_page { print $q->header(), $q->start_html(), # you'll want to skin this too, natural +ly :) $q->start_form(), 'Choose your skin: ', $q->popup_menu(-name => 'skin', '-values' => \@skin_names) +, $q->submit('skin'), $q->hidden('old_url' => get_old_url()), $q->end_form(), $q->end_html(); exit; }

Re: Alternatives to PerlTransHandler?
by perrin (Chancellor) on Nov 01, 2001 at 08:50 UTC
    You don't need mod_perl for that (and if you had it, I wouldn't use a PerlTransHandler for this). Just check out the Apache CGI configuration options. You can make ANYTHING a CGI script, even if it's named foo.html. If you don't like making lots of separate scripts, you could do some magic with mod_rewrite to have them all go tone script.
      I think that this site (WSMCafe) is a lively example of what SamQi is trying to do. It's all CGI, no mod_perl that I can see.

      perrin, I'm not sure if I agree with you. Could you please elaborate as to why PerlTransHandler isn't good for something like this. Here's a small example of what I'm working on and I'll soon have a working example to show for it. It seems to do its job pretty well, although I'm pretty sure there are some things that need to be improved. I do agree with you on how it really doesn't need mod_perl to be. But I figure if I have it, I use it. It goes on the theory, why keep on querying the database to make the pages when they can be generated as static pages.
      package util::TransHandler; use strict; use Apache::Constants qw(:common); sub handler { my $r = shift; my $uri = $r->uri; my ($host,$port) = split(/:/, $r->headers_in->{'Host'}); lc($host); print STDERR $host,"\n"; # if the hostname has more than one subdomain from the one specifi +ed below, reject it. # bar.slinger.foo.com = OK # bar.baz.slinger.foo.com = NOT OK if ($host =~ m/^([a-z0-9]+\.){2,}\.?slinger\.foo\.com$/) { $r->pnotes('BadHost' => ['1']); return DECLINED; # if its not from the base domain. Process it. Find the files and +return the correct path. } elsif ($host !~ m/^(slinger)?\.?foo.com$/) { $host =~ m/^([a-z0-9]+)\.slinger\.foo.com$/; my $members = MEMBERS->select( { SUBDOMAIN => $1 } ); my $session = SESSIONS->select( { SUBDOMAIN => $1 } ); # if the subdomain exists in the database, process it. # Otherwise let the user know its available to use. if ($members != 0 || $session != 0) { my $thedir = $r->server_root_relative($r->dir_config('User +Dir')); my $result; if (ref($members) eq 'ARRAY') { $result = $members->[0]{DI +RECTORY}; } if (ref($session) eq 'ARRAY') { $result = $session->[0]{DI +RECTORY}; } return DECLINED unless $uri =~ s!^/(.*)$!$thedir/$result/$ +1!; $r->pnotes('DontDo' => ['1']); $r->filename($uri); return OK; } else { # Switch that says the subdomain is available. $r->pnotes('SubDomain' => [$1]); return OK; } } else { return DECLINED; } }

      Any improvements to it would be gladly accepted. This probably looks sloppy to most.

      BMaximus
        If the goal for him was just to have one program handle all of these .html URLs, it's easy to do that with a simple httpd.conf thing like this:
        <Files *.html> # or whatever SetHandler perl-script PerlHandler My::Secret::Handler </Files>
        What you are doing is considerably more complex, and makes sense to do in a TransHandler.
Re: Alternatives to PerlTransHandler?
by ajt (Prior) on Nov 01, 2001 at 14:38 UTC
    Skinning HTML sounds more like a job for XSLT than Perl per se. Given a structural XML document what you want to be able to do is transform it in a per user manner via one of a selection of templates into user xHTML.

    The XSLT process will allow you to move content chunks around the page easily, and choose different CSS style sheets and so on.

    AxKit or AxKit is probably the Perl solution for this, but may not be a solution for you given your server restrictions.

    I must confess that I built my own templating solution that does almost what you want, and it works via the .htaccess file, but I plan to migrate to AxKit with time, as it's a more sopisticated solution.

Re: Alternatives to PerlTransHandler?
by Fastolfe (Vicar) on Nov 02, 2001 at 05:52 UTC
    Why have an extension at all? Extensions in URL's are a holdover from our filesystem-based web concepts.. There's no technical requirement that they be there.

    By enabling content negotiation (MultiViews via mod_negotiation) in Apache, you could reference skinned.cgi like this:

    http://foo.bar.bah/~stesla/skinned

    This would automatically select .html, .cgi, or whatever "best" extension can handle this URI. In most cases there'll only be one, but it also allows you to go multi-language or multi-content-type if you wanted to.

    Plus, if you change technologies at a later date and instead to go with, say, .shtml instead of .cgi, or back your content with XML, you don't have to go through and change all of your URL's.

    Lastly, even if you don't go with a trick like this, mod_rewrite can be used to re-write your "pretty" URI's with less-pretty ones that are more reflective of the true name of the resource.

Re: Alternatives to PerlTransHandler?
by rfb (Sexton) on Nov 02, 2001 at 02:39 UTC
    Ridding yourself of that pesky .cgi suffex, one way that works for me naming the cgi index.cgi, so your args are passed after the path name.
    ie:
    http://foo.bar.bah/~stesla/?skin_one
    http://foo.bar.bah/~stesla/?skin_two

    -rfb

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://122493]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-04-19 02:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found