How can I troubleshoot my Perl CGI script?

前端 未结 8 1086
深忆病人
深忆病人 2020-11-22 02:43

I have a Perl script that isn\'t working and I don\'t know how to start narrowing down the problem. What can I do?


Note: I\'m adding the question because I rea

相关标签:
8条回答
  • 2020-11-22 02:49

    I think CGI::Debug is worth mentioning as well.

    0 讨论(0)
  • 2020-11-22 02:54

    It will probably also be worth mentioning that Perl will always tell you on what line the error occurs when you execute the Perl script from the command line. (An SSH Session for example)

    I will usually do this if all else fails. I will SSH into the server and manually execute the Perl script. For example:

    % perl myscript.cgi 
    

    If there is a problem then Perl will tell you about it. This debugging method does away with any file permission related issues or web browser or web server issues.

    0 讨论(0)
  • 2020-11-22 02:59

    Are you using an error handler while you are debugging?

    die statements and other fatal run-time and compile-time errors get printed to STDERR, which can be hard to find and may be conflated with messages from other web pages at your site. While you're debugging your script, it's a good idea to get the fatal error messages to display in your browser somehow.

    One way to do this is to call

       use CGI::Carp qw(fatalsToBrowser);
    

    at the top of your script. That call will install a $SIG{__DIE__} handler (see perlvar)display fatal errors in your browser, prepending it with a valid header if necessary. Another CGI debugging trick that I used before I ever heard of CGI::Carp was to use eval with the DATA and __END__ facilities on the script to catch compile-time errors:

       #!/usr/bin/perl
       eval join'', <DATA>;
       if ($@) { print "Content-type: text/plain:\n\nError in the script:\n$@\n; }
       __DATA__
       # ... actual CGI script starts here
    

    This more verbose technique has a slight advantage over CGI::Carp in that it will catch more compile-time errors.

    Update: I've never used it, but it looks like CGI::Debug, as Mikael S suggested, is also a very useful and configurable tool for this purpose.

    0 讨论(0)
  • 2020-11-22 03:00

    You may run the perl cgi-script in terminal using the below command

     $ perl filename.cgi
    

    It interpret the code and provide result with HTML code .It will report the error if any.

    0 讨论(0)
  • 2020-11-22 03:06

    I wonder how come no-one mentioned the PERLDB_OPTS option called RemotePort; although admittedly, there aren't many working examples on the web (RemotePort isn't even mentioned in perldebug) - and it was kinda problematic for me to come up with this one, but here it goes (it being a Linux example).

    To do a proper example, first I needed something that can do a very simple simulation of a CGI web server, preferably through a single command line. After finding Simple command line web server for running cgis. (perlmonks.org), I found the IO::All - A Tiny Web Server to be applicable for this test.

    Here, I'll work in the /tmp directory; the CGI script will be /tmp/test.pl (included below). Note that the IO::All server will only serve executable files in the same directory as CGI, so chmod +x test.pl is required here. So, to do the usual CGI test run, I change directory to /tmp in the terminal, and run the one-liner web server there:

    $ cd /tmp
    $ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'
    

    The webserver command will block in the terminal, and will otherwise start the web server locally (on 127.0.0.1 or localhost) - afterwards, I can go to a web browser, and request this address:

    http://127.0.0.1:8080/test.pl
    

    ... and I should observe the prints made by test.pl being loaded - and shown - in the web browser.


    Now, to debug this script with RemotePort, first we need a listener on the network, through which we will interact with the Perl debugger; we can use the command line tool netcat (nc, saw that here: Perl如何remote debug?). So, first run the netcat listener in one terminal - where it will block and wait for connections on port 7234 (which will be our debug port):

    $ nc -l 7234
    

    Then, we'd want perl to start in debug mode with RemotePort, when the test.pl has been called (even in CGI mode, through the server). This, in Linux, can be done using the following "shebang wrapper" script - which here also needs to be in /tmp, and must be made executable:

    cd /tmp
    
    cat > perldbgcall.sh <<'EOF'
    #!/bin/bash
    PERLDB_OPTS="RemotePort=localhost:7234" perl -d -e "do '$@'"
    EOF
    
    chmod +x perldbgcall.sh
    

    This is kind of a tricky thing - see shell script - How can I use environment variables in my shebang? - Unix & Linux Stack Exchange. But, the trick here seems to be not to fork the perl interpreter which handles test.pl - so once we hit it, we don't exec, but instead we call perl "plainly", and basically "source" our test.pl script using do (see How do I run a Perl script from within a Perl script?).

    Now that we have perldbgcall.sh in /tmp - we can change the test.pl file, so that it refers to this executable file on its shebang line (instead of the usual Perl interpreter) - here is /tmp/test.pl modified thus:

    #!./perldbgcall.sh
    
    # this is test.pl
    
    use 5.10.1;
    use warnings;
    use strict;
    
    my $b = '1';
    my $a = sub { "hello $b there" };
    $b = '2';
    print "YEAH " . $a->() . " CMON\n";
    $b = '3';
    print "CMON " . &$a . " YEAH\n";
    
    $DB::single=1;  # BREAKPOINT
    
    $b = '4';
    print "STEP " . &$a . " NOW\n";
    $b = '5';
    print "STEP " . &$a . " AGAIN\n";
    

    Now, both test.pl and its new shebang handler, perldbgcall.sh, are in /tmp; and we have nc listening for debug connections on port 7234 - so we can finally open another terminal window, change directory to /tmp, and run the one-liner webserver (which will listen for web connections on port 8080) there:

    cd /tmp
    perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'
    

    After this is done, we can go to our web browser, and request the same address, http://127.0.0.1:8080/test.pl. However, now when the webserver tries to execute the script, it will do so through perldbgcall.sh shebang - which will start perl in remote debugger mode. Thus, the script execution will pause - and so the web browser will lock, waiting for data. We can now switch to the netcat terminal, and we should see the familiar Perl debugger text - however, output through nc:

    $ nc -l 7234
    
    Loading DB routines from perl5db.pl version 1.32
    Editor support available.
    
    Enter h or `h h' for help, or `man perldebug' for more help.
    
    main::(-e:1):   do './test.pl'
      DB<1> r
    main::(./test.pl:29):   $b = '4';
      DB<1>
    

    As the snippet shows, we now basically use nc as a "terminal" - so we can type r (and Enter) for "run" - and the script will run up do the breakpoint statement (see also In perl, what is the difference between $DB::single = 1 and 2?), before stopping again (note at that point, the browser will still lock).

    So, now we can, say, step through the rest of test.pl, through the nc terminal:

    ....
    main::(./test.pl:29):   $b = '4';
      DB<1> n
    main::(./test.pl:30):   print "STEP " . &$a . " NOW\n";
      DB<1> n
    main::(./test.pl:31):   $b = '5';
      DB<1> n
    main::(./test.pl:32):   print "STEP " . &$a . " AGAIN\n";
      DB<1> n
    Debugged program terminated.  Use q to quit or R to restart,
      use o inhibit_exit to avoid stopping after program termination,
      h q, h R or h o to get additional info.
      DB<1>
    

    ... however, also at this point, the browser locks and waits for data. Only after we exit the debugger with q:

      DB<1> q
    $
    

    ... does the browser stop locking - and finally displays the (complete) output of test.pl:

    YEAH hello 2 there CMON
    CMON hello 3 there YEAH
    STEP hello 4 there NOW
    STEP hello 5 there AGAIN
    

    Of course, this kind of debug can be done even without running the web server - however, the neat thing here, is that we don't touch the web server at all; we trigger execution "natively" (for CGI) from a web browser - and the only change needed in the CGI script itself, is the change of shebang (and of course, the presence of the shebang wrapper script, as executable file in the same directory).

    Well, hope this helps someone - I sure would have loved to have stumbled upon this, instead of writing it myself :)
    Cheers!

    0 讨论(0)
  • 2020-11-22 03:09

    For me, I use log4perl . It's quite useful and easy.

    use Log::Log4perl qw(:easy);
    
    Log::Log4perl->easy_init( { level   => $DEBUG, file    => ">>d:\\tokyo.log" } );
    
    my $logger = Log::Log4perl::get_logger();
    
    $logger->debug("your log message");
    
    0 讨论(0)
提交回复
热议问题