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

I am running a website that serves static HTMLs containing links to some PDF files. I wish to grant conditional access to these PDFs. That is, if a user clicks on a link to PDF, say his userid is looked up in a database and then if it is present, the user is allowed to view the PDF.
Is there anything in CGI-Perl/apache that allows this kind of filtering? I am NOT using mod-perl.
I understand one solution is to do something like
<a href='http://server.com/cgi-bin/check_user.pl?my_file.pdf'>

instead of simple
<a href='http://server.com/htdocs/my_file.pdf'>

The Perl script will check for user and do stuff.
But is there anything configurable in apache itself that would allow my check_user.pl script to run for every PDF file accessed?

Replies are listed 'Best First'.
Re: Filter apache web get request using cgi-perl
by daxim (Curate) on Jun 06, 2012 at 15:41 UTC
Re: Filter apache web get request using cgi-perl
by thomas895 (Deacon) on Jun 06, 2012 at 17:34 UTC

    Technically, this is an Apache question, and not a Perl one. But if you must do it with Perl, here's something to get you started:

    #!/usr/bin/perl -wT use CGI; use File::MimeInfo qw( mimetype ); use CGI::Carp qw( fatalsToBrowser ); #Of course, you'll want a more el +egant method # of error reporting than I use h +ere use constant FILES_DIR => "/path/to/files/"; my $cgi = new CGI; #Get the requested filename my $wanted_file = $cgi->param( "file" ); #my $wanted_file = $cgi->keywords; #Check if data is tainted - VERY IMPORTANT unless( $wanted_file =~ /\w{1}[\w-.]*\@[\w-.]+/ ) { #User tried to pass tainted data, e.g. "/etc/passwd" die( "Nice try, buddy." ); } #Check if that actually exists unless( -f FILES_DIR.$wanted_file" ) { die( "That file cannot be found." ); } #Check if the user is allowed to see that file #NOTE: Using cookies to store user id's is a bad idea. You # should use a session or a token of some sort. my $given_userid = $cgi->cookie( "user_id" ); my @allowed_people = get_an_array_of_allowed_people_from_somewhere(); unless( grep($given_userid, @allowed_userid) ) { die( "You are not allowed to see this file." ); } #Since we got here, we can give the user their file my $content_type = mimetype( FILES_DIR.$wanted_file ); open( FILE, "<", FILES_DIR.$wanted_file ) or die( "Cannot open file: $ +!" ); print $cgi->header( -type => $content_type ); print while <FILE>; close FILE;
    ~Thomas~
    confess( "I offer no guarantees on my code." );
Re: Filter apache web get request using cgi-perl
by scorpio17 (Canon) on Jun 07, 2012 at 13:23 UTC

    You should take a look at the Apache module MOD_REWRITE.

    It will let you map a URL like this:

    http://server.com/pdfs/my_file

    into something like this:

    http://server.com/cgi-bin/check_user.pl?my_file.pdf

    However, it might be a good idea to use some kind of id number, instead of the actual file name, in the URL. Then the script could use that id to do a database lookup, and get the path, filename, etc.

    Using the actual filename may cause problems if it contains spaces, or other non-URI safe characters, for example.

    The PDF files need to be in a directory NOT under the HTML document root (i.e., it needs to be impossible to access them by URL, else your system can be easily bypassed. Your script will need to read the requested PDF and then write it back out. Make sure to set the mime-type correctly in the html header (something like 'application/pdf'). This way if you have an index page listing all your files, when someone clicks on a link, the browser won't load a new page, but the pdf will open up in a new window. Note that the exact behavior may vary depending on which browser is being used, and what plugins have been installed, etc. Some people like for pdfs to open inside the browser, others prefer to launch a pdf reader on the side, while others may prefer to get the "save as" dialog and view it later. The mime type may help give you some control over this.