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

Hi, I got a little problem, I made a script that work pretty well in the command line, but when I put it on the server, half the code is printed, and there's no error message.

#################### CGI ###########################

local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read in text $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "GET") { $buffer = $ENV{'QUERY_STRING'}; } # Split information into name/value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $game = $FORM{game}; $tutorial = $FORM{tutorial}; print "Content-type:text/html\r\n\r\n";

################### Perl ###########################

if (defined($game) && $game !~ m/general|announcement|announcements|do +om3mod|events|finalmap|friends|games|general|hl2mod|pc|recycle|teammo +d|test/) { my $file = "forums/boards/".$game.".txt"; open (my $fh, $file) or die "Can't open $file :$!"; while (defined($line = <$fh>)) { @elements = split(/\|/,$line); print "</var><a href=\"http://www.my-domain.com/tutori +als.pl?tutorial=".$elements[0].">".$elements[1]."<a> Wrote by ".$elem +ents[2]."<br/>"; } }
####################################################

Resume :

I enter a key/value in the browser, if I print the value, it get out fine, if there's no value, the else work fine, but if there's a matching value, it enter the if and it block there. I am guessing it is the while that cause the problem, But I can't find how to fix it, and I don't see why it was working in the command line without error, and not on the server.

The files is at the right location, everything is the same, there's absolutly no error, it just doesn't print anything after the IF, if I entered a matching key/value in the broswer...

Someone could help me? :(

Replies are listed 'Best First'.
Re: Running in Terminal, but not on Server
by moritz (Cardinal) on Jan 24, 2008 at 21:38 UTC
    Use CGI::param() or a similar CPAN module to parse the parameters - don't do it yourself, that's ugly and error-prone.

    Second hint: don't use unfiltered query params as file names. Suppose somebody enters ../../../../etc/password as the game param - an attacker could read arbitrary files on your system.

    Third hint: use strict;. Always. and use warnings;

    Fourth hint: local doesn't declare variables. my does.

    Last one: if you use split, don't trust that the result contains two items - check it.

    BTW an empty file would explain the behaviour of your script.

      Thanks for the hints, I will try to fix them, unfortunately, I can't use Perl/CGI modules as I don't know how to install them (Everything is on a server, no remote terminal, just a cPanel)

      For the use strict; parameter, everytime I use it, my script give me an internal error when put on the server, so I never put it :(.

      Hmm and it would have been nice if it would be that, I thought the same thing first, but there's 2 line inside, and in that case, I can trust the value of split for the opened files as they are all recorded the same way, for each line, via perl. But yeah of course, I will need to verify the one made from the browser.

      It still doesn't work, but thanks for the help, at least I will be able to make it more secure. =)

        CGI is shipped with perl since perl 5.4, which is more than ten years old - chances are that CGI.pm is already installed.

        As for the debugging, try use CGI::Carp qw(fatalsToBrowser); as your first line of code - it will print error messages to the browser. (And yes, CGI::Carp is also a core module since perl 5.4).

        If you can't even access core modules, then either find another server to work on, or chose a different language. Perl without modules really sucks, compared to other languages with modules/libs.

        And btw there is cgipan, which installs CPAN modules via CGI ;-)

        Aww, I almost give up, I don't understand why it doesn't want to open that file. I tryed to put it in read mode, and anyway, the folders accept to be read, but not to be written, so it should work... I also tryed to put absolute URL, or starting the path from the root. Nothing Work. The program just don't want to open it.
      All the folders are set to 755 (Read / Execute) and the files 666 (Read) I have tryed to put them executre but it doesn't change anything. I have looked in my forum file to see how they opened their file but it's a really really long code. I have quickly copied/pasted just to see if it could work, but it didn't change anything on the error. If you wanna see the code, (it's a sub-function, so I had to use fopen instead. It seem to modifiy the filename to destroy the security hole, put a countdown limit on the opened file, and modifiy the file locking.
      # fopen: opens a file. Allows for file locking and better error-ha +ndling. sub fopen ($$;$) { my ($pack, $file, $line) = caller; $file_open++; my ($filehandle, $filename, $usetmp) = @_; ## make life easier - spot a file that's not closed! if (($debug == 1 or ($debug == 2 && $iamadmin))) { $openfiles +.= qq~$filehandle -> $filename ~; } my ($flockCorrected, $cmdResult, $openMode, $openSig); $serveros = "$^O"; if ($serveros =~ m/Win/ && substr($filename, 1, 1) eq ":") { $filename =~ s~\\~\\\\~g; # Translate windows-style \ s +lashes to windows-style \\ escaped slashes. $filename =~ s~/~\\\\~g; # Translate unix-style / slas +hes to windows-style \\ escaped slashes. } else { $filename =~ tr~\\~/~; # Translate windows-style \ s +lashes to unix-style / slashes. } $LOCK_EX = 2; # You can probably keep this +as it is set now. $LOCK_UN = 8; # You can probably keep this +as it is set now. $LOCK_SH = 1; # You can probably keep this +as it is set now. $usetempfile = 0; # Write to a temporary file w +hen updating large files. # Check whether we want write, append, or read. $filename =~ m~\A([<>+]*)(.+)~; $openSig = $1 || ''; $filename = $2 || $filename; $openMode = $yyOpenMode{$openSig} || 0; $filename =~ s~[^/\\0-9A-Za-z#%+\,\-\ \.\:@^_]~~g; # Remove + all inappropriate characters. if ($filename =~ m~/\.\./~) { &fatal_error("cannot_open","$fil +ename. $maintxt{'609'}"); } # If the file doesn't exist, but a backup does, rename the bac +kup to the filename if (!-e $filename && -e "$filename.bak") { rename("$filename.b +ak", "$filename"); } if (-z $filename && -e "$filename.bak") { rename("$filename.ba +k", "$filename"); } $testfile = $filename; if ($use_flock == 2 && $openMode) { my $count; while ($count < 15) { if (-e $filehandle) { sleep 2; } else { last; } ++$count; } unlink($filehandle) if ($count == 15); local *LFH; CORE::open(LFH, ">$filehandle"); $yyLckFile{$filehandle} = *LFH; } if ($use_flock && $openMode == 1 && $usetmp && $usetempfile && + -e $filename) { $yyTmpFile{$filehandle} = $filename; $filename .= '.tmp'; } if ($openMode > 2) { if ($openMode == 5) { $cmdResult = CORE::open($filehandle, + "+>>$filename"); } elsif ($use_flock == 1) { if ($openMode == 4) { if (-e $filename) { # We are opening for output and file locking i +s enabled... # read-open() the file rather than write-open( +)ing it. # This is to prevent open() from clobbering th +e file before # checking if it is locked. $flockCorrected = 1; $cmdResult = CORE::open($filehandle, "+<$filen +ame"); } else { $cmdResult = CORE::open($filehandle, "+>$filen +ame"); } } else { $cmdResult = CORE::open($filehandle, "+<$filename" +); } } elsif ($openMode == 4) { $cmdResult = CORE::open($filehandle, "+>$filename"); } else { $cmdResult = CORE::open($filehandle, "+<$filename"); } } elsif ($openMode == 1 && $use_flock == 1) { if (-e $filename) { # We are opening for output and file locking is enable +d... # read-open() the file rather than write-open()ing it. # This is to prevent open() from clobbering the file b +efore # checking if it is locked. $flockCorrected = 1; $cmdResult = CORE::open($filehandle, "+<$filename"); } else { $cmdResult = CORE::open($filehandle, ">$filename"); } } elsif ($openMode == 1) { $cmdResult = CORE::open($filehandle, ">$filename"); # O +pen the file for writing } elsif ($openMode == 2) { $cmdResult = CORE::open($filehandle, ">>$filename"); # +Open the file for append } elsif ($openMode == 0) { $cmdResult = CORE::open($filehandle, $filename); # +Open the file for input } unless ($cmdResult) { return 0; } if ($flockCorrected) { # The file was read-open()ed earlier, and we have now veri +fied an exclusive lock. # We shall now clobber it. flock($filehandle, $LOCK_EX); if ($faketruncation) { CORE::open(OFH, ">$filename"); unless ($cmdResult) { return 0; } print OFH ''; CORE::close(OFH); } else { truncate(*$filehandle, 0) || &fatal_error("truncation_ +error","$filename"); } seek($filehandle, 0, 0); } elsif ($use_flock == 1) { if ($openMode) { flock($filehandle, $LOCK_EX); } else { flock($filehandle, $LOCK_SH); } } return 1; }