1

I'm using a new payment processor, and their data sheet simply says their information is posted as multidimensional array. To quote just a few of the variables:

products[x][prod_number]
products[x][prod_name]
products[x][prod_type]

** There are ten such arrays

I have discovered if the person orders 3 items, there is a variable called "item_count" which means X becomes [0],[1] and [2]

But what is the method to read in this POSTed data and separate it. Sure it's gonna be a 'foreach' loop of some sort, but what variable names I need is a mystery

For normal variables, ie get the "name/value" pairs, I use this:

use CGI qw/:standard/;

@names=param;
foreach $name(@names){
$value=param($name);
$$name=$value;
}

Any pointers?

+++++

Not sure if this is the correct way to add to this post; I'm still learning system

my question now is WHAT FORMAT is this data POSTed to STDIN etc. Or more to the point, what will it be read into. Since "products" is a single variable name, would all the data be within a single "$products" variable, or would all the data be contained within @products?

i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
Cristofayre
  • 121
  • 1
  • 11
  • Gosh, I can't believe this! Posted 35 mins ago, and already 2 responses. Thanks guys. Will take a look at both these replies. This is what I came up with about 5 mins ago. (if comment will show code) Assuming it's all within the variable '$product' ... ' @products=$products; foreach $item(@products){ $prod_num[$item]=$products[$item]['prod_number']; $prod_name[$item]=$products[$item]['prod_name']; $prod_type[$item]=$products[$item]['prod_type']; etc }' – Cristofayre Oct 22 '13 at 15:51

3 Answers3

2
my $num_items = $cgi->param('item_count');

my @ordered_prods;
for my $ordered_prod_num (1..$num_items) {
   my %ordered_prod;
   for my $field_name (qw( prod_number prod_name prod_type )) {
      $ordered_prod{$field_name} =
         $cgi->param("products[$ordered_prod_num][$field_name]");
   }

   push @ordered_prods, \%ordered_prod;
}

Or on second thought,

my @ordered_prods;
for my $param_name ($cgi->param()) {
   if (
      my ($ordered_prod_num, $field_name) =
         $param_name =~ /^products\[([0-9]+)\]\[(\w+)\]\z/
   ) {
      $ordered_prods[$ordered_prod_num]{$field_name} =
         $cgi->param($param_name);
   }
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Of the two, it's easier for my brain to "see" what's happening with code No1 so will use that option. The code I listed below is somewhat long winded and doesn't use what I term "cryptics" (such as $i Ditto with "my"; things seem to usual work without it) – Cristofayre Oct 22 '13 at 15:56
  • 7
    Removing `my` is not acceptable. Always use `use strict; use warnings;`! – ikegami Oct 22 '13 at 16:04
  • Actually, it does use `$i`. But that's easy to fix in both. – ikegami Oct 22 '13 at 16:07
0

Better way to recieve CGI Params:

Hashref:

my $params = { map { $_ => ($cgi->param($_))[0] } $cgi->param };

Straight Hash:

my %params = map { $_ => ($cgi->param($_))[0] } $cgi->param; 

Or Monk-Mode ;)

sub Vars { 
    my $q = shift; 
    my %in; 
    tie(%in,CGI,$q); 
    return %in if wantarray; 
    return \%in; 
} 
Alex Tape
  • 2,291
  • 4
  • 26
  • 36
  • That does not result in a useful data structure. It just pushes the problem deeper in the code, into code that shouldn't care about limits of HTML forms. – ikegami Oct 22 '13 at 15:33
  • 3
    The first is equivalent to `my $params = $cgi->Vars;` – ikegami Oct 22 '13 at 15:35
  • Thanks for the reply. Afraid it's a bit "heavy" for me as I cannot visualise what's going on at each stage, ie break it down into what's happening – Cristofayre Oct 22 '13 at 15:58
0

I managed to solve how multi-dimensional arrays work by developing a little script that others might like to try. (I'm able to test this offline as I have a PERL running on my Window's PC. No doubt others can test via a similar enviroment)

Basically, I copied a "problem" from another poster about how to POST arrays, and built a script to analyse what was being sent from HTML form to server script. I then added my own decoding routine with the help of the answers posted above. In terms of "pure" programming, it's probably crude, but it can be studied stage by stage to see what's happening: (the way I prefer to work!)

 #!/usr/bin/perl
use CGI qw/:standard/;
print "content-type: text/html\n\n";
use CGI::Carp qw( fatalsToBrowser );

if (param('action') eq '1'){    # Ignore this: Simply to help demo work
&output;
}



## The form window
## Allows two people to input required "diameters"

print <<EOF;
<form method="post" action="http://www.MY-DOMAIN.com/cgi-bin/test_multi.pl">    <!--Post to your own domain-->
<input type="hidden" name="action" value="1">                   <!-- Ignore: Simply helps demo script along-->
<table>
<tr>
<td>Customer 0: Top diameter<input name="diameter[0][top]" type="text" size="5"></td>
  <td>Customer 0:Bottom diameter<input name="diameter[0][bottom]" type="text" size="5"></td>
</tr>
<tr>
  <td>Customer 1: Top diameter<input name="diameter[1][top]" type="text" size="5"></td>
  <td>Customer 1: Bottom diameter<input name="diameter[1][bottom]" type="text" size="5"></td>
</tr>
</table>
<input type="submit" value="send form">
</form>
EOF



sub output{         # Ignore fact that it's in sub-routine: Just makes demo easier
print "These are the \"name/value\" pairs as seen by the input to script,<br>ie what form sends to &lt;stdin&gt;<br><b>Note: The \"|\" symbol is added by script for clarity</b><br><br>";
@names=param;
foreach $name(@names){
$value=param($name);
print "$name=$value|";      #Visual reminder of what's happening
}

print "<hr>";

$item_count=1;                  # ONE LESS than less than total number of "levels" in HTML form, ie Customer[0], Customer[1] = 1
@field_name=('top','bottom');           # Fields as defined in form

foreach  $i($item_count){           # Loop through each of the levels, (Customer[0] and Customer[1] in this example)
    foreach $x(@field_name){        # Loop through the fields within each level ([top] and [bottom] in example)
$name=$field_name[$x];              # Places the field name[$x] in the variable "name"
$value=param("diameter[$i][$field_name[$x]]");  # The value of the array is assigned to a variable "value" 
$$name=$value;                  # The name is assigned to a variable, and given the value (ie "$top=xx" "$bottom=zz")
print "Customer $i \$$name=".$value."<br>"; # Visual reminder of what's happening
    }
# Process this loop, and do something with data before moving to next loop
# Values on first loop:  "$i = 0", "$top=xx" and "$bottom=zz" with values of the first array
# Value on second loop: "$i=1", "$top=xx" and "$bottom=zz" with values of the second array
}
print "<hr>";

# The names of "diameter", "top" and "bottom" reflect the names used in the form and would be changed to suit requirements.
# The advantage of this script is it assigns values back to single variables, 
# and avoiding getting in a muddle trying to keep track of which element of [A][B] array one is working on at any time 
}

Hope this might help others learn how the arrays work.

NB: It seems multidimensional arrays are sent in their entirety ie: diameter[0][top]=x&diameter[0][bottom]=z&diameter[1][top]=x&diameter[1][bottom]=z, complete with square brackets in pairs

Cristofayre
  • 121
  • 1
  • 11