Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Validating the contents of scalars using an array based list

by JPaul (Hermit)
on Apr 03, 2003 at 17:03 UTC ( [id://247809]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings Monks;
The title isn't terribly descriptive, and I couldn't think of anything better in such a short space... At any rate, this issue:

I'm working on a set of CGIs which read in a number of vars from a FORM submit. I have a list of vars which cannot be empty, so after I read in all the var's using ->param(), I have something like this:

if ($var eq "" || $var2 eq "" || $var3 eq ""} { &complain(); }
Now I've been told that this list of non-empty fields can change depending on the whim of the customer. Therefore I need to have a better, less hard-coded, way of checking the vars. The list of vars that must be non-empty will be imported from DBI, since everything is database based anyway.
My problem is trying to work out a tidy way of actually taking this list of fields and comparing it to the bunch of scalars I have. I could make a hash, and have some kind of routine to check over the hash, ala:
my $var1 = $cgi->param('var1'); my $var2 = $cgi->param('var2'); my $var3 = $cgi->param('var3'); my $h = { 'var1' => $var1, 'var2' => $var2, 'var3' => $var3 }; my @list = qw(var1 var3); foreach (@list) { if (!exists $$h{$_}) { &complain; } }
But that is somewhat untidy, as you can see.
How would you do the above?

My thanks,
JP,
-- Alexander Widdlemouse undid his bellybutton and his bum dropped off --

Replies are listed 'Best First'.
Re: Validating the contents of scalars using an array based list
by broquaint (Abbot) on Apr 03, 2003 at 17:15 UTC
    If you're stuck with using scalars (I'd recommend getting unstuck ASAP and use an actual data structure) then you could do it like this
    no strict 'refs'; for($cgi->param) { ## &func is bad form, see. perlsub complain() unless exists ${__PACKAGE__."::"}{$_} and defined *{ ${__PACKAGE__."::"}{$_} }{SCALAR} and defined ${ *{ ${__PACKAGE__."::"}{$_} }{SCALAR} }; }
    So for each parameter check if the package variable with the name of the given parameter is defined (check symbol table entry, then type glob entry for SCALAR, then value referenced in type slot) and complain if not. So as you can see, using symbolic variables is a very icky route indeed (as Dominus illustrates very very well).
    HTH

    _________
    broquaint

Re: Validating the contents of scalars using an array based list
by BrowserUk (Patriarch) on Apr 03, 2003 at 18:04 UTC

    Instead of fetching your form values individually, look at the CGI::Vars() method for retrieving a hash containing them.

    If you then hold the values which you are comparing against in another hash, the comparison becomes a simple loop.

    If you are looking for exact equality between the two lists, you can even use grep in the conditional.

    my %checks = (var1=>'foo', var2='bar', var3=>'qux' ); my %params = q->Vars; complain() unless keys %checks == grep{ $param{$_} eq $checks{$_} }keys %checks;

    This relies on both grep and keys returning numeric values in a scalar context to determine if all the values in values in %checks had equivalent keys with the same value in %params.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Validating the contents of scalars using an array based list
by hardburn (Abbot) on Apr 03, 2003 at 17:16 UTC

    I think your solution is just fine. Otherwise, you could use something like WWW::Form and set the 'optional' attribute on its validators as needed.

    Update: Didn't notice that you were using symbolic refs. That makes your solution less fine (:

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: Validating the contents of scalars using an array based list
by Super Monkey (Beadle) on Apr 03, 2003 at 17:28 UTC
    Because you have to check for all null values, you will have an O(n) solution. I don't think you can improve much on you approach, other than rolling some step together into one liners. Check out splice(), it could simplify the parameter to scalar assignments for you.
Re: Validating the contents of scalars using an array based list
by TGI (Parson) on Apr 04, 2003 at 05:24 UTC

    Try Params::Validate for all your parameter validation needs.

    You can do something like this:

    my $nonempty = sub { shift() ne '' }; my $check_params = { client1 => sub { validate( @_, { var1 => { type => SCALAR, # a scalar ... callbacks => { # and is non-empty 'not empty' => $nonempty, }, }, var2 => { type => SCALAR, # a scalar ... callbacks => { # and is non-empty 'not empty' => $nonempty, }, }, } ); }, client2 => sub { # more of the same }, }; my %vars; my @varnames = $q->param; @vars{@varnames} = map { $q->param($_) } @varnames; $check_params->{$client}->(%vars);

    With this approach you can check for type, regex matching or require that an arbitrary subroutine(s) return true. You may want to consider generating the hash of functions, instead of having it hard coded.

    Params::Validate is very nice.


    TGI says moo

Re: Validating the contents of scalars using an array based list
by InfiniteSilence (Curate) on Apr 03, 2003 at 22:30 UTC
    I dunno, but doesn't the cgi param function already return an undef when you pass it a bogus param name? In this case wouldn't it be okay to do the following without extra hash creation:
    #!/usr/bin/perl -w use strict; use CGI; #using params in a file 'cause I don't have a webserver handy open(INPUTFILE,"c:\\temp\\inputs.dat"); my $cgi = new CGI(\*INPUTFILE); close(INPUTFILE); my @keywords = qw~man dog horse barker~; foreach(@keywords) { if (!defined($cgi->param($_)) || $cgi->param($_) eq ' ' || $cgi->p +aram($_) eq '' ) { print "Nothing there for $_!\n"; } } #contents of the .dat file are #man=horse #dog=man #horse=

    Celebrate Intellectual Diversity

Re: Validating the contents of scalars using an array based list
by Improv (Pilgrim) on Apr 03, 2003 at 17:41 UTC
    Try this:
    my @varnames = qw{var1 var2 var3}; foreach my $var (@varnames) { if(${$var} eq "") {&complain}; }
    It's kind of ugly, but it might be the best solution..
      It's kind of ugly, but it might be the best solution..

      It is ugly and it most definitely is not the best solution.

      The correct solution involves using a hash and iterating through that hash. One way of doing this could be:

      my @varnames = qw( Var1 Var2 Var3 ); my %params; @params{@varnames} = map { $cgi->param($_) } @varnames; if (grep { !defined $params{$_} || $params{$_} eq '' } @varnames) { &complain; } # Now, at this point, you have read in all your parameters # and verified that each is defined as well as not the # empty string. # Do other stuff here.
      This also illustrates a very important concept in application development - separating the things that can change from the things that won't ... aka Encapsulation. We are separating out the logic from the things being logic'ed. This is especially important for you because you don't know which varnames you want to apply this logic to.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      I like this a bit more than a hash, but why not use real references?

      foreach my $check ( \( $var1, $var2, $var3 ) ) { complain() if $$check eq ''; }
Re: Validating the contents of scalars using an array based list
by aquarium (Curate) on Apr 04, 2003 at 10:37 UTC
    I'm not sure I quite got the drift of what you're doing, but from what I understand: You will be reading from a db table the param names to read off from the currently submitted form, perhaps comparing them also. If that's the case, then the db table should contain param_name and param_value columns....it could also be linked via a foreign key to a forms table...anyway, and then you could grep (param_names should have a pattern to grep easily) through %ENV in a loop. If the name is in %ENV then it is defined, and the loop only needs to check for empty '' values. Chris
Re: Validating the contents of scalars using an array based list
by JPaul (Hermit) on Apr 04, 2003 at 15:53 UTC
    Thanks all, many great ideas which I've percolated into my final solution.
    If you see any problems, please drop a post :)
    I chose to instead of checking the perl variables, check the CGI parameters - which made much more sense, thanks for the ideas Monks;
    my @varlist = qw(var1 var2 var3); foreach (@varlist) { if (!defined $cgi->param($_) || $cgi->param($_) eq "") { &complain($_); } }
    Where &complain() can translate var# into the HTML side field name (ie. "Phone number", instead of 'phone').

    Cheers all;
    JP,
    -- Alexander Widdlemouse undid his bellybutton and his bum dropped off --

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://247809]
Approved by broquaint
Front-paged by Tomte
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-26 04:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found