4

I'm not aware of how to grab the query string from the URL using Perl. I've tried a couple of ways, example:

my $qs = $ENV{'QUERY_STRING'};
my @d = split(/&/, $qs);

if ( $d[1] eq 'reports' ) {
    ... do something
}

and

use CGI;
my $q = CGI->new;
my $page = $q->param('page');

But am not getting the value of the key. Right now I'm manually placing in the query string, i.e. project.local/routes.cgi?page=reports but I get the following from the command line:

Use of uninitialized value $qs in split at ./routes.cgi line 23.
Use of uninitialized value $d[1] in string eq at ./routes.cgi line 25.

I'm not sure why this warning exists as it should just be undef if it doesn't exist?

How should I store and check a query string variable? I'm primarily using the routes.cgi script as a routes controller where all links point to i.e. <a href="project.local/routes.cgi?page=xx"> and then I process a template toolkit file and redirect to that page (good concept?)

Results of diagnostics:

Use of uninitialized value $qs in split at ./routes.cgi line 23 (#1)
    (W uninitialized) An undefined value was used as if it were already
    defined.  It was interpreted as a "" or a 0, but maybe it was a mistake.
    To suppress this warning assign a defined value to your variables.

Edit:

use URI qw( );
use URI::QueryParam qw( );

my $u = URI->new($base_url);
my ($p) = $u->query_param('page');

if ( $p eq 'reports' ) {
    ...do something
}
a7omiton
  • 1,597
  • 4
  • 34
  • 61
  • You could try adding `use diagnostics;` for more more details. – Cole Tierney Jul 29 '14 at 12:09
  • @putnamhill thanks, that's pretty helpful. i've included the results of that in my answer – a7omiton Jul 29 '14 at 12:12
  • although i'm not sure that this warning message will help solve the underlying problem, as i'm getting the content of an environment variable? – a7omiton Jul 29 '14 at 12:15
  • Don't parse the URI (or the query args from $ENV) yourself, you're most likely going to do it wrong if you do. Use the CGI object to get at the parameters. Use the https://metacpan.org/pod/URI module if you need (or want) to parse full URIs. – Leeft Jul 29 '14 at 12:23
  • Focus on your second attempt (`use CGI`). The code you have for that example looks fine, what problems are you seeing? – RobEarl Jul 29 '14 at 13:15
  • @RobEarl When I run the script using the url 'cgi-bin/routes.cgi?page=reports' I get an internal server error, and when I run the cgi script from the command line I get an uninitialised value for $q->param('page') – a7omiton Jul 29 '14 at 13:17
  • I might try Mojolicious, as it supports routing built in – a7omiton Jul 29 '14 at 13:18
  • 1
    See http://stackoverflow.com/questions/2165022/how-can-i-troubleshoot-my-perl-cgi-script/2165040#2165040 for help with the dreaded Internal Server Error (specifically the errors to browser/error log part) – RobEarl Jul 29 '14 at 13:20
  • @RobEarl immensely useful, thank you so much for sharing – a7omiton Jul 29 '14 at 13:23

3 Answers3

4

Man, youre fighting many days (based on your past questions) with your route.cgi. Reading thru comments and answers in your past questions, many developers already said to you: use some framework.

Now for your question(s):

Use of uninitialized value $qs in split at ./routes.cgi line 23.

Thats mean (in line, what the use diagnostics says) - the $qs variable isn't contains any value. Why the $ENV{'QUERY_STRING'}; isn't have a value is depends on your environment, but generally, you should not depend on some environment variables but on what you get from the HTTP request.

Use of uninitialized value $d[1] in string eq at ./routes.cgi line 25.

Of course, because the $qs is undefined, the split splits the nothing, and the splitted nothing is nothing too - so you get nothing to your @d array and therefore the $d[1] isn't initialised.

BTW, when you comes from the php-word (as you said in one of your questions), you should to know, than after an succesfull split of the "QUERY_STRING" at & you will get to $d[0] the value page=report and not only the report.

As @AndyLester told you, for handling URL's (getting or composing) its parts here is the URI::URL module, but you really should at least read it's description.

Ad routes: generally is better and nicer and more SEO friendly to have URLs like:

http://example.com/blog/archive/2013/12/20

and not

http://example.com/run?section=blog&action=archive&year=2014&month=12&day=20

So, for the "routes" don't use URL parameters, but the PATH_INFO. And this "philosophy" is already developed into many frameworks, like Poet+Mason, Mojolicious, Dancer and many others, or here are standalone modules for handling routes. (search MetaCPAN.org).

From my point of view, the perl web-app developemnt based on the next commands:

Install my own perl-environment (need only once)

curl -L http://install.perlbrew.pl | bash
#relog, to init the environment

perlbrew available
prelbrew install perl-5.20.0
prelbrew switch perl-5.20.0
prelbrew install-cpanm

When got my "own" perl

cpanm Poet #will install a bunch of modules
#or alternatively
cpanm Mojolicious

And from now, things are relatively easy:

cd my_development_directory
poet new myapp
cd myapp

echo 'This is my report <% localtime %>' > comps/report.mc
./bin/run.pl

and you have an running perl web-application. So, point your browser to: http://localhost:5000/report and will get

This is my report Tue Jul 29 16:09:52 2014

and alongside you will get an great debug panel and much more... (see Mason & Poet manuals)

I'm still an beginner in perl development, so other more experianced perl-monks could give you better advices.

clt60
  • 62,119
  • 17
  • 107
  • 194
1

You want to use the URI::URL module.

http://search.cpan.org/dist/URI/lib/URI/URL.pm

drew010
  • 68,777
  • 11
  • 134
  • 162
Andy Lester
  • 91,102
  • 13
  • 100
  • 152
  • Thanks for sharing that. I still get the uninitialised warning however with the code included in the question now – a7omiton Jul 29 '14 at 12:45
-1

jm666 is correct, you really should consider using a framework. However, if you are looking to keep your module installs to a minimum, try something like this...

use strict;
use warnings;
use URI::Escape;
use Data::Dumper;

#this will catch anything after the "?", as in SomeURL?Var=111&OtherVar=QQQ
my $RequestHash;
if($ENV{"QUERY_STRING"}) {
    #QUERY_STRING="id=demo:5&other=some%20text&last=more%20text"
    my @TempArray=split("&", $ENV{"QUERY_STRING"});
    foreach my $item (@TempArray) {
        my ($Key, $Value)=split("=", uri_unescape($item)); #need to fix this to work with more than one "=" in the value
        $RequestHash->{lc($Key)}=$Value; #normalize the key name to lower case - because you never know what users will do
    } #end foreach
} #end query check if

print Data::Dumper::Dumper($RequestHash);
Rick Sarvas
  • 769
  • 10
  • 20