Beyond the Basics |
Grrr - Perl (Replace variables in Template) |
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
What am i doing wrong here? I basically modified this off one of my older scripts that i had working... and i can't for the life of me figure out why this isn't working??? I have all the permissions set properly... i can't find any missing semi-colons... all my braces match... *sigh* Help! I thought i had a good handle on this... i know it's probably somethign really simple too. heh. Chris form: http://www.countlesshorizons.com/processforms/form.htm perl: #!/usr/local/bin/perl $title = $input{'title'}; #title of poem $author = $input{'author'}; #author's name $lname = $input{'lname'}; #letter of alphabet to assign author (am or nz) $submission = $input{'submission'}; #body of submission $fileNumber = $input{'filenumber'}; #name of file $prevNum = $fileNumber - 1; #insert file name to assign values $nextNum = $fileNumber + 1; #insert file name to assign values $authEmail = $input{'authemail'}; #author's email address #Subroutines &inputIn; &header; &writePage; #subroutine to read and parse input and place into array sub inputIn { if ($ENV{'REQUEST_METHOD'} eq 'GET') {$formInfo = $ENV{'QUERY_STRING'};} else {read(STDIN, $formInfo, $ENV{'CONTENT_LENGTH'});} @inputPairs = split (/[&;]/, $formInfo); %input = (); foreach $pair (@inputPairs) { $pair =~ s/\+/ /g; ($name, $value) = split (/=/, $pair); $name =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; $value =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; $input{$name} = $value; } } #Subroutine to write CGI Header for HTML page sub header { print qq~Content-type: text/html\n\n~; } #imports template page and replaces variables sub writePage { open(TEMPLATE, 'templatepoems.htm'); @Page = <TEMPLATE>; close(TEMPLATE); foreach $line(@Page) { $line =~ s/\*\*title\*\*/$title/; $line =~ s/\*\*author\*\*/$author/; $line =~ s/\*\*lname\*\*/$lname/; $line =~ s/\*\*submission\*\*/$submission/; $line =~ s/\*\*filenumber\*\*/$fileNumber/; $line =~ s/\*\*prevnum\*\*/$prevNum/; $line =~ s/\*\*nextnum\*\*/$nextNum/; $line =~ s/\*\*authemail\*\*/$authEmail/; print $line; } } template: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> **title**<br> **author**<br> **lname**<br> **submission**<br> **filenumber**<br> **prevnum**<br> **nextnum**<br> **authemail**<br> </body> </html> |
||
© Copyright 2002 C.G. Ward - All Rights Reserved | |||
Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669Michigan, US |
I haven't had the chance to look at the link to see what it's doing, and you didn't give any indication of what it's not doing, but I'm going to take a quick guess. If this doesn't help, I'll try to find time to look more deeply later. My first glace suggests you're trying to use variable before they've been filled? The very first line of the script is assigning $title from the %input hash, but there's absolutely no way that hash can have anything in it yet. Put your call to the inputln routine above the assignments instead of below. Better yet - don't fill two variable for the same job. Change your regular expressions to use the hash. For example … $line =~ s/\*\*title\*\*/$input{'title'}/; … will save a completely useless assignment. Make sense? If that doesn't help, I'll be back after dinner. |
||
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
actually that DOES make complete sense (both, cutting down the work, but especially the point at which the variables are being called) what it's NOT doing, is not filling in the text as it should... not being defined would fit exactly what it's doing.... heh i will try this when i get home tonight ron - thank you, as always, for your help... and... uhmm... if you DO get some free time (hahahah) or at least the inclination, would you mind a quick run through on how i might be able to have the output of this file saved to my server? peace Chris |
||
Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669Michigan, US |
Well, on one hand, saving the information to disk is simple. Concatenate the variables together, open a file for appending, write one line to the file, close the file. Using the tilde char as your field delimiter, it might look like this: $dataline = "$title~$author~$lname~$submission"; open(LOGS,">>path/file.log "); # append operation print LOGS "$dataline\n"; close(LOGS) Piece of cake. Unfortunately, there's always that other hand waiting around to spoil the simplicity. In a multi-user environment, you need to make sure two visitors aren't hitting the disk file at the same exact moment, so you need a file locking mechanism. You also need to make sure your delimiter (the tilde in this case) isn't included as text in any of your variables, or you'll have the wrong number of "fields" in that line. And because you're writing the data as a single line (record) in the text file, you'll need to make sure there's no line breaks in the data, too. The last two are simple substitutions, but the locking mechanism takes a bit more. I use a couple of subroutines to do it. # lock and unlock routines rely on SYMLINK and therefore a # non-existant file can not be locked sub GetLock { my $file_name = $_; my ($i); ## try several times, waiting a second in between for ($i = 1; $i <= 10; ++$i) { ## true if the lock file was created if ( symlink ($file_name, "$file_name.lock") ) { return 1; # success! } sleep 1; } &FATAL("Could not get lock on $file_name<br>$file_name.lock"); return 0; # failure :-( } sub DropLock { my ($file_name) = $_; unlink ("$file_name.lock"); } I make the necessary subsitutions in my input routine, what you're calling inputln. That's because there are a LOT of other substitutions you should make in order to protect the security of your system. A very common hacking trick is to type a OS command as data in a form and then hope the script passes it to the system. To protect ourselves, we need to test for that before doing anything else with the form data. Inside the foreach loop, just before you assign $value to the hash, I would do something like this: # remove potentially dangerous commands that should never # be passed to any Unix process (like sendmail) $value =~ s/\0//g; $value =~ s/system\(.+//g; $value =~ s/grep//g; $value =~ s/\srm\s//g; $value =~ s/\srf\s//g; $value =~ s/\.\.([\/\:]|$)//g; $value =~ s/< *((SCRIPT)|(APPLET)|(EMBED))[^>]+>//ig; # disable all HTML commands (I'm including spaces so it'll show here) $value =~ s/</& lt;/g; $value =~ s/>/& gt;/g; $value =~ s/~/& #0124;/sg; # protect our delimiter $value =~ s/\n/< br>/g; # convert line breaks So now, our "simple" write to disk should look something like this: $dataline = "$title~$author~$lname~$submission"; &GetLock("path/file.log"); open(LOGS,">>path/file.log "); # append operation print LOGS "$dataline\n"; close(LOGS) &DropLock("path/file.log"); |
||
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
worked perfectly fine - thank you so much for your patience Ron. NOW - if you have time, or inclination, i have a few other questions. i'll be trying to find the answers to these as well in my books, but thought i'd pose them in case you had any input: 1. re: above - saving file to server (a raw guess is something to do with STDOUT...) 2. i want to eliminate a space between the characters in a string... oh... i think i may have got it. maybe using something along the lines of: $variable =~ s/\%%20(i don't know what character to use here to represent the space)//g; 3. format a number properly - ie: in above examples, $filenumber comes out as a 6-digit number, but $prevNum and $nextNum comes out as a two or three digit number, skipping all the leading zeros. okies... that should do for now, thoguh of course there's lots more later. heh. thanks again Ron Chris |
||
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
heh of course it's not simple!!! you replied in the (long) time it took me to write my last reply (bouncing back and forth between book and screen... can't seem to find what represents the space character) looks good, and i was just reading about the security issues today - thank you for that snippet. does writing a new "htm" file work along the same lines? i would imagine it does... looks like i'm in for some testing! will come back to this after playing a little bit - this is still so fun! Chris |
||
Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669Michigan, US |
1. Writing files - yea, writing an HTML files is basically the same. Except you rarely have to lock them, and you do NOT want to append as I indicated for the data files (change the >> to a single > to create or re-create a file). To write any file, remember that you have to have permission to do so. That usually means setting up a directory with write permissions before running the script. 2. Eliminating spaces - you have the right idea, but you don't have to "represent" a space with any special code. $variable =~ s/ //; will work fine. 3. Formatting fixed width numbers - this one requires a bit of a kludge. The function sprintf exists so we can print columns of numbers and make sure they line up correctly. It does its job by adding spaces to the beginning of numbers, but we can easily use a regexp to change those leading spaces into leading zeroes. $number = 17; $number = sprintf("%5d", $number); $number =~tr/ /0/; The result would be 00017 |
||
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
OK - all that is good! i even figured out a few things on my own (like how to turn all the letters in a string to lower case and how to retrieve just the first letter!!!) HOWEVER - I am having problem with file permissions... how do i tell the program that i want to do this: ../../processforms/$filename ? I tried it using escape characters (see following, but it's not working???) hmm... will keep working at it. Thanks again Ron Have: open(FILE,">$dir..\/..\/\/processforms\/$fileNumber.htm") || die "Can't create index file $fileNumber: $!\n\n"; Get: Can't create index file 00021: No such file or directory |
||
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296Purgatorial Incarceration |
and i DO have all my permissions set to read write and execute (just in case at this point) |
||
Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669Michigan, US |
Hard to say for sure what's happening, Chris, but the path in your open statement looks, uh, a little strange. How can you have a variable ($dir) in front of the parent dir symbols (double dots)? The best thing is usually to assign your entire open parameter to a variable, and then print that in your die clause. my $openPath = "$dir..\/..\/\/processforms\/$fileNumber.htm"; open(FILE,">$openPath ") || die "Can't create index file $openPath: $!\n\n"; |
||
⇧ top of page ⇧ | ||
All times are ET (US). All dates are in Year-Month-Day format. |