Getting JSON response WITH cURL - php

I don't know what I'm doing wrong but I've already lost a couple days struggling with this.
Here is my cURL request from the command line:
curl -i -H "Accept: text/html" http://laravel.project/api/v1/users/4
This returns:
HTTP/1.1 200 OK
Server: nginx/1.6.2
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache
Date: Sun, 29 Mar 2015 10:33:36 GMT
Set-Cookie: laravel_session=eyJpdiI6ImNPTkZIYVJZSVRKaHBOZTR3SWh0dHc9PSIsInZhbHVlIjoiblpZYVJlN2dBY1ljejNIYUQycXpsNXRWd1I5a3JSRG8wSWdDOWlHVTMrYUcrdDBNVmVuZUNkOGtJb2M4bXFpTFF3cUdoTFZOVXBWXC82Q1luSGd5bjJBPT0iLCJtYWMiOiI0ZTEwOWQxMmVhMzY2NjI1Yzc1MTBmZmRmYjUyOGQwNDlhYzRjOTNiM2FiOWIyN2E1YjA0OTM4YTUxZmNmMzMzIn0%3D; expires=Sun, 29-Mar-2015 12:33:36 GMT; Max-Age=7200; path=/; httponly
{
"data":{
"id":4,
"name":"Helena",
"email":"hh#gmail.com",
"created_at":"2015-03-26 21:13:16",
"updated_at":"2015-03-26 21:13:16"
}
}
So everything looks fine: the Content-type is correctly set and response is in JSON.
But now watch what happens if I consume the API with curl in PHP:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $final_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
$result = curl_exec($ch);
return json_decode($result);
I get this response:
{#165
+"data": {#167
+"id": 4
+"name": "Helena"
+"email": "hh#gmail.com"
+"created_at": "2015-03-26 21:13:16"
+"updated_at": "2015-03-26 21:13:16"
}
}
And, if I return the $result without json_decode, I get this:
"{
"data":{
"id":4,
"name":"Helena",
"email":"hh#gmail.com",
"created_at":"2015-03-26 21:13:16",
"updated_at":"2015-03-26 21:13:16"
}
}"
The correct response but inside quotes. I've read in PHP docs that curl_opt_returntranfer returns the result as a string but I can't be the only person on the planet that just wants to get the JSON.
This is my ApiController class:
class ApiController extends Controller {
// Base controller for API Controllers
protected $statusCode = 200;
protected function respond($data)
{
return Response::json([
'data' => $data,
]);
}
protected function respondNotFound($message = 'No data found')
{
return Response::json([
'error' => [
'message' => $message,
'status_code' => $this->getStatusCode(),
]
]);
}
}
This is my UserController:
class UserController extends ApiController {
public function show($user)
{
if ($user == null)
return $this->setStatusCode(404)->respondNotFound('User not found');
return $this->respond($user);
}
}

And if I return the $result without json_decode i get this: The correct response but inside quotes
nope, what makes you think that? i guess the problem is how you are printing it, you are most likely printing it with var_export($result) or var_dump($result) or echo json_encode($result); which is adding the quotes. if you just want the json, just echo it with echo $result;, no extra processing, just echo the string as-is, it's already json.

I think this will solve your problem:
curl -i -H "Accept: text/html" http://laravel.project/api/v1/users/4 | tr -d '"'

$response = (string)$result;
$resp_arr = explode("<!DOCTYPE",$response);
$obj = json_decode(trim($japi_arr[0]));
if(isset($obj[0]))
{
$rsp_id = $obj[0]->id;
$rsp_name = $obj[0]->name;

Related

CURL Object of type \'System.DBNull\' cannot be converted to type \'System.String

Im trying to recieve some response from a website/server, and all i get in return is:
System.ArgumentException','Object of type \'System.DBNull\' cannot be converted to type \'System.String
my PHP code:
$url = 'website';
$fields = array('searchstring' => urlencode('solkrem'), 'menuID' => urlencode(0), 'genses' => urlencode('20170201178577A2F54'), 'removeimages' => urlencode(false));
function httpPost($url, $data)
{
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
echo "<br><br>";
$result = httpPost($url,$fields);
var_dump($result);
I also do know, when im trying it trough requestmaker.com with the data and url, i get the response i wanted...
Am i not encoding my fields right, or what could be the cause?
EDIT: some info from requestmaker.com :
Request Headers Sent:
POST xxxxx HTTP/1.1
Host: xxx.com
Accept: */*
Content-Type: text/html
Content-Length: 75
request header recieved:
HTTP/1.1 200 OK
Date: Thu, 02 Feb 2017 14:03:20 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Cache-Control: private
Expires: Thu, 02 Feb 2017 14:03:19 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 58300
EDIT 3:
I found out, even that the site is asking me to add the details with the & seperator, it wont work if its like this, and it will produce same error:
But if it looks like this, without the & seperator, it works. I dont know how its sent, cause its backend PHP on the test page.
Also, if i dont send any fields, it will give same output as the error i have.
update 4:
FRom their website, i saw they are sending it like:
'searchstring=solkrem\r\nmenuID=0\r\ngenses=20170201178577A2F54\r\nremoveimages=false
would that do something? hmm.
I think your error is with the "removeimages" parameter...
You have:
'removeimages' => urlencode(false)
And it should probably be:
'removeimages' => urlencode('false')
URL encoding a Boolean value of false will not pass anything in the query string and create a null value on the other end.

Curl exec returns more than JSON. How do I extract just the JSON data?

My curl exec response returns this:
string(151937) "HTTP/1.1 200 OK Access-Control-Allow-Headers: Content-Type, Accept-Tenant, Authorization Access-Control-Allow-Methods: POST,GET,PUT,PATCH,OPTIONS Access-Control-Allow-Origin: * Cache-Control: private Content-Type: application/json; charset=utf-8 Date: Mon, 28 Sep 2015 08:35:33 GMT Server: Microsoft-IIS/7.5 Warning: Unsupported Authentication Scheme X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Content-Length: 151475 Connection: keep-alive {"ShortResultText":"SE19","Restaurants":[{"Id":50371,"Name":"Mahjestics Caribbean Cuisine","Address":"247 Gypsy Road","Postcode":"SE27 9QY","City":"London","CuisineTypes":[{"Id":76,"Name":"Caribbean","SeoName":null},{"Id":97,"Name":"African","SeoName":null}],"Url":"http://majestic-caribbean-cuisine-west-norwood.just- ...
But the JSON starts here at "{ ShortResultText"..:
{
"ShortResultText": "SE19",
"Restaurants": [
{
"Id": 50371,
"Name": "Mahjestics Caribbean Cuisine",
"Address": "247 Gypsy Road",
"Postcode": "SE27 9QY",
"City": "London",
"CuisineTypes": [
{
"Id": 76,
"Name": "Caribbean",
"SeoName": null
},
{
"Id": 97,
"Name": "African",
"SeoName": null
}
"Url": "http://majestic-caribbean-cuisine-west-norwood.test.co.uk",
"IsOpenNow": true,
"IsSponsored": false,
"IsNew": false,
"IsTemporarilyOffline": false,
"ReasonWhyTemporarilyOffline": "",
"UniqueName": "majestic-caribbean-cuisine-west-norwood",
"IsCloseBy": false,
"IsHalal": true,
"DefaultDisplayRank": 1,
"IsOpenNowForDelivery": true,
"IsOpenNowForCollection": true,
"RatingStars": 4.71,
"Logo": [
{
"StandardResolutionURL": "http://d30v2pzvrfyzpo.cloudfront.net/uk/images/restaurants/50371.gif"
}
],
"Deals": [],
"NumberOfRatings": 7
I need to get JUST the JSON data from my curl response and I'm not sure the best way to go about it? The curl response header might vary in length depending on the "ShortResultText" value from POST as this is a variable.
Then I'll be able to get the data in an array and loop through it.
Curl code:
$url = "http://api-interview.test.com/restaurants?q=se19";
$ch = curl_init();
$api_headers = array(
'Content-Type: text/plain; charset=utf-8',
'Accept-Tenant: uk',
'Accept-Language: en-GB',
'Authorization: Basic VGVjaFRlc3RBUEk6dXNlcjI=',
'Host: api-interview.test.com'
);
//print_r($api_headers);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $api_headers);
// echo "<pre>";
// $data = curl_exec($ch);
// echo "</pre>";
echo "<pre>";
$data = curl_exec($ch);
echo "</pre>";
//just testing here
// $json = json_encode($data, true);
// $json1 = json_decode($json, true);
// var_dump($json1);
//print $json1['restaurants'];
//$json = json_encode($data, true);
// foreach($json['restaurants'] as $value) {
// echo $value->postcode;
// }
curl_close($ch);
You only have to set CURLOPT_HEADER to false.
Try this:
$json1 = json_decode($json, true);
foreach($json1['Restaurants'] as $key => $val){
print_r($val); // You will get here the ID, Name ....
echo 'ID: ' $val['Id'] . 'Name: ' . $val['Name']; . 'Rating Stars: ' . $val['RatingStars']..
//If you want to go deeper and get the CuisineTypes just do below
foreach($val['CuisineTypes'] as $key2 => $val2) {
print_r($val2); //This is the cuisine types
}
}
Or you can just manipulate your array:
$newData = [];
foreach($json1['Restaurants'] as $key => $val)
{
$newData[] = ['Name' => $val['Name'], 'CusineTypes' => $val['CuisineTypes'], 'RatingStars' => $val['RatingStars']];
}
print_r($newData);

How to get cURL JSON array only in ZF2

I am using ZF2 and curl for connecting with one of my clients API.
For example I am getting the response as
HTTP/1.1 200 OK Access-Control-Allow-Origin: * Content-Type: application/json; charset=ISO-8859-1 Date: Thu, 04 Dec 2014 06:12:13 GMT Server: Google Frontend Cache-Control: private Alternate-Protocol: 80:quic,p=0.02,80:quic,p=0.02 Connection: close { "time": "06:12:13 AM", "milliseconds_since_epoch": 1417673533861, "date": "12-04-2014" }
I need the JSON array only.
My code is:
$data = "";
$adapter = new Curl();
$client = new Client();
$client->setAdapter($adapter);
$client->setUri('http://date.jsontest.com');
$client->setMethod('POST');
$adapter->setCurlOption(CURLOPT_POST, 1);
$adapter->setCurlOption(CURLOPT_POSTFIELDS, $data);
$adapter->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
$adapter->setCurlOption(CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Authorization: Bearer $token'
));
$response = $client->send();
return new ViewModel(array(
'response' => $response,
));
The send() method of the Zend HTTP Client returns a new Response instance after successfully complete the request. You're directly passing that response instance to your view, not the content (body) inside the response.
Try this:
// Your current code..
$response = $client->send();
$viewModel = new ViewModel();
if($response->getStatusCode() === 200) {
$obj = json_decode($response->getBody(), true);
if($obj === null) {
// Json cannot be decoded.. handle it..
}
$viewModel->setVariable('response', $obj);
} else {
// Status code is not 200, handle it..
}
// And return the model
return $viewModel;
Not perfect but it should work..

PHP curl_exec returns both HTTP/1.1 100 Continue and HTTP/1.1 200 OK separated by space

I'm calling a service from PHP using cURL, like this:
$response = curl_exec($ch);
and the request/response headers look something like this:
Request:
POST /item/save HTTP/1.1
Host: services.mydomain.com
Accept: */*
Content-Length: 429
Expect: 100-continue
Content-Type: multipart/form-data
Response:
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Fri, 06 Jul 2012 08:37:01 GMT
Server: Apache
Vary: Accept-Encoding,User-Agent
Content-Length: 256
Content-Type: application/json; charset=utf-8
followed by the body (json encoded data).
The problem is that the common thing is to split headers and body in the response by the first empty line encountered, except in this case, the empty line is after the 100 Continue and therefore everything else gets pushed into the body–and that is not valid json anymore :-)
So my question is this: What's the common way to deal with this?
I have 3 options lined up:
Specify that curl should not expect 100-continue? (How?)
Specify that curl should only send back the headers of the last response? (How?)
Manually check for 100 Continue headers and disregard them and their following empty line? (In that case, are there other similar things that could happen, that I should manually check for?)
Unless I'm missing something obvious, I'm sure people have stumbled upon this and solved it many times!
I will opt for #1.
You can force curl to send empty "Expect" header, by adding:
curl_setopt($ch, CURLOPT_HTTPHEADER,array("Expect:"));
to your code
If you want check it manually, you should define your own header callback and maybe write callback (look for CURLOPT_HEADERFUNCTION and CURLOPT_WRITEFUNCTION in curl_setopt doc), which has simply to ignore all "HTTP/1.1 100 Continue" headers.
Here's another method that uses the approach I described in the comment by parsing the response into header vs. body using CURLINFO_HEADER_SIZE:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://test/curl_test.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
// sets multipart/form-data content-type
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'field1' => 'foo',
'field2' => 'bar'
));
$data = curl_exec($ch);
// if you want the headers sent by CURL
$sentHeaders = curl_getinfo($ch, CURLINFO_HEADER_OUT);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$header = substr($data, 0, $headerSize);
$body = substr($data, $headerSize);
echo "==Sent Headers==\n$sentHeaders\n==End Sent Headers==\n";
echo "==Response Headers==\n$headers\n==End Response Headers==\n";
echo "==Response Body==\n$body\n==End Body==";
I've tested this, and it results in the following output:
==Sent Headers==
POST /curl_test.php HTTP/1.1
Host: test
Accept: */*
Content-Length: 242
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------
d86ac263ce1b
==End Sent Headers==
==Response Headers==
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Fri, 06 Jul 2012 14:21:53 GMT
Server: Apache/2.4.2 (Win32) PHP/5.4.4
X-Powered-By: PHP/5.4.4
Content-Length: 112
Content-Type: text/plain
==End Response Headers==
==Response Body==
**FORM DATA**
array(2) {
["field1"]=>
string(3) "foo"
["field2"]=>
string(3) "bar"
}
**END FORM DATA**
==End Body==
i had the same problem but this solution does note work for me, finaly i have found this methode and all its fine:
we have to prepare data post fields before sending them:
function curl_custom_postfields($curl, array $assoc = array(), array $files = array()) {
/**
* For safe multipart POST request for PHP5.3 ~ PHP 5.4.
* #param resource $ch cURL resource
* #param array $assoc "name => value"
* #param array $files "name => path"
* #return bool
*/
// invalid characters for "name" and "filename"
static $disallow = array("\0", "\"", "\r", "\n");
// build normal parameters
foreach ($assoc as $key => $value) {
$key = str_replace($disallow, "_", $key);
$body[] = implode("\r\n", array(
"Content-Disposition: form-data; name=\"{$key}\"",
"",
filter_var($value),
));
}
// build file parameters
foreach ($files as $key => $value) {
switch (true) {
case false === $value = realpath(filter_var($value)):
case !is_file($value):
case !is_readable($value):
continue; // or return false, throw new InvalidArgumentException
}
$data = file_get_contents($value);
$value = call_user_func("end", explode(DIRECTORY_SEPARATOR, $value));
$key = str_replace($disallow, "_", $key);
$value = str_replace($disallow, "_", $value);
$body[] = implode("\r\n", array(
"Content-Disposition: form-data; name=\"{$key}\"; filename=\"{$value}\"",
"Content-Type: application/octet-stream",
"",
$data,
));
}
// generate safe boundary
do {
$boundary = "---------------------" . md5(mt_rand() . microtime());
} while (preg_grep("/{$boundary}/", $body));
// add boundary for each parameters
array_walk($body, function (&$part) use ($boundary) {
$part = "--{$boundary}\r\n{$part}";
});
// add final boundary
$body[] = "--{$boundary}--";
$body[] = "";
// set options
return #curl_setopt_array($curl, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => implode("\r\n", $body),
CURLOPT_HTTPHEADER => array(
"Expect: 100-continue",
"Content-Type: multipart/form-data; boundary={$boundary}", // change Content-Type
),
));}
you have to prepare two arrays:
1- post field with normal data: (name1 = val1, name2 = val2, ...)
2- post field with file data: (name_file 1, path_file1, name_file2 = path_file2, ..)
and finaly call this function before executing curl like this.
$r = curl_custom_postfields($curl, $post, $postfields_files);
I have come across this with 100s and 302s etc it's annoying but sometimes needed (gdata calls etc) so i would say leave curl returning all headers and extract the body a little differently.
I handle it like this (can't find my actual code but you'll get the idea):
$response = curl_exec($ch);
$headers = array();
$body = array();
foreach(explode("\n\n", $response) as $frag){
if(preg_match('/^HTTP\/[0-9\.]+ [0-9]+/', $frag)){
$headers[] = $frag;
}else{
$body[] = $frag;
}
}
echo implode("\n\n", $headers);
echo implode("\n\n", $body);
I begrudge the longwinded hackish method (would prefer it if curl marked the body content somehow) but it has worked well over the years. let us know how you get on.

Crocodoc api not working with php

I am trying to use Crocodoc api with the following code to get the status.
$croco = new Crocodoc();
$uuids = "786e072b-981c-4d2a-8e80-80e215f1f7c2";
echo "\n\nchecking status of : ", $uuids;
$status = $croco->getStatus($uuids);
echo "\n\nstatus is : ", $status;
class Crocodoc {
public $api_key = 'HPUd6LZXg5174TAENbvBcx30';
public $api_url = 'https://crocodoc.com/api/v2/';
public function getStatus($uuids){
$url = $this->api_url.'document/status';
$token = $this->api_key;
$dataStr = '?token='.$token.'&uuids='.$uuids;
// this is a GET request
$output = $this->doCurlGet($url, $dataStr);
return $output;
}
}
I don't get the status and no error. What is wrong or it does not work in evaluation mode. Right now I am using it local with XAMPP, can that be a problem?
What doCurlGet does?
Because the request (and response) is fine:
HTTP/1.1 200 OK
Server: nginx/1.2.0
Date: Thu, 24 May 2012 10:11:27 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
[
{
"uuid": "786e072b-981c-4d2a-8e80-80e215f1f7c2",
"viewable": true,
"status": "DONE"
}
]
You might try with a real curl, like:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "/* generated url to crocodoc */");
$data = curl_exec($ch);
curl_close($ch);
Or directly:
$data = file_get_contents('/* generated url to crocodoc */');
Edit:
Just tried this code, and it works fine:
$croco = new Crocodoc();
$uuids = "786e072b-981c-4d2a-8e80-80e215f1f7c2";
$status = $croco->getStatus($uuids);
var_dump($status);
class Crocodoc {
public $api_key = 'HPUd6LZXg5174TAENbvBcx30';
public $api_url = 'https://crocodoc.com/api/v2/';
public function getStatus($uuids){
$url = $this->api_url.'document/status';
$token = $this->api_key;
$dataStr = '?token='.$token.'&uuids='.$uuids;
// this is a GET request
return file_get_contents($url.$dataStr);
}
}

Categories