in reply to Re: Re: Not my first program, but the first I'll share...
in thread Not my first program, but the first I'll share...
I was asked by pekkhum if I could explain a bit, so here's the best job I am capable of doing. Hopefully it's enough to help out a bit.
1. #!c:/perl/bin/perl -w 2. $|++; 3. use strict; 4. use CGI::Simple; 5. use HTML::Template;
Line 1 lets us know where perl is. '-w' switch enables some warnings that help us better our programs. Line 2 disables output buffering. Basically, perl sends data output to its destination as fast as possible. Lines 3-5 import modules we will use to make things much simpler. CGI::Simple is used, just because I prefer it over the bloated CGI.pm.
7. my $q = CGI::Simple->new; 8. my $t = HTML::Template->new( filehandle => *DATA );
These 2 lines call what is known as a 'constructor'. Line 7 starts a new CGI.pm session, so we can manipulate the CGI environment. Line 8 loads a template we will fill. Less messy and much better to use a template system over CGI.pm's html-generating methods. The filehandle => *DATA part means we are reading the template from an open filehandle (which in this case happens to be the magical in-file __DATA__ block). Essentially, we are telling the HTML::Template module to read in everything below the __DATA__ at the bottom of the file.
10. my @ext = qw( pl css htm html shtm shtml ); 11. my $file = $q->param('file'); 12. my $fh;
Line 10 is an array containing a list of extensions we will allow a user to view through this script. The qw() simply lets us make a list without using tons of quotes (so we don't have to use my @ext = ( 'pl', 'css', 'htm', 'html', 'shtm', 'shtml' );). Line 10 uses our $q object from CGI::Simple to get the decoded value of the 'file' parameter that got passed to our script. Line 12 defines a variable named $fh that we will later use as a filehandle to read in a file.
14. if ( 15. ($file =~ /[^a-zA-Z0-9_\-\.]/) or 16. ($file =~ /\.\./) or ($file eq '.') or 17. !(grep { $file =~ /\.$_\z/i } @ext) 18. !(-e $file) or 19. !(open $fh, '<', $file) or 20. ) {
This looks like a lot. We'll break it down into each separate statement. In line 15 we use a regular expression (aka 'regex') to test the contents of the $file variable (which we earlier set the the value of the 'file' parameter passed to the script. /[^xyz]/ will return true if $file contains any character that is not a 'x', 'y', or 'z', so our regex will fail if $file contains character(s) other than letters, numbers, hyphens, underscores and periods. Line 16 simply ensures that the user cannot attempt to navigate the directory tree or use '.' as a filename. Line 17 tests the filename passed by the user to make sure it is an acceptable extension as defined in the @ext array. Line 18 makes sure the file exists before we try to open it. Line 19 tries to open the file for reading.
21. $t->param( 22. title => 'My File Viewer', 23. file => 'Script Error', 24. code => 'An error occured while preparing the file for displa +y.' 25. ); 26. } 27. 28. else { 29. $t->param( 30. title => 'My File Viewer', 31. file => $file, 32. code => do { local $/; <$fh> } 33. ); 34. }
The tests presented from lines 15-19 are grouped together with 'or' statements, so that the entire if() statement will return false if any of the tests (bad filename, bad extension, non-existant file, open() call failed) fail. If all tests pass, then lines 21 through 25 will be executed. If any of the tests fail, then lines 29 through 33 will be run instead. Lines 21-25 fill our template with values that display an error to the user. Lines 29-33 fill the template with a page title, filename, and file contents.
36. print $q->header, $t->output; 37. exit;
Line 36 prints out a valid http header, followed by the resulting filled-out template. Line 37 simply makes a clean exit.
The most confusing pieces of code within this script are most likely learning how the template system functions and the combination of tests for valid user input. For help with the former, check out the documentation for HTML::Template. As for further help with the code, feel free to ask me anything and I'll _try_ to answer. Upon failure of further explanation, I'll try to point you to the right help docs. Good luck.
If the above content is missing any vital points or you feel that any of the information is misleading, incorrect or irrelevant, please feel free to downvote the post. At the same time, please reply to this node or /msg me to inform me as to what is wrong with the post, so that I may update the node to the best of my ability.
|
|---|