How to pass a name-value pair as an argument in Perl - perl

I think this is very basic perl question but I am not getting it through.
I am using LWP::UserAgent package to build a post request in perl script.
The code is as follows:
my $urlStr = "http://localhost/testproj/AServlet";
my $postDataStr = "{name => \'ankur434\'}";
my $response = $ua->post($urlStr, $postDataStr);
The above code doesn't work & gives following error -
<Dec 6, 2010 3:15:54 PM IST> <Error> <HTTP> <BEA-101215> <Malformed Request "/testproj/AServlet". Request parsing failed, Code: -1>
However when I directly pass postDataStr's value to post method, it works perfectly well, like shown below:
my $response = $ua->post($urlStr, {name => 'ankur434'});
I tried few options like escaping { with backward slash (\{) but nothing worked...
Can anyone suggest something? Thanks!

{name => 'ankur434'}
is a hash reference.
"{name => \'ankur434\'}"
is, as your variable name indicates, a string.
Perl does not automatically convert the latter to the former.
You seem to be under the impression that in Perl, only strings can be assigned to variables or passed to subroutines.
This is not the case. Just use
my $urlStr = "http://localhost/testproj/AServlet";
my $postData = {name => 'ankur434'};
my $response = $ua->post($urlStr, $postData);

Related

Error: ' Can't use string ("") as a HASH ref while "strict refs" ' in combination with google recaptcha v2. Works on local machine but not on webhost

I am very new to Perl and was just assigned the quick task to change the reCAPTCHA to reCAPTCHA v2.
On my local machine this works fine, however when I push the new version of the login form to the webhost, the form does not seem to work. I get the following error:
AH01215: Can't use string ("") as a HASH ref while "strict refs" in use at login_new.cgi line 68, line 1.: [........]
The code snippet is based on the documentation I found here: https://metacpan.org/pod/Captcha::reCAPTCHA::V2
And according to the error log my error is somewhere in here (line 68):
if ($submit) {
my $response = $cgi->param('g-recaptcha-response');
my $result = $captcha->verify($captcha_private_key, $response );
if ($result->{success}) # This is line 68
{....}
This is quite confusing to me, especially since it is working on my local machine. Could you please help? Best regards and thank you in advance!
The Verify Function has a bug. I just looked at the implementation. in case that "$res" isn't 'successful' it wont give you back the wanted hash reference.
As a quick workaround I would check if your my $result is equal to "" if thats the case the verify function failed.
In the long run you should probably submit that bug to the creator of the module.
disclaimer: I havent downloaded the module and just looked at the source without actually trying my workaround so take it with a grain of salt and try it in a safe environment first
sub verify {
my ($self, $secret, $response, $remoteip) = #_;
# ... more code here, removed for better readability
my $res = $self->{ua}->post_form(
$self->{verify_api},
$params
);
if ($res->{success}) {
my $content = decode_json $res->{content};
if ($content->{success}){
return { success => 1 };
} else {
return { success => 0, error_codes => $content->{'error-codes'} };
}
}
}

Attempt to access upserted_id property in perl MongoDB Driver returns useless HASH(0x3572074)

I have a Perl script that pulls a table from a SQL database ($row variable) and attempts to do a MongoDB update like so:
my $res = $users->update({"meeting_id" => $row[0]},
{'$set' => {
"meeting_id" => $row[0],
"case_id" => $row[1],
"case_desc" => $row[2],
"date" => $row[3],
"start_time" => $row[4],
"end_time" => $row[5],
#"mediator_LawyerID" => $row[6],
"mediator_LawyerIDs" => \#medLawIds,
"case_number" => $row[6],
"case_name" => $row[7],
"location" => $row[8],
"number_of_parties" => $row[9],
"case_manager" => $row[10],
"last_updated" => $row[11],
"meeting_result" => $row[12],
"parties" => \#partyList
}},
{'upsert' => 1}) or die "I ain't update!!!";
My client now wants ICS style calendar invites sent to their mediators. Thus, I need to know whether an update or insert happened. The documentation for MongoDB::UpdateResult implies that this is how you access such a property:
my $id = $res->upserted_id;
So I tried:
bless ($res,"MongoDB::UpdateResult");
my $id = $res->upserted_id;
After this code $id is like:
HASH(0x356f8fc)
Are these the actual IDs? If so, how do I convert to a hexadecimal string that can be cast to Mongo's ObjectId type? It should be noted I know absolutely nothing about perl; if more of the code is relevant, at request I will post any section ASAP. Its 300 lines so I didn't want to include the whole file off the bat.
EDIT: I should mention before anyone suggests this that using update_one instead of update returns the exact same result.
HASH(0x356f8fc) is a Perl Hash reference. It's basically some kind of (internal) memory address of some data.
The easiest way to get the contents is Data::Dumper:
use Data::Dumper
[...]
my $result = $res->upserted_id;
print Dumper($result);
HASH(0x356f8fc) is just the human readable representation of the real pointer. You must dump it in the same process and can't pass it from one to another.
You'll probably end up with something like
`my $id = $result->{_id};`
See the PerlRef manpage for details.
See also the MongoDB documentation about write concern.
PS: Also remember that you could use your own IDs for MongoDB. You don't need to work with the generated ones.

Using variable for HTTP request headers with Perl

I am trying to write a function to create HTTP requests (POST and GET mostly) in Perl. I am keeping everything generic by using variables so that I don't have to worry about the type of request, the payload, headers, etc, however HTTP::Request->header() doesn't seem to like my variable:
my($req_type, $headers, $endpoint, $args, $request, $jsonfile) = #_;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new($req_type => $endpoint);
$req->content_type('application/json');
foreach (#$headers) {
$req->push_header($_);
}
$req->content($args);
$req->content($request);
print "request : ".$req->as_string;
I tried a few different approches, and using push_header got me the closest, but I realize it may not be the best solution. I think it might have something to do with single quotes getting passed in:
#headers = "'x-auth-token' => '$_token'";
I can post more of the code if it is helpful. I'm hoping some Perl guru will know exactly what I'm doing wrong. I'm sure it's something to do with the format of the string I'm passing in.
#headers = "'x-auth-token' => '$_token'";
The header function expects to be passed two arguments. The header name and the header value.
You are passing it one argument: a string containing a fragment of Perl code.
You need to format your data more sensibly.
my %headers = (
"x-auth-token" => $_token;
);
and
foreach my $header_name (keys %headers) {
$req->push_header($header_name => $headers{$header_name});
}

WWW::Mechanize text field issue

I'm trying to submit a form by post method using WWW::Mechanize perl module.
use WWW::Mechanize;
my $mech = WWW::Mechanize->new();
...
$mech->get($url);
...
my $response = $mech->submit_form(
form_name => $name,
fields => {
$field_name => $field_value
},
button => 'Button'
);
$field_name is generally speaking a text field (though the type is not specified explicitly in the form), which has a preset value.
$field_name => $field_value in $mech->submit_form on whatever reason does not replace the value, instead $field_value is added into the form after the original value:
{submitted_field_value} = {original_value},{provided_value}
How to replace {original_value} with {provided_value} in the form to be submitted ?
What happens if you add this single line to your code before calling $mech->submit_form():
$mech->field( $name, [$field_value], 1 );
This makes sure that the first value is added, or overwritten if it already exists.
1 is the number parameter (or position index)
See the documentation of WWW::Mechanize:
$mech->field( $name, \#values, $number )
Given the name of a field, set its value to the value specified. [...]
The optional $number parameter is used to distinguish between two
fields with the same name. The fields are numbered from 1.
It's important to remember WWW::Mechanize is better thought of as a 'headless browser' as opposed to say LWP or curl, which only handle all the fiddly bits of http requests for you. Mech keeps its state as you do things.
You'll need to get the form by using $mech->forms or something similar (its best to decide from the documentation. I mean there so many ways to do it.), and then set the input field you want to change, using the field methods.
I guess the basic way to do this comes out as so:
$mech->form_name($name);
$mech->field($field_name, $field_value);
my $response = $mech->click('Button');
Should work. I believe it will also work if you get the field and directly use that (ie my $field = $mech->form_name($name); then use $field methods instead of $mech.
I managed to make it working at my will. Thanks Timbus and knb for your suggestions. Though my case may not be completely general (I know the preset value) but I'd share what I've found (by trails & errors).
my $mech = WWW::Mechanize->new();
$mech->get($url);
$mech->form_name( $name );
my $fields = $mech->form_name($name);
foreach my $k ( #{$fields->{inputs}}){
if ($k->{value} eq $default_value){
$k->{value}=$field_value;
}
}
my $response = $mech->click('Button_name');

How do I pass a variable into a URL in a Perl script?

How do I pass a variable into a URL in a Perl script?
I am trying to pass the variables in an array to url. For some reason it is not working. I am not sure what I am doing wrong. The code roughly looks like this:
#coins = qw(Quarter Dime Nickel);
foreach (#coins) {
my $req = HTTP::Request->new(POST =>'https://url/$coins.com');
}
This does not work as $coins does not switch to Quarter,Dime,Nickel respectively.
What am I doing wrong?
First, variables do not interpolate in single quoted strings:
my $req = HTTP::Request->new(POST => "https://url/$coins.com");
Second, there is no variable $coins defined anywhere:
foreach my $coin (#coins) {
my $req = HTTP::Request->new(POST => "https://url/$coin.com");
}
Also, make sure to use strict and warnings.
You should also invest some time into learning Perl properly.
Use
'https://url/' . $_ . '.com'
Instead of your
'https://url/$coins.com'