Curl JSON request in PHP - php

I am trying to send the following cURL request in PHP:
$ curl -H 'Content-Type: application/json' -d '{"username":"a", "password":"b","msisdn":"447000000001","webhook":"http://example.com/"}' https://ms.4url.eu/lookup
Which should return:
198 bytes text/html; charset=UTF-8
{
"id": "ea26d0b2-b839-46b9-9138-50cc791bab47",
"msisdn": "447825001771",
"status": "Success",
"networkCode": "23471",
"countryName": "UK",
"countryCode": "GBR",
"network": "O2",
"networkType": "GSM",
"ported": "No"
}
I have tried to implement the code to send a request using cURL like so:
<?php
$data = array('{"username":"a", "password":"b", "msisdn":"447123121234", "webhook":"http://1f89e4a8.ngrok.io"}');
$data_string = json_encode($data);
$ch = curl_init('http://ms.4url.eu/lookup');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
?>
Using this method nothing seems to be happening I cannot see the JSON data being sent to ms.4url.eu/lookup, and when I try to echo $result I get no data echoed out?
Any help is much appreciated.
A Successful curl request is showing:
POST /testDir/getPost.php HTTP/1.1
host: 1f89e4a8.ngrok.io
accept: application/json
content-type: application/json
content-length: 198
Connection: close
X-Forwarded-For: 5.44.233.221
{"id":"ea26d0b2-b839-46b9-9138-50cc791bab47","msisdn":"447123121234","status":"Success","networkCode":"23471","countryName":"UK","countryCode":"GBR","network":"O2","networkType":"GSM","ported":"No"}
The post request from my PHP code is showing:
GET /testDir/curlPost.php HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393
Accept-Encoding: gzip, deflate
Host: 1f89e4a8.ngrok.io
X-Forwarded-For: 92.11.143.199
Overall I would like to send the curl request from sendRequest.php and receive the Post for the webhook to getPost.php possibly using:
$entityBody = file_get_contents('php://input');
if ($entityBody != null){
echo $entityBody;
}
at the Minute I am using the getPost.php to send the HTTP 200 OK so ms.4url.eu stops sending requests 302 Found.

I think it is how you are building the json string...
You start by defining $data as an array of strings, and then json_encode it. But it is already in json format anyway (from a quick eyeball check).
The json_encode (and _decode) are meant to work with an associative array for your data.
Or just send the data string you are building, just check that it is in correct json format first.
<?php
// build an associative array
$data["username"]="a";
$data["password"]="b";
$data["msisdn"]="447123121234";
$data["webhook"]="http://1f89e4a8.ngrok.io";
// turn it into json formatted string
$json_data=json_encode($data);
print_r($data);
print($json_data);
?>
This gives you something like
Array
(
[username] => a
[password] => b
[msisdn] => 447123121234
[webhook] => http://1f89e4a8.ngrok.io
)
{"username":"a","password":"b","msisdn":"447123121234","webhook":"http:\/\/1f89e4a8.ngrok.io"}

Try to get like raw post data like below
<?php
$fp = fopen('php://input', 'r');
$rawData = stream_get_contents($fp);
echo "<pre>";
print_r($rawData);
echo "</pre>";

If you send only the json string via curl you have to use, on the destination page, php://input to retrieve the data, because there is not key => value and the variables $_POST and $_REQUEST don't intersect the request.
And, of course, check wich data are you sending in post. It seems incorrect to json_encode an array with an element "string"..
If you want to retrieve the request from the $_POST or $_REQUEST variable it's better if you put your json data into a key using the http_build_query function like following:
$data_string = json_encode($data);
$ch = curl_init('http://ms.4url.eu/lookup');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array('data' => $data_string)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);

Related

PHP file_get_contents returns with a 400 Error

My problem is pretty straightforward, but I cannot for the life of me figure out what is wrong. I've done something similar with another API, but this just hates me.
Basically, I'm trying to get information from https://owapi.net/api/v3/u/Xvs-1176/blob and use the JSON result to get basic information on the user. But whenever I try to use file_get_contents, it just returns
Warning: file_get_contents(https://owapi.net/api/v3/u/Xvs-1176/blob): failed to open stream: HTTP request failed! HTTP/1.1 400 BAD REQUEST in Z:\DevProjects\Client Work\Overwatch Boost\dashboard.php on line
So I don't know what's wrong, exactly. My code can be seen here:
$apiBaseURL = "https://owapi.net/api/v3/u";
$apiUserInfo = $gUsername;
$apiFullURL = $apiBaseURL.'/'.$apiUserInfo.'/blob';
$apiGetFile = file_get_contents($apiFullURL);
Any help would be largely appreciated. Thank you!
You need to set user agent for file_get_contents like this, and you can check it with this code. Refer to this for set user agent for file_get_contents.
<?php
$options = array('http' => array('user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0'));
$context = stream_context_create($options);
$response = file_get_contents('https://owapi.net/api/v3/u/Xvs-1176/blob', false, $context);
print_r($response);
That's what page is sending: "Hi! To prevent abuse of this service, it is required that you customize your user agent".
You can customize it using curl like that:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://owapi.net/api/v3/u/Xvs-1176/blob");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
$output = curl_exec($ch);
$output = json_decode($output);
if(curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
var_dump($output);
}
curl_close($ch);
If you do curl -v https://owapi.net/api/v3/u/Xvs-1176/blob you will get a response and you will see what headers cURL includes by default. Namely:
> Host: owapi.net
> User-Agent: curl/7.47.0
> Accept: */*
So then the question is, which one does owapi care about? Well, you can stop cURL from sending the default headers like so:
curl -H "Accept:" -H "User-Agent:" -H "Host:" https://owapi.net/api/v3/u/Xvs-1176/blob
... and you will indeed get a 400 response. Experimentally, here's what you get back if you leave off the "Host" or "User-Agent" headers:
{"_request": {"api_ver": 3, "route": "/api/v3/u/Xvs-1176/blob"}, "error": 400, "msg": "Hi! To prevent abuse of this service, it is required that you customize your user agent."}
You actually don't need the "Accept" header, as it turns out. See the PHP docs on how to send headers along with file_get_contents.

Why is my POST with cURL not returning JSON correctly?

In PHP, I'm trying to retrieve the url for a specific page in DocuSign that constantly refreshes. The POST to retrieve this url is in the form:
POST http://demo.docusign.net/restapi/{apiVersion}/accounts/{accountId}/envelopes/{envelopeId}/views/recipient
This should return a json file in the form:
{
"url": "example.example.com"
}
However, I am extremely new to using PHP and POST methods and don't believe I'm doing this correctly. The API explorer for this method in particular is here. I am using cURL methods to make this request. Here is my code ($recipient,$account_id,$access_token are found accurately within another file):
$url = "http://demo.docusign.net/restapi/v2/accounts/$account_id
/envelopes/$envelope_id/views/recipient";
$body = array("returnUrl" => "http://www.docusign.com/devcenter",
"authenticationMethod" => "None",
"email" => "$recipient",
"userName" => "$recipient");
$body_string = json_encode($body);
$header = array(
'Accept: application/json',
'Content-Type: application/json',
'Content-Length: '.strlen($body_string),
);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body_string);
$json_response = curl_exec($curl);
$response = json_decode($json_response, true);
var_dump($response);
I am able to get the correct return on the API explorer, but not when making the request with PHP. I believe this is due to the fact that I am not incorporating the $header or $body correctly, but at this point I am just not sure.
ADDED: This is the raw output for the request when correctly running the method on the API Explorer:
Accept: application/json
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,fa;q=0.6,sv;q=0.4
Cache-Control: no-cache
Origin: https://apiexplorer.docusign.com
Referer: https://apiexplorer.docusign.com/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Authorization: Bearer fGehcK7fkRvFguyu/7NGh01UUFs=
Content-Length:
Content-Type: application/json
This is the JSON request being formed in my code:
{
"returnUrl":"http:\/\/www.docusign.com\/devcenter",
"authenticationMethod":"Password",
"email":"example#example.com",
"userName":"example#example.com",
"clientUserId":"4c6228f4-fcfe-47f9-bee1-c9d5e6ab6a41",
"userId":"example#example.com"
}
You are not hitting a valid DocuSign URL in your cURL code. Right now you are sending requests to:
http://demo.docusign.net/apiVersion/v2/accounts/{accountId}/envelopes/{envelopeId}/views/recipient
Instead of "apiVersion" it should be "restApi" like this:
http://demo.docusign.net/restapi/v2/accounts/{accountId}/envelopes/{envelopeId}/views/recipient
We can't send post fields, because we want to send JSON, not pretend to be a form (the merits of an API which accepts POST requests with data in form-format is an interesting debate). Instead, we create the correct JSON data, set that as the body of the POST request, and also set the headers correctly so that the server that receives this request will understand what we sent:
$data = array("name" => "Hagrid", "age" => "36");
$data_string = json_encode($data);
$ch = curl_init('http://api.local/rest/users');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
All these settings are pretty well explained on the curl_setopt() page, but basically the idea is to set the request to be a POST request, set the json-encoded data to be the body, and then set the correct headers to describe that post body. The CURLOPT_RETURNTRANSFER is purely so that the response from the remote server gets placed in $result rather than echoed. If you're sending JSON data with PHP, I hope this might help!
I know this question was asked more than 3 years ago, but this may help someone who finds this question because they are having the same problem. I do not see a cURL option that will decode the response in your code. I have found that I need to use the cURL option CURLOPT_ENCODING like this: curl_setopt($ch,CURLOPT_ENCODING,""); According to the PHP manual online, it says, 'CURLOPT_ENCODING - The contents of the "Accept-Encoding: " header. This enables decoding of the response. Supported encodings are "identity", "deflate", and "gzip". If an empty string, "", is set, a header containing all supported encoding types is sent.' You can find this option at https://www.php.net/manual/en/function.curl-setopt.php. I hope this helps save someone from having a headache.

Can't make Curl POST request from web app

A server I am working on appears to be denying outbound HTTP requests. The reason I think this is because I've tried both Guzzle and curl requests to the API.
The API lives on the same domain as the web server (this is temporary at clients request). I can make requests to the API server via Postman (Chrome plugin), but when I run that same request on the server, it doesn't return anything.
Here are the headers from the 'Postman' request:
POST /api2/user/session HTTP/1.1
Host: example.com
Connection: keep-alive
Content-Length: 49
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: PHPSESSID=d9ad79c4c0822fc5c86f4d8799307f1b; _ga=GA1.2.1674422587.1425409444
Post data:
token=a559d5bba5a9e9517d5c3ed7aeb62db6&user=30972
This works. It returns the data. But when I call the same endpoint from within my web app, I get nothing.
$data = urlencode("token=a559d5bba5a9e9517d5c3ed7aeb62db6&user=30972");
$ch = curl_init('http://example.com/api2/user/session');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($data))
);
$result = curl_exec($ch);
What I don't understand is I can run the following, and it returns the content:
print file_get_contents("http://www.google.com");
When I var_dump the $_POST fields on the endpoint user/session it returns the array of postdata using Postman but $_POST fields are blank when sending via the web app. Even before it makes any request to the database, the post fields should be set right?
Via SSH this also works:
curl -F token=a559d5bba5a9e9517d5c3ed7aeb62db6 -F user=30972 http://example.com/api2/user/session
As suggested in comments I've tried:
var_dump(function_exists('curl_version'));
// bool(true)
I can't figure out what's going on.
Edit: This works ... but I don't want to use sockets. Must be a curl issue.
$fp = fsockopen('example.com', 80);
$vars = array(
'token' => 'a559d5bba5a9e9517d5c3ed7aeb62db6',
'user' => '30972'
);
$content = http_build_query($vars);
fwrite($fp, "POST /api2/user/session HTTP/1.1\r\n");
fwrite($fp, "Host: example.com\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: ".strlen($content)."\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");
fwrite($fp, $content);
header('Content-type: text/plain');
while (!feof($fp)) {
echo fgets($fp, 1024);
}
Edit:
curl_error() also returns no error.
To better understand the differences between the PHP code and cURL, I created a RequestBin instance and tried both on it. They yielded drastically different results:
It seemed like the POST data from the PHP script yielded an incorrect result for what was sent. This can be fixed by using a built-in PHP function http_build_query.
It will yield a more apt result:
This can be caused by a session lock... If you use curl to access the same server, the same session is used. While the script is running, the session is locked by default, this means that the current request has to finish before another is handled for the same session. This would explain a timeout of the request in curl, as your first request is not completed and another is made...
Using session_write_close() before the curl_exec will unlock the session and correct the problem.
It turns out I needed to use http_build_query.
$vars = array(
'token' => 'a559d5bba5a9e9517d5c3ed7aeb62db6',
'user' => '30972'
);
$content = http_build_query($vars);
$ch = curl_init('http://example.com/api2/user/session');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($content))
);
$result = curl_exec($ch);

Custom curl CURLOPT_HTTPHEADER with result [Authentication-API-Key] => 123456

A http connection requires a HTTP POST request with a custom header object Authentication-API-Key
With CURL it's automatically converted to [HTTP_AUTHENTICATION_API_KEY] => 12345
Cannot figure out why
A simplle extract from a php class for testing is
Please help me out, how to get a $_SERVER result with [Authentication-API-Key] => 123456
<?php
$contentType = 'text/xml';
$method = 'POST';
$auth = '';
$header1 = 'Authentication-API-Key: 12345';
$charset= 'ISO-8859-1';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/test/returnurl.php");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array('Content-type: ' .
$contentType . '; charset=' . $charset,
$header1));
curl_exec($ch);
?>
<?php
//http://localhost/test/returnurl.php
Print_r($_SERVER,true)
?>
output:
Array
(
[HTTP_HOST] => localhost
[HTTP_ACCEPT] => */*
[CONTENT_TYPE] => text/xml; charset=ISO-8859-1
[HTTP_AUTHENTICATION_API_KEY] => 12345
...
)
If I run your code, I get the message that $header2 is undefined, so I think you need to fix that.
If I remove $header2, this is the output:
GET /test/returnurl.php HTTP/1.1
Host: localhost
Accept: */*
Content-type: text/xml; charset=ISO-8859-1
Authentication-API-Key: 12345
So that seems to be okay. What is your output? Note that currently the request is send using GET, not POST.
EDIT: I created the script /test/returnurl.php that simply dumps the $_SERVER array, now I see what you mean. The fact that it ends up like that on the receiving end does not mean that you haven't set the header correctly, so the service that you're using should be receiving it as intended.
That's how _SERVER works; it does not give you the HTTP header keys verbatim.
It is not CURL doing this. Examine the actual HTTP request and you'll see that your header is fine.
Another example is $_SERVER['CONTENT_TYPE'], which gives you the value of the Content-Type HTTP header.
There is no problem here.
A script I am using passes an array like array("Content-type: image/png").
Perhaps by putting it in an array you prevent it from breaking into an array at the :
I am new to cURL so I haven't even been able to test this theory yet..

PHP Curl - Get data generated with AJAX

I want to get data generated by an AJAX request. In this page http://www.fipe.org.br/web/index.asp?p=51&aspx=/web/indices/veiculos/default.aspx there are some html selects. When the user click on the first one (Marca), the second one is filled. I want to get this data.
This is my code:
<?php
$curl = curl_init();
$postData = array('ddlAnoValor' => 0,
'ddlMarca' => 1,
'ddlModelo' => 0,
'ddlTabelaReferencia' => 123,
'txtCodFipe' => '');
$result = null;
$httpResponse = null;
curl_setopt($curl, CURLOPT_URL, 'http://www.fipe.org.br/web/indices/veiculos/default.aspx?p=51');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_REFERER, 'http://www.fipe.org.br/web/indices/veiculos/introducao.aspx');
curl_setopt($curl, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
$result = curl_exec($curl);
$httpResponse = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if($httpResponse == '404') {
throw new exception('This page doesn\'t exists.');
}
echo $result;
curl_close($curl);
?>
Page request header
Host: www.fipe.org.br
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.13) Gecko/20100916 Iceweasel/3.5.13 (like Firefox/3.5.13)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
X-MicrosoftAjax: Delta=true
Cache-Control: no-cache, no-cache
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://www.fipe.org.br/web/indices/veiculos/default.aspx?p=51
Content-Length: 9415
Cookie: __utma=106123796.1351303072.1287075522.1287075522.1287075522.1; __utmb=106123796; __utmc=106123796; __utmz=106123796.1287075522.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none); ASPSESSIONIDAADQDQRD=EKBEJHEDKCIOAAHNFFMLGMKO
Pragma: no-cache
But I always get the form as result. I've tried to set cookie but cookies.txt file is always empty. I don't know if this cookie is required. cookies.txt has 777 permission. What am I doing wrong? Thank you.
If you look at the post variables (use the net panel on firebug to do this) when using the form on the site, you will see that it contains some variables which you are not submitting with your PHP code, such as _VIEWSTATE and _EVENTVALIDATION.
I guess that these relate to the session established by the browser when displaying the form, and I further guess that if these and their related variables are not present then the server will return the full page HTML including the form.
You could try to simulate these variables, but I suspect you are doomed to fail.
Ideally you should contact the site and ask them how you can retrieve the information you are looking for. Perhaps they have a webservice which exposes it?

Categories