Detect click on HREF link?

Hi Experts,

I'm wanting to detect when a visitor downloads a file on my website, so I can do things like: immediately increment counters, etc.
My HTML might be something like this (but I can change it if required):
  <A HREF="MyFile.txt">MyFile.txt<A>
How can I make it so when a user clicks the link it starts up a Perl script, or whatever?

I know I could look at web stats on the site, but I think they are not updated promptly and I'm wondering if there is a more direct method, without having to monitor logs, etc.

Also, how can I get the IP Address of the person who clicks the link?

Thanks...TRS
LVL 12
tel2Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

yo_s_cantaCommented:
To add on click event use this:
<A onclick="yourfunc()" HREF="MyFile.txt">MyFile.txt<A>
You need to make a function (yourfunc) that make that update for you with ajax.
I advice you to use this jquery. (www.jquery.com)
http://docs.jquery.com/Ajax/jQuery.ajax
0
kebabsCommented:
You can either set up a HTTP request that triggers through a JavaScript onclick event or simply link to the server side script which both does the counter incrementing and outputs the requested file. The IP address can be obtained with $ENV{REMOTE_ADDR} in Perl.
0
kebabsCommented:
yo_s_canta, that is a bit of an unnecessary burden don't you think? And it requires the client to have JavaScript.
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

yo_s_cantaCommented:
Your solution need also javascript,  you can't do it without js.
That framework will help him in the future, it's very simple to work with that.
look here http://docs.jquery.com/Ajax/load#urldatacallback
It is very simple to do that

$("a").click( 
    function() {
        $.get("count.php", { downloadid: "32345"} );
    }
);

Open in new window

0
tel2Author Commented:
Thanks guys,

I no nothing about ajax and I don't even know if my web host supports it.  I know it supports Perl & PHP (Perl is my preference).

kebabs, you suggested I could:
> simply link to the server side script which both does the counter incrementing and outputs the requested file.
could you please explain how I might do the above?  I know how to get a Perl script to increment the counter, but how do I get it to start the file download?

Thanks.
0
kebabsCommented:
1. I proposed two suggestions. The latter one was the preferred one and does not require JS
2. It might be useful in other scenarios, but it is a dependency nonetheless

This is what I suggest:

<a href="getfile.php?file=MyFile.txt">MyFile.txt</a>

getfile.php
<?php
 
// using PHP as it is more beginner friendly than Perl
 
// quick and dirty validation
if (!isset($_GET['file'])) exit;
// e.g. only allow text files in same directory
if (preg_match('~(\.\.|/)\.txt$~', $_GET['file'])) exit;
 
// Increment counter, get IP ($_SERVER['REMOTE_ADDR']) etc.
 
// Output contents of requested file
readfile($_GET['file']);

Open in new window

0
kebabsCommented:
BTW, I was replying to yo_s_canta.

tel2:
Sorry for using PHP, I didn't see your post until after I wrote it.
You can modify my example to download the requested file by adding:

header('Content-Disposition: attachment; filename="'.$_GET['file'].'"');
header('Content-Length: ' . filesize($_GET['file']));

Here is the modified example:
<?php
 
// quick and dirty validation
 
if (!isset($_GET['file'])) exit;
$file = $_GET['file'];
 
if (!file_exists($file)) exit;
 
// e.g. only allow text files in same directory
if (preg_match('~(\.\.|/)\.txt$~', $file)) exit;
 
// Increment counter, get IP ($_SERVER['REMOTE_ADDR']) etc.
 
// Output contents of requested file, optionally, use a location header
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Content-Length: ' . filesize($file));
readfile($file);
 
?>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
tel2Author Commented:
Thanks kebabs!

Anyone know how to do that in Perl?
0
tel2Author Commented:
In addition to my last post, is there a way I could tell if the file download was completed or not?  Or better still, how much of it was completed (eg: 50% complete).

Thanks.
0
Adam314Commented:
I don't know of any way to tell if it was completed, other than maybe looking in the log file (maybe look at number of bytes transferred)..

Similar to the above, but in perl:
#!/usr/bin/perl
use strict;
use CGI;
use CGI::Carp qw[fatalsToBrowser warningsToBrowser];
 
my $cgi = new CGI;
die "No file specified" unless $cgi->param('file');
 
#If you want to restrict to same dir, or something else...
die "Invalid file specified" if $cgi->param('file') =~ /\.\.\//;
 
print $cgi->header(
    'Content-Disposition' => "attachment; filename=$file",
    'Content-Length' => filesize($file),
    'type' => 'application/x-download');
open(IN,"<", $file) or die "Could not read file: $!\n";
print while(<IN>);
close(IN);

Open in new window

0
tel2Author Commented:
Looks great, Adam!  I plan to try your code soon.

When you talk of the number of bytes transferred (in a log file), are you talking about some file transfer info that the web host provides, or some other log file?
0
tel2Author Commented:
Hi guys,

Having run Adam's script, I got these errors:
    Global symbol "$file" requires explicit package name at getfile.pl line 13.
    Global symbol "$file" requires explicit package name at getfile.pl line 14.
    Global symbol "$file" requires explicit package name at getfile.pl line 16.
    Execution of getfile.pl aborted due to compilation errors.

So, I changed 2 lines as follows:
    die "No file specified" unless my $file = $cgi->param('file');
    die "Invalid file specified" if $file =~ /\.\.\//;    # Optional change

But then I received this error:
    Undefined subroutine &main::filesize called at getfile.pl line 12.

To workaround this, I tried hard-coding the file size (3 bytes for this test):
        'Content-Length' => 3,
but got the same error, so I removed that line completely, and now I can download the file, but the file has the name "getfile.pl" instead of "MyFile.txt".

I know that $file contains "MyFile.txt", because I tried printing it after it was assigned.

How should I resolve all these issues (filesize and wrong filename)?

Thanks.
0
Adam314Commented:
Had a few bugs in that version of the code.  Try this version:
#!/usr/bin/perl
use strict;
use CGI;
use CGI::Carp qw[fatalsToBrowser warningsToBrowser];
 
my $cgi = new CGI;
my $file = $cgi->param('file');
die "No file specified" unless $file;
 
#If you want to restrict to same dir, or something else...
die "Invalid file specified" if $file =~ /\.\.\//;
 
print $cgi->header(
    -Content_Disposition => "attachment; filename=$file",
    -Content_Length => -s $file,
    -type => 'application/x-download');
open(IN,"<", $file) or die "Could not read file: $!\n";
print while(<IN>);
close(IN);

Open in new window

0
tel2Author Commented:
Sorry for the delay in getting back to you guys.

Thanks Adam, that works perfectly!

Thanks kebabs for providing the original version (in PHP).

Thanks yo_s_canta for your JavaScript option.

Good to have you all on the EE team!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Scripting Languages

From novice to tech pro — start learning today.