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

Ok, I'm using CGI to generate pages for a web-based database thing. I have a table of values which I'm outputting, and at the right edge of each row is a button marked "Delete". So it looks like this:
print Tr( start_form(-action => url()), hidden(-name => "hidden", -value => $row), td($row->[0]), td($row->[1]), td($usage), td($cumu_usage), td(submit(-name => "choice", -value => "Delete")), end_form(), );
Where $row is a reference to a row of data. When the user clicks the "Delete" button, the reloading script notices this and tries to look up param("hidden") to figure out where to find the data it wants to delete, like this:
... elsif (param("choice") eq "Delete") { print (param("hidden")); ...
But instead of outputing a memory address, this outputs the 0th element of the array $row was referring to, and so naturally, if I try
$dataref = param("hidden"); $date = $dataref->[0];
Perl complains that I can't use that string as an array reference. Why isn't the reference getting passed through as a reference? Thanks kindly, LassiLantar.

Update: I fixed it by using the primary key of the row to get back to the data I wanted. Thanks for the help! (This is my first question to the Monks, and I must say, I'm impressed =)

Replies are listed 'Best First'.
Re: Passing a reference as the value of a hidden html field
by chromatic (Archbishop) on Jul 20, 2004 at 21:02 UTC
    Why isn't the reference getting passed through as a reference?

    A reference refers to a data structure in memory. Here's a reference from a program I just ran: SCALAR(0x1013751c). Since you're on a different machine, there's not much you can do with it.

    Now you may not run your program on a whole series of servers, which is fine, and may wonder why it doesn't make sense even in the same program. In my case, knowing the reference does me no good because the program has exited. If you're using the CGI model, where the web server launches a separate process to run the program, this is what's happening.

    You may be running mod_perl or another persistent environment, where the program stays running. That's fine, but remember that you're sending this data to a client. Not only may it have absolutely no idea what Perl is or what type of a reference you've passed, imagine what could happen if you did allow the client to tell you what's in your computer's memory!

    You need to pass some other sort of data to identify the rows to delete -- the primary key of the appropriate row often works well. Fortunately, that's usually plain scalar data.

      I'm not proposing to allow my clients to see my memory addresses, it's a purely internal thing. I think I'm just stupid for not deciding to just use a unique ID on each row of data =)

      Interesting that under mod_perl it's persistant and the memory addresses stay. Seems like it would be a poor idea to write scripts to depend on that, though, no? What if someone tries to run your script on a non mod_perl/non persistent environment?

      Thanks!
      LassiLantar

        Even under mod_perl, there are probably multiple server kids serving requests, so there's little guarantee you'll reach the same process as before. You're right that you shouldn't rely on this... but fortunately, it's really hard (but not impossible) to turn a stringified reference back into a real reference.

        There are times in which a similar technique works, though. Continuations can work really well for web programming, though Perl 5 doesn't really support them natively. You'll probably be sorry for asking what they are unless you've used Scheme.

        I'm not proposing to allow my clients to see my memory addresses, it's a purely internal thing.

        But if you use these addresses in hidden fields of html form than everyone can see them in a html source and send back fake addresses. It's a big hole

Re: Passing a reference as the value of a hidden html field
by ccn (Vicar) on Jul 20, 2004 at 20:56 UTC

    I do not know the way to translate a string to a reference, may be it is possible through xs. But who guarantees that in every script invocation you have the same addresses in memory for your rows?

    I suggest to use unique rowID instead of the reference to a row

    Update:You can easily implement exactly what you want:

    my %refhash = map {\$_ => \$_} @rows; $dataref = param("hidden"); $date = $refhash{$dataref};
    But it's a bad way, don't do this.