Post Nested parameters using Curl in PHP - php

This is the Request body that I need to send- (Curl POST request in PHP)
$data = {
"paramOne" : "f733787d-5649",
"paramTwo": {
"format": "123XD"
},
"paramThree": [
{"type":"cn", "value":"Test User Manish 1"},
{"type":"c", "value":"US"}
]
};
I'm trying to use it at this line of my Curl Request in PHP-
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
The nested params are messing up the format in which I'm trying to send.
I already tried using http_build_query but then paramThree is causing problems.
I'm looking for the changes that I need to make to the format of $data before I use http_build_query on it.

It's JSON. You can either post it as a string (enclosed in quotes) or make an array first, convert it to JSON and then post it. Like this:
$array = [
'paramOne' => 'f733787d-5649',
'paramTwo' => [
'format' => '123XD'
],
'paramThree' => [[
'type' => 'cn',
'value' => 'Test User Manish 1'
],
[
'type' => 'c',
'value' => 'US'
]]
];
$data = json_encode($array);
In both cases use
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));

Related

Guzzle with Laravel 9

I'm working on Lavravel 9 with guzzle to send some data in
the below code need to get some data from the database how can get data from the database?.
$response = Http::post('APIurl', [
"headers" => [
//header information
],
"body" => [
'title' => "**Get data from database**",
'body' => "**Get data from database**,
'userId' => 22
],
]);
Thank you
Assuming your API returns a json result, simply call the json() method on the Response object. If you want the raw response body, use body() instead.
For example, take github's api:
$response = Http::get('api.github.com'); // replace with your call
$body = $response->body(); // returns string
$json = $response->json(); // tries to return a json array.
To add data to your request, try passing a json string in the body.
$data = json_encode([
'title' => ...,
'body' => ...,
'user_id' => ...,
]);
$response = Http::post('your-api-here', [
'headers' => [
...
],
'body' => $data,
]);

Guzzle: Sending POST with Nested JSON to an API

I am trying to hit a POST API Endpoint with Guzzle in PHP (Wordpress CLI) to calculate shipping cost. The route expects a RAW JSON data in the following format:
{
"startCountryCode": "CH"
"endCountryCode": "US",
"products": {
"quantity": 1,
"vid": x //Variable ID
}
}
Link to the API I am consuming: https://developers.cjdropshipping.com/api2.0/v1/logistic/freightCalculate
$body = [
"endCountryCode" => "US",
"startCountryCode" => "CN",
"products" => [
'vid' => $vid,
'quantity' => 1
],
];
$request = $this->client->request(
'POST', 'https://developers.cjdropshipping.com/api2.0/v1/logistic/freightCalculate',
[
'headers' => [
'CJ-Access-Token' => $this->auth_via_cj(), // unnecessary, no auth required. Ignore this header
],
'body' => json_encode( $body )
],
);
I've also tried using 'json' => $body instead of the 'body' parameter.
I am getting 400 Bad Request error.
Any ideas?
Try to give body like this.
"json" => json_encode($body)
I spent so many hours on this to just realise that products is actually expecting array of objects. I've been sending just a one-dimensional array and that was causing the 'Bad Request' error.
In order to fix this, just encapsulate 'vid' and 'quantity' into an array and voila!
You don't need to convert data in json format, Guzzle take care of that.
Also you can use post() method of Guzzle library to achieve same result of request. Here is exaple...
$client = new Client();
$params['headers'] = ['Content-Type' => 'application/json'];
$params['json'] = array("endCountryCode" => "US", "startCountryCode" => "CN", "products" => array("vid" => $vid, "quantity" => 1));
$response = $client->post('https://developers.cjdropshipping.com/api2.0/v1/logistic/freightCalculate', $params);

Sending json as html over wordpress api

i am trying to send json as raw (html) to wordpress api but its not working for me
$json = json_encode([
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
]);
$query = http_build_query([
'title' => $titleFile,
'content' => json_decode(stripslashes($json))
]);
$username = 'admin';
$password = '123456';
$url = "http://mysite/wp-json/wp/v2/posts/?$query";
$cmd = "curl --request POST --user $username:$password \"$url\"";
$requestWP = shell_exec($cmd);
print_r($requestWP);
die();
its working fine, but the post is made with json in the body format if I don't decode and if I decode the post is empty as its an array how can I send the value of the key in raw (html) not Json?
wordpress api endpoint https://developer.wordpress.org/rest-api/reference/posts/
output with json_decode()
stdClass Object ( [key1] => value1 [key2] => value2 [key3] => value3 )
I dont think its the best way to do this but worked for me
$json = json_encode([
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
]);
$data = json_decode($json, TRUE);
$data = implode(',', $data);
$data = str_replace(',', '', $data);
$query = http_build_query([
'title' => $titleFile,
'content' => $data
]);
$username = 'admin';
$password = '123456';
$url = "http://mysite/wp-json/wp/v2/posts/?$query";
$cmd = "curl --request POST --user $username:$password \"$url\"";
$requestWP = shell_exec($cmd);
print_r($requestWP);
die();
OK, so there are a few different things in your code that should be addressed. I'm not a Wordpress expert, so I will give you some general guidelines:
Making a POST request
There are a few different ways of sending a HTTP request from PHP, either using native functions or libraries, but using shell_exec to call CURL is definitely not the best. If you want to use CURL, I'd suggest the CURL library. Otherwise try a library like Guzzle
Payload goes in the body
When sending a POST request, the correct way to send the data (and the way Wordpress is expecting it) is to send it in the body of the request, not as part of the query string as you seem to be doing.
Payload should be a JSON string
You should do something similar to the following snippet to generate the body of your request if you are going to use CURL:
$data = json_encode([
'title' => 'my title',
'content' => [
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
]
]);
$data will then have the JSON string:
"{"title":"my title","content":{"key1":"value1","key2":"value2","key3":"value3"}}"
Guzzle for instance, will take care of that for you.
Authentication
The endpoint you are trying to hit is protected and using login/password won't work unless you are using the Basic Authentication plugin.
Putting it all together
This is all you should need if you decide to use Guzzle and Basic Authentication:
$client = new GuzzleHttp\Client();
$client->post('http://mysite/wp-json/wp/v2/posts/', [
'auth' => [$username, $password],
'json' => $data
]);

Perl - LWP API Post

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!
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]);
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"
);

sending array via query string in guzzle

Guzzle client creates by default from this code
$client->get('https://example.com/{?a}', array('a' => array('c','d')));
this url
https://example.com/?a=c,d
What is the best practice to send array in query string in RESTful application? The question is, how can I determine on the server side whether c,d is a string or an array? Isn't it better to send arrays using square brackets, e.g. a[]=c&a[]=d? How can I set Guzzle to use square brackets? Or it is better to use JSON encoded variables? On the server side I'm using Tonic.
Working Solution:
$vars = array('state[]' => array('Assigned','New'), 'per_page' => $perPage, 'page' => $pageNumber);
$query = http_build_query($vars, null, '&');
$string = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $query); // state[]=Assigned&state[]=New
$client = new Client([follow instruction to initialize your client ....]);
$response = $client->request('GET', $uri, ['query' => $string]);
Now you have same name parameters in your request.
Dung.
Source: http_build_query with same name parameters
It seems the answer is here.
I wanted to do something like ?status[]=first&status[]=second
You can do this in Guzzle like shown in the link above:
$client = new Client('http://test.com/api');
$request = $client->get('/resource');
$query = $request->getQuery();
$query->set('status', array('first', 'second'));
Guzzle has a helper function you can use called build_query(). This uses PHP's http_build_query().
Here's an example of how to use it:
$params = [
'a[]' => [
'c',
'd'
],
'page' => 1
];
$query = \GuzzleHttp\Psr7\build_query($params);
$response = $client->request('GET', 'https://example.com/', [
'query' => $query
]);
I'm not 100% sure this quite answers the question. But I found the question while looking for how to construct complex queries using Guzzle and none of the answers here were the solution I ended up using. I'm adding it here in case it's ever useful for any other devs.
Using Guzzle 6, you can do this type of request:
$endPoint = "https://example.com";
$queryParams = [
'a' => [
[
"b" => "c"
]
]
];
$options = [
'debug' => true, // so you can see what the request looks like
'query' => $queryParams
];
$client->request('GET', $endPoint, $options);
As a real world example, query params like this:
$queryParams = [
'filters' => [
[
"field" => "status",
"value" => "open",
"operator" => "equal"
],
[
"field" => "total",
"operator" => "greater_than",
"value" => 50
],
],
'limit' => 500,
'start' => 7
];
produce a url like this:
https://example.com?filters=[{"field":"status","operator":"equal","value":"open"},{"field":"total","operator":"less_than","value":50}]&limit=500&start=7
The point being that the query key of the $options array, seems very powerful. I'd recommend having a play with that before going down the route of writing complex regular expressions.
$query = array('x' => array(
'a',
'b',
'c'
));
$query_string = http_build_query($query, null, '&'); //build query string
$query_string = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '[]=', $query_string); //x[]=a&x[]=b
$response = $guzzle->client->get($path, array('query' => $query_string)); //Make guzzle request
return json_decode($response->getBody()->getContents()); //Return JSON decoded array
This is how you can process x with array of values in guzzle, tested with version 6 or later

Categories