Question

I'm trying to post a new item to a listing website using LWP. The listing website provides an example of how to post the data but using PHP, I’ve therefore tried to reproduce the solution but in Perl.

This is the PHP example.

$postData = array('type'   => 'fixedPrice',
                  'item'   => array(
                      'id_country'         => 0,
                      'id_category'        => 80,
                      'fixed_price'        => '1.00', 
                      'currency'           => 'EUR',
                      'title'              => 'My title',
                      'personal_reference' => 'My personal ref',
));

//RESOURCE CALL WITH POST METHOD

$url = 'http://correct.server.address/item?token=MyPersonalToken';
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, true);
curl_setopt ($ch, CURLOPT_POSTFIELDS, http_build_query($postData) );
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
$xml_response  = curl_exec($ch);

My Perl solution:

#!/usr/bin/perl

### Module requests ###

use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
use XML::LibXML;
use Data::Dumper;

### Make Request to get the session Token ###

my $url = "http://correct.server.address/seller";
my $api = "APIKEY";

my $userAgent = LWP::UserAgent->new();
my $request = HTTP::Request->new(POST => $url . "?apikey=" . $api);
my $response = $userAgent->request($request);

### Display error if request to server fails ###

unless ($response->is_success) {
    print "Content-type: text/html\n\n";
    print "Error: " . $response->status_line;
    exit;
}

### Assign response xml to $xml_token ###

my $xml_token = $response->content;

### Parse XML through XML::LibXML module ###

my $parser = XML::LibXML->new();
my $tree = $parser->parse_string($xml_token);
my $root = $tree->getDocumentElement;
my $token = $root->getElementsByTagName('token');

### Make Request to add Item - PROBLEM STARTS HERE ###

my $postURL = "http://correct.server.address/item" . "?token=" . $token;

my %item_data = (type => "fixedPrice",
                item => {
                    id_country => "0",
                    id_category => "728",
                    fixed_price => "1.00",
                    currency => "GBP",
                    title => "Test item",
                    personal_reference => "12345"
                }
            );

my $userAgentReq2 = LWP::UserAgent->new();
my $requestReq2 = HTTP::Request->new(POST => $postURL);
$requestReq2->header(content_type => 'multipart/form-data');
$requestReq2->content(\%item_data);
my $responseReq2 = $userAgentReq2->request($requestReq2);

### Display error if request to server fails ###

unless ($responseReq2->is_success) {

    print "Content-type: text/html\n\n";
    print "<p>Error Message: " . $responseReq2->status_line;
    print "</p><p>Output of test data sent: \n";
    print Dumper(\%item_data);
    print "</p><p>Dumped Response: \n";
    print Dumper($responseReq2);
    print "</p><p>\n";
    print "Token: $token\n";
    print "</p><p>\n";
    print "Response: " . $responseReq2->as_string;
    print "</p>\n";
    exit;
}

### Assign response xml to $xml_responseReq2 ###

my $xml_responseReq2 = $responseReq2->content;

### Display Token ###

print "Content-type: text/html\n\n";
print "<p>Response: $xml_responseReq2</p>\n";
print Dumper($responseReq2);
exit;

My first post request to retrieve the session token works correctly and I receive the token. However my second post request trying to add the item fails.

This is the dumped response:

$VAR1 = bless( {
                 '_content' => 'Not a SCALAR reference at /usr/lib/perl5/site_perl/5.8.8/LWP/Protocol/http.pm line 203.
',
                 '_rc' => 500,
                 '_headers' => bless( {
                                        'client-warning' => 'Internal response',
                                        'client-date' => 'Fri, 21 Mar 2014 12:13:34 GMT',
                                        'content-type' => 'text/plain',
                                        '::std_case' => {
                                                          'client-warning' => 'Client-Warning',
                                                          'client-date' => 'Client-Date'
                                                        }
                                      }, 'HTTP::Headers' ),
                 '_msg' => 'Not a SCALAR reference',
                 '_request' => bless( {
                                        '_content' => {
                                                        'item' => {
                                                                    'currency' => 'GBP',
                                                                    'id_category' => '728',
                                                                    'id_country' => '0',
                                                                    'personal_reference' => '12345',
                                                                    'title' => 'Test item',
                                                                    'fixed_price' => '1.00'
                                                                  },
                                                        'type' => 'fixedPrice'
                                                      },
                                        '_uri' => bless( do{\(my $o = 'http://correct.server.address/item?token=986aee823d54a7c2d50651c1b272c455')}, 'URI::http' ),
                                        '_headers' => bless( {
                                                               'user-agent' => 'libwww-perl/6.05',
                                                               'content-type' => 'multipart/form-data'
                                                             }, 'HTTP::Headers' ),
                                        '_method' => 'POST'
                                      }, 'HTTP::Request' )
               }, 'HTTP::Response' );

Please can someone help me as to where I’m going wrong, many thanks in advance!

Was it helpful?

Solution

The following appears to achieve what you want.

my %item_data = (type => "fixedPrice",
                'item[id_country]' => "0",
                'item[id_category]' => "728",
                'item[fixed_price]' => "1.00",
                'item[currency]' => "GBP",
                'item[title]' => "Test item",
                'item[personal_reference]' => "12345"
        );

my $userAgentReq2 = LWP::UserAgent->new();
my $responseReq2 = $userAgentReq2->post($postURL,[%item_data]);

OTHER TIPS

PHP allows you to create POST variables that get automatically deserialized into nested structures; for example, you can have form fields called item[0] and item[1] and so forth and those will appear in your server-side PHP script as an array of values. But HTTP does not have any concept of arrays; post data are simple key and value pairs.

The sample client-side PHP code is trying to build a nested array structure which PHP's curl interface will automatically translate into HTTP field names. It's been a million years since I've done any PHP, but I think the field names would end up being item[0][id_country], item[0][id_category], and so on. This is how PHP "cheats" HTTP to put complex structure into POSTs.

Perl's LWP library does not support building field names out of nested structures this way. That's why you're getting this error:

Not a SCALAR reference at /usr/lib/perl5/site_perl/5.8.8/LWP/Protocol/http.pm line 203. '

In your POST arguments, the item key is pointing to a hash reference, but LWP expects to only see a plain scalar or scalar reference there.

So you'll need to change your LWP POST parameters to something like the following. (If this is not exactly right, you can use a HTTP sniffer on the PHP code to figure out what the actual field names are that it generates.)

my %item_data = (type => "fixedPrice",
                 'item[0][id_country]' => "0",
                 'item[0][id_category]' => "728",
                 'item[0][fixed_price]' => "1.00",
                 'item[0][currency]' => "GBP",
                 'item[0][title]' => "Test item",
                 'item[0][personal_reference]' => "12345"
            );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top