Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Interpolating variables for use in method calls

by dpatrick (Scribe)
on Jul 13, 2001 at 23:23 UTC ( #96546=perlquestion: print w/replies, xml ) Need Help??

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

I need to accept a cgi variable from which is to
interpolate into a constructor method for class
Allsys::Resource::ManMan in which there are several
different constructors, namely

newDocument
openDocument
viewDocument

(with
saveDocument
closeDocument
as destructors, kind of).

elsif (defined($q->param('task'))) { my $task = $q->param('task'); if ($task =~ /^([\w]+)$/) { $task = $1; # untainting } my $refname = $q->param('refname'); if ($refname =~ /^([\w]+)$/) { $refname = $1; # untainting } my $ref = "Allsys::Resource::ManMan->" . $task . "Document($refnam +e)"; my $documents = {}; $documents->{$refname} = eval($ref); print $documents->{$refname}; }


The third from last line is where I've tried to do this.
Can anyone shed some light on what I'm doing wrong?

dap

Replies are listed 'Best First'.
(ar0n) Re: Interpolating variables for use in method calls
by ar0n (Priest) on Jul 13, 2001 at 23:32 UTC
    You're using double quotes where you should be using single:
    my $ref = 'Allsys::Resource::ManMan->' . $task . 'Document($refname)';

    The problem is that $refname gets interpolated in double quotes, which will result in a function call with a bareword in it. Single quotes don't interpolate, so...

    Note that only the last string needs single quotes. I changed them both for consistency's sake :)

    ar0n ]

      Thank you. That worked, but I don't quite understand why.
      I thought that I needed $refname to be interpolated before
      the eval in order for the parameter to be passed to viewDocument()
      ...

      dap

        Let me expand on what arOn was saying

        Suppose you ultimately want to call foo->bar( $baz ). And the way you want to achieve it is by dynamically deciding what the subroutine you're going to use, like so:

        my $subname = 'baz'; my $param = { abc => 'xyz' }; # or an object. whatever. eval 'foo->' . "$subname( \$param )";

        Okay, now observe what happens when you call the eval.

        # first, the string that is to be eval'ed is created 'foo->' . "$subname( \$param )" => 'foo->baz( $param )' # then the eval kicks in eval 'foo->baz( $param )' # which is effectively means foo->baz( $param ); # where $param is the ref to a hash

        Now observe what happens if I change the quotations and such...

        # suppose we use "$subname( $param )" 'foo->' . "$subname( $param )" => "foo->baz( 'HASHx(....)' )" # where HASHx(...) is the string representation of the # hash ref. this happens because you're interpolating # the hashref within the string end result => foo->baz( 'HASHx( .... )' ); ---- # what if we use "baz( $param )" ? 'foo->' . "baz( $param )" => "foo->baz( 'HASHx(....)' )" # ah, same as the example above end result => foo->baz( 'HASHx( .... )' ); ---- # suppose we use '$subname( $param )' 'foo->' . '$subname( $param )' => 'foo->$subname( $param )' # so no interpolation is done in the first step... foo->$subname( $param ); # ah, but this is perfectly valid!

        Hope that clears things up. Personally, I like suaveant's way of calling method better, though

Re: Interpolating variables for use in method calls
by suaveant (Parson) on Jul 13, 2001 at 23:34 UTC
    You know that you can do just...
    my $method = $task.'Document'; $documents->{$refname} = Allsys::Resource::ManMan->$method($refname);
    That should work...

                    - Ant

Re: Interpolating variables for use in method calls
by HyperZonk (Friar) on Jul 13, 2001 at 23:33 UTC
    I wouldn't do that. You are untainting something that should not, IMO, be untainted. Consider an if statement and call the darn method from there. You are definitely asking for trouble with this code.

    All someone would have to do is return
    'NewDocument($refname);unlink(*);'

    and you would wish you hadn't used this shortcut.

    Update: Indeed, as noted below, you can only use letters, numbers, and _ or your regex will cast it out like so many demons. Still, there would seem to me to be just a little too much room for an exploit here. IMO, of course.
      I got you, and I considered using if/elsif or a switch to
      do call the methods, which I still may do, though the regex
      I'm using only allows words containing alphabet characters
      correct?

      dap

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2023-03-29 22:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which type of climate do you prefer to live in?






    Results (73 votes). Check out past polls.

    Notices?