CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
this is a dump question...

 



menchen
User

Jul 21, 2001, 5:10 PM

Post #1 of 11 (2599 views)
this is a dump question... Can't Post

if i have a variable: $line = "line14";

can i define $line14 as "this is line 14" by doing $$line = "this is line 14"; ?
which in this case $line will be converted to line14, and $$line will be $line14.

i know this is wrong, what is the correct way to do this?


-jason

ps. let me know if i have explain the question correctly.





mhx
Enthusiast / Moderator

Jul 22, 2001, 1:10 AM

Post #2 of 11 (2594 views)
Re: this is a dump question... [In reply to] Can't Post

Hi Jason,

you're talking about symbolic or soft references, and your code is right. This code

Code
$line  = 'line14'; 
$$line = 'this is line 14';
print "\$line = $line\n",
"\$\$line = $$line\n",
"\$line14 = $line14\n";

will print

Code
$line   = line14 
$$line = this is line 14
$line14 = this is line 14

However, using soft references is no good idea in most cases. You shouldn't use them unless you really need them. (Actually I can't think of any case that requires them right now.) Furthermore, the use strict pragma disables soft references to prevent you from accidentially using them.

If $line would have been undefined, either because it was never used or by explictly setting it to undef,

Code
$$line = 'this is line 14';

would have created a hard reference $line to a scalar variable containing 'this is line 14'. This wouldn't have created a new variable $line14 as in the previous example, so

Code
$$line = 'this is line 14'; 
print "\$line = $line\n",
"\$\$line = $$line\n",
"\$line14 = $line14\n";

would print something like

Code
$line   = SCALAR(0x176f120) 
$$line = this is line 14
$line14 =

and besided issue a warning about the usage of an uninitialized variable if run with the -w flag. You can also see the way that hard references are interpolated.
You wouldn't normally use

Code
$$line = 'this is line 14';

to create a hard reference, you rather use the backslash operator:

Code
$line = \'this is line 14';

Which has the same effect, except $line hasn't to be undefined, because it is explicitly assigned a value here.
Hard references run fine under use strict and are the preferred way of working with references in Perl.

If you want to know more about references, have a look at the perlref manpage with perldoc perlref.

Hope this helps.

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



Janie
stranger

Jul 22, 2001, 4:15 AM

Post #3 of 11 (2583 views)
Re: this is a dump question... [In reply to] Can't Post

Hi jason and Marcus.
Marcus. That's a very nice answer and should encourage jason to consider his options. However, and forgive me if I misunderstand, but when you say...


Code
$line = \'this is line 14';

...are you not defeating the whole purpose of the original intention, ie: to use the variable $line to be a symbol for the identifier 'line14'? With your code $line would now hold a reference to 'this is line 14' and cannot be used to initialize $line14.

I had to work on a script once where the original author decided to use about 50 incoming parameter names as subroutine names. He wrote the same number of if/else statements to accomodate. I cleaned it up using symbolic references.
This is Perl, and you can be a little naughty and relax from strict sometimes. Here's a way to retain the original value of $line...


Code
#no strict;		# no warning 
no strict /refs/; # with warning
my $line = *line14;
$$line = 'this is line 14';
print substr($line, rindex($line,":")+1, length($line)), "\n$line\n$$line\n$line14\n";
use strict;

I would use 'no strict /refs/', heed the warning and warn others.

Janie.
map{$,--%(5>>1)^0?push@y,$_:unshift@y,$_}sort(another=>Hacker=>Just=>Perl);for(1&1=>1|0){push@y,shift@y}print"@y"



mhx
Enthusiast / Moderator

Jul 22, 2001, 7:46 AM

Post #4 of 11 (2576 views)
Re: this is a dump question... [In reply to] Can't Post

Hi Janie,


In Reply To
However, and forgive me if I misunderstand, but when you say...

Code
$line = \'this is line 14';

...are you not defeating the whole purpose of the original intention, ie: to use the variable $line to be a symbol for the identifier 'line14'? With your code $line would now hold a reference to 'this is line 14' and cannot be used to initialize $line14.

I didn't want that line to be related to the underlying problem (which I unfortunately don't know very much about from Jason's question). I just put it there to demonstrate a better way of creating a reference than

Code
$$line = 'this is line 14'

Sorry if that was misleading.
Of course, you can use symbolic references where appropriate. But although I know how they work, I never felt the need to use them yet. If I take your example, why pass the name of a subroutine if you can pass a subroutine reference?

Code
sub call_it { shift->() } 
sub testsub { print "TESTSUB\n" }
call_it( \&testsub ); # strict safe
call_it( 'testsub' ); # not strict safe

I'm not a strict fanatic (Ok, I am ;-), but I have too little knowledge about the problem, perhaps there's really a good reason for soft refs. Smile

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



menchen
User

Jul 22, 2001, 10:25 AM

Post #5 of 11 (2575 views)
Re: this is a dump question... [In reply to] Can't Post

both of your answers have helped alot,
thank you very much for answering :)

-jason



Janie
stranger

Jul 22, 2001, 10:37 PM

Post #6 of 11 (2560 views)
Re: this is a dump question... [In reply to] Can't Post

Hi Marcus. Firstly, I agree with you that

Code
$line = \'this is line 14';

is the correct way to assign a reference, and I am also an advocate of strict. I should also appologise for not explaining my example better.

Here's a brief explanation of what I meant. Say you have a pile of if/else statements in a script that's been thrown at you by your boss...


Code
if ($q->param('func') eq "doit") {&doit;} 
if ($q->param('func') eq "printit") {&printit;}
if ($q->param('func') eq "readit") {&readit;}
if ($q->param('func') eq "deleteit") {&deleteit;}
...etc..(63 in all)
(I've changed the identifiers here to save the author from embarrassment)!

...where $q->param('func') is the name of a query string parameter.

Wouldn't it be better to just say something like...


Code
my $action = $q->param('func'); 
no strict 'refs';
&$action if $action;
use strict 'refs';

...and be done with it. What I'm trying to say is that there are occasions when it seems to be more convenient (and efficient dare I say) to lose the shackles. Or is there a way to do this under strict?

Janie.
map{$,--%(5>>1)^0?push@y,$_:unshift@y,$_}sort(another=>Hacker=>Just=>Perl);for(1&1=>1|0){push@y,shift@y}print"@y"



mhx
Enthusiast / Moderator

Jul 22, 2001, 11:47 PM

Post #7 of 11 (2558 views)
Re: this is a dump question... [In reply to] Can't Post

Hi Janie,

Of course, using symbolic references is a lot better than that if-overkill! And now I also see why subroutine references aren't possible in your case. (Because you get the subroutine identifier from a HTTP request.) So, first of all, thanks for letting me know the first real example where you need symbolic references!
However, I would have written something like this:

Code
unless( eval '&'.$q->param('func') ) { 
print h1( "Something's wrong: $@" );
# ... or any other error handler ...
}

It not only runs under strict (I hate those fanatics!! ;-), but the real advantage is that it offers the opportunity for catching the error if the subroutine requested by $param( 'func' ) doesn't exist.

In Reply To
Say you have a pile of if/else statements in a script that's been thrown at you by your boss...

Fortunately, my boss doesn't throw perl code at me ;-) But I see enough code like this in other Perl forums. I remember a piece of code that had about 30 lines just for counting the number of lines in some text files (copy&paste for every file)!

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



Janie
stranger

Jul 23, 2001, 1:07 AM

Post #8 of 11 (2554 views)
Re: this is a dump question... [In reply to] Can't Post

Hi Marcus. Thanks a lot, I'm sold! I would use eval() under strict as you've suggested, but I would...


Code
if($q->param('func')){ 
unless( eval '&'.$q->param('func') ) {
print h1( "Something's wrong: $@" );
}
}

...so I wouldn't have to track down all the url's and make sure they had the 'func' parameter.

Ta, Janie.

map{$,--%(5>>1)^0?push@y,$_:unshift@y,$_}sort(another=>Hacker=>Just=>Perl);for(1&1=>1|0){push@y,shift@y}print"@y"



abstracts
Novice

Jul 23, 2001, 5:01 AM

Post #9 of 11 (2546 views)
Re: this is a dump question... [In reply to] Can't Post

Hello,

Consider:

Code
http://yoursite.com/cgi-bin/yourscript.cgi?func={print(\"Hello\");+unlink+$0}

So, you should get the idea, never execute arbitrary code taken from a cgi program. In this situation, you don't need eval or soft references. The better approach is to use a dispatch table as follows.

Code
sub hello{ print "Hello\n" } 
sub bye{ print "Goodbye\n" }
sub myname{ print "My name is @_\n" }

my %cmds = (
hello => \&hello,
bye => \&bye,
myname => \&myname);

while(<>){
chomp;
my ($cmd, @args) = split;
unless(exists($cmds{$cmd})){
print "Command <$cmd> unknown\n";
next;
}
$cmds{$cmd}->(@args);
}

Hope this helps,,,

Aziz,,,



mhx
Enthusiast / Moderator

Jul 23, 2001, 6:04 AM

Post #10 of 11 (2545 views)
Re: this is a dump question... [In reply to] Can't Post

Yes, I think that's the best approach, even if it results in more typing. I was so centered on references that I forgot about security issues :-(
Perhaps the following shortcut is more convenient for the long list of routines that Janie mentioned.

Code
my %cmds = eval join ',', map "$_ => \\&$_", 
qw(hello bye myname);

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



(This post was edited by mhx on Jul 23, 2001, 5:05 AM)


Janie
stranger

Jul 23, 2001, 7:29 AM

Post #11 of 11 (2541 views)
Re: this is a dump question... [In reply to] Can't Post

Hi abstracts.

quote: "never execute arbitrary code taken from a cgi program"

Of course - it goes without saying. But actually the program didn't accept arbitrary code. I enabled -T and then did something like:


Code
$action = $q->param('func'); 
$action =~ /^(\w*)$/ or die("Can't accept data. Could be dangerous: $!\n");
$action = $1; # untainted

or something to that effect, I can't remember exactly now. But anyway, that wasn't the issue here. We were discussing symbolic references, and I was using the query string function calls as an example. You'll just have to believe me when I say it really wasn't a practical option to rewrite the script. At the time, mine was not to question why!

Janie.

map{$,--%(5>>1)^0?push@y,$_:unshift@y,$_}sort(another=>Hacker=>Just=>Perl);for(1&1=>1|0){push@y,shift@y}print"@y"


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives