I'm trying to send a GET request to an API using PHP stream_context_create and file_get_contents.
I need to add API keys to the headers of my request, I'm storing these in an array so I easily edit them later and use them in multiple functions. What is a good way to include these arrays as headers?
In this case the key of the array would be the header keys and the value of the array the value of the header.
Some code to explain the problem
<?php
$api = array(
"X-Api-Id" => "id",
"X-Api-Key" => "key",
"X-Api-Secret" => "secret"
);
$options = array(
"http" => array(
"header" => "Content-type: application/x-www-form-urlencoded\r\n", // here I need to add the $api array
"method" => "GET"
)
);
return file_get_contents("example.com", FALSE, stream_context_create($options));
?>
Simply add the info to the header.
<?php
$api = [
'X-Api-Id' => 'id',
'X-Api-Key' => 'key',
'X-Api-Secret' => 'secret',
];
$headerData['Content-type'] = 'application/x-www-form-urlencoded';
$headerData = array_merge($headerData, $api);
array_walk($headerData, static function(&$v, $k) { $v = $k.': '.$v; });
$options = array(
'http' => [
'header' => implode("\n", $headerData),
'method' => 'GET'
]
);
return file_get_contents('example.com', FALSE, stream_context_create($options));
?>
To encode the data you can use http_build_query().
To add it to the header options you should be able to do something like:
$options = array(
"http" =>array(
'method' => 'POST', // GET in your case(?)
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($api)
)
);
Related
I need to do a POST call to save data on a server. The server requires for some items a JSON-Encoded List. However when I do the post call and I look at $result, the data of the "JSON-Encoded List" is not saved and the items are null. The POST call is however successful.
$items = json_encode((array(
"name" => $_GET['title'],
"sub_type" => $subtype_fd,
"calories" => intval($_GET['calories']),
"carbohydrate" => floatval($_GET['carbohydrate']),
"cholesterol" => floatval($_GET['cholesterol']),
"fiber" => floatval($_GET['fiber']),
"protein" => floatval($_GET['protein']),
"saturated_fat" => floatval($_GET['saturated_fat']),
"unsaturated_fat" => floatval($_GET['unsaturated_fat']),
"sodium" => floatval($_GET['sodium']),
"sugar" => floatval($_GET['sugar'])
)));
var_dump($items);
$data = array('note' => $_GET['title'], 'sub_type' => $subtype_bld, 'items' => $items);
$options = array(
'http' => array(
"header" => "Content-Type: application/x-www-form-urlencoded\r\nAuthorization: Bearer {$_COOKIE['access_token']}\r\n",
'method' => 'POST',
'content' => $data
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
The Info from API
Host: jawbone.com
Accept: application/json
Content-Type: multipart/form-data
The content context option should be a string, you're providing an array. It's supposed to be a string in URL-encoded format. The http_build_str function will convert an associative array into this format. So use:
'content' => http_build_str($data)
Where did I make a mistake? My PHP-script:
<?php
// Set username and password
$lgname = "someUsername";
$lgpassword = "somePassword";
// First login to receive 1) token, 2) sessionid and 3) cookieprefix
$parameters = array('action' => 'login', 'lgname' => "$lgname", 'lgpassword' => "$lgpassword", 'format' => 'json');
options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($parameters)
),
);
$context = stream_context_create($options);
$result = file_get_contents("http://en.wikipedia.org/w/api.php", false, $context);
// Echo out the answer from MediaWiki-API
echo "$result";
// Put the needed parts of the answer into variables and echo them out
$array = json_decode($result,true);
$token = $array["login"]["token"];
$sessionid = $array["login"]["sessionid"];
$cookieprefix = $array["login"]["cookieprefix"];
echo "</BR>token: $token, sessionid: $sessionid, cookieprefix: $cookieprefix</BR>";
// Second login to 1) post token and 2) send sessionID within the header
$parameters = array('action' => 'login', 'lgname' => "$lgname", 'lgpassword' => "$lgpassword", 'lgtoken' => "$token", 'format' => 'json');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n" .
"Cookie: " . $cookieprefix . "_session = $sessionid\r\n",
'method' => 'POST',
'content' => http_build_query($parameters)
),
);
$context = stream_context_create($options);
$result = file_get_contents("http://en.wikipedia.org/w/api.php", false, $context);
// Echo out result
echo "$result";
?>
What I get as an answer to my second POST-request is (exactly the same as to my first POST-request) that I need a token (even though I posted the token and even the sessionID in my second POST-request):
{"login": {
"result":"NeedToken",
"token":"82b3f2e1f1aa702ca6ceae473bb16bde",
"cookieprefix":"dewiki",
"sessionid":"531143bd7425722bf1be88e520dea6d5"}
}
The mistake is in using file_get_contents() in the first place. Use a PHP library for the MediaWiki web API, instead.
If you really want to do things yourself, ask a token from meta=tokens.
I want to update a video using google api v3 and i get the error 400 Bad Request.
This is my code.
$url = 'https://www.googleapis.com/youtube/v3/videos?part=snippet&videoId='.$_GET['videoId'].'&access_token='.Session::get('access_token');
$params = array(
"id"=> $_GET['videoId'],
"kind"=> "youtube#video",
'snippet' => array(
"title"=> "I'm being changed.",
"categoryId"=> "10",
"tags"=> array(
"humanities",
"Harpham",
"BYU"
),
'description' => 'test!'
)
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'PUT',
'content' => http_build_query($params),
),
);
$context = stream_context_create($options);
$result = json_decode(file_get_contents($url, false, $context));
I think since you don't set all parameters inside snippet, that's giving an error. What you can do is, first getting that video with videos->list, then updating the field you are interested in and sending back the update request with the whole object back.
Here's an example also utilizing php client library: https://github.com/youtube/api-samples/blob/master/php/update_video.php
I have a simple xmlhttprequest with AJAX and want to rebuild this with PHP.
var data = {};
var payload = {
"flags" : true,
"codes" : true,
"units" : true
};
data.payload = JSON.stringify(payload);
$.ajax({
type : 'POST',
url : 'http://httpbin.org/post',
data : data,
success : function(response) {
var arr = JSON.stringify(response);
document.getElementById('placeholder').innerHTML = arr;
}
});
This works fine!
Now my Version with PHP:
$data = array(
'payload' => array(
'flags' => true,
'codes' => true,
'units' => true
)
);
$options = array(
"http" => array(
"method" => "POST",
"header" => "Content-Type: application/json\r\n",
"content" => json_encode($data)
)
);
$url = "http://httpbin.org/post";
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
var_dump($response);
When I compare the results there is a difference in the structure.
Ajax looks like this:
{"form":{"payload":"{\"flags\":\"true\",
and PHP looks like this:
{"form": {},..."data": "{\"payload\":{\"flags\":\"true\",
Why is in PHP the "form" empty?
I've tried it an extra Array "form", but when I look at the result there is a second "form" in the string.
You use improper way of building POST data.
Try this:
$payload = array(
'flags' => true,
'codes' => true,
'units' => true
);
$data = array(
'payload' => json_encode($payload)
);
$options = array(
"http" => array(
"method" => "POST",
"header" => "Content-Type: application/x-www-form-urlencoded\r\n",
"content" => http_build_query($data)
)
);
Explanation
In your JS code POST data is an object containing one key-value pair {"payload": json} where json is json-encoded string representing payload object. This POST data object finally results (in $.ajax implementation) in a url-encoded string which look like this: payload=%7B%22flags%22%3Atrue%2C%22codes%22%3Atrue%2C%22units%22%3Atrue%7D.
Described process is exactly reproduced by my php code.
Have you tried to trigger json_last_error() right after encoding your array ?
$options = array(
"http" => array(
"method" => "POST",
"header" => "Content-Type: application/json\r\n",
"content" => json_encode($data)
)
);
$error = json_last_error();
echo $error;
In case of a silent json error, maybe it could give you a clue.
Let us know :)
I am troubleshooting some problems with POSTing to a remote site, specifically the remote host never returns any data (empty string).
Before I try to troubleshoot anything else, I want to make sure the calling code is actually correct. The code is:
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: application/xml",
'timeout' => 60.0,
'ignore_errors' => true, # return body even if HTTP status != 200
'content' => $send_xml
)));
$response = trim(file_get_contents($this->bulk_service_url, false, $context));
All my questions belong to the "header" option and it's values, and how to correctly format it and write it. The PHP documentation, discussion below it and even stackoverflow research yield very inconsistent results.
1) do I have to include the Content-Length header, and if not, will PHP calculate it correctly? The documentation does not include it, but I've seen many people include it manually, is it then respected or overwritten by PHP?
2) do I have to pass the header option as a string, or an associative array? Manual says string, majority pass it as a string, but this comment says that if PHP was compiled with --with-curlwrappers option, you have to pass it as an array. This is very inconsistent behavior.
3) when passing as a string, do I have to include terminating \r\n characters? Especially when specifying just one header. Manual does not provide such an example, first comment on manual page does include it, second one does not, again, no clear rule on how to specify this. Does PHP automatically handle both cases?
The server is using PHP 5.3.
You should really store your headers within code as an array and finalize the preparation just prior to sending the request...
function prepareHeaders($headers) {
$flattened = array();
foreach ($headers as $key => $header) {
if (is_int($key)) {
$flattened[] = $header;
} else {
$flattened[] = $key.': '.$header;
}
}
return implode("\r\n", $flattened);
}
$headers = array(
'Content-Type' => 'application/xml',
'ContentLength' => $dl,
);
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => prepareHeaders($headers),
'timeout' => 60.0,
'ignore_errors' => true,
'content' => $send_xml
)));
$response = trim(file_get_contents($url, FALSE, $context));
Preparing context try to add:
ContentLength: {here_calculated_length} in 'header' key preceded with \r\n
"\r\n" at the end of 'header' key.
So it should look like:
$dl = strlen($send_xml);//YOUR_DATA_LENGTH
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: application/xml\r\nContentLength: $dl\r\n",
'timeout' => 60.0,
'ignore_errors' => true, # return body even if HTTP status != 200
'content' => $send_xml
)));
Just a little improvement of the suggestion by #doublejosh, in case it helps someone:
(use of array notation and one-liner lambda function)
$headers = [
'Content-Type' => 'application/xml',
'Content-Length' => strlen($send_xml)
];
$context = stream_context_create(['http' => [
'method' => "POST",
'header' => array_map(function ($h, $v) {return "$h: $v";}, array_keys($headers), $headers),
'timeout' => 60.0,
'ignore_errors'=> true,
'content' => $send_xml
]
]);