Can anyone help with the following
I'm trying to make a JSON request to a RESTful API. The code below is kindly shared by Wes Furlong
The code seems to be able to decode to JSON fine but sends as a URL encoded string
<?php
function rest_helper($url, $params = null, $verb = 'GET', $format = 'json')
{
$cparams = array(
'http' => array(
'method' => $verb,
'ignore_errors' => true
)
);
if ($params !== null) {
$params = http_build_query($params);
if ($verb == 'POST') {
$cparams['http']['content'] = $params;
} else {
$url .= '?' . $params;
}
}
$context = stream_context_create($cparams);
$fp = fopen($url, 'rb', false, $context);
if (!$fp) {
$res = false;
} else {
// If you're trying to troubleshoot problems, try uncommenting the
// next two lines; it will show you the HTTP response headers across
// all the redirects:
// $meta = stream_get_meta_data($fp);
// var_dump($meta['wrapper_data']);
$res = stream_get_contents($fp);
}
if ($res === false) {
throw new Exception("$verb $url failed: $php_errormsg");
}
switch ($format) {
case 'json':
$r = json_decode($res);
if ($r === null) {
throw new Exception("failed to decode $res as json");
}
return $r;
case 'xml':
$r = simplexml_load_string($res);
if ($r === null) {
throw new Exception("failed to decode $res as xml");
}
return $r;
}
return $res;
}
I need to be able to:
Add a content type of application/json
Convert params to JSON
Can't use curl in this environment
The main thing is the content type -- currently defaults to urlencoded
Any tips or ideas appreciated - Thanks
Latest attempt
function restHelper($url, $params = null, $verb = 'GET', $format = 'json'){
$cparams = array(
'http' => array(
'method' => $verb,
'ignore_errors' => true,
'header' =>"Content-type: application/json \r\n"
)
);
if ($params !== 'None') {
$jparams = json_encode($params);
if ($verb == 'POST') {
$cparams['http']['content'] = $jparams;
} elseif ($verb =='PUT') {
$cparams['http']['content'] = $jparams;
} else {
$params = http_build_query($params);
$url .= '?' . $params;
}
}
Still not working -- API tests fine from REST IDE Seems to be from how the content type is working for JSON
In the end found a way of including CURL in scriptcase.
Here is what worked (prototype)
(Thanks Lorna Jane http://www.lornajane.net/posts/2011/posting-json-data-with-php-curl)
Thanks everyone that looked at this
$service_url = 'http://dev.eventplus.co.nz/api/logon';
$ch = curl_init($service_url);
$data = '[
{
"Header": {
"Username": "testapi#teamprema.co.nz",
"SessionId": "123"
}
},
{
"Config": {}
},
{
"Params": {"Query": {"Password": "test12345"}}
}
]';
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data))
);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
$response = curl_exec($ch);
if ($response === false) {
$info = curl_getinfo($ch);
curl_close($ch);
die('error occured during curl exec. Additioanl info: ' . var_export($info));
}
curl_close($ch);
print $response;
Related
Ik got the following code to retrieve some json by API:
public function get_json($jsonurl, $ttl = 3600) {
$cache_file = $this->cache_dir . DIRECTORY_SEPARATOR . md5($jsonurl);
$function = __FUNCTION__;
if (file_exists($cache_file) && filemtime($cache_file) < time() - $ttl) {
unlink($cache_file);
}
if (!file_exists($cache_file)) {
file_put_contents($this->cache_dir . DIRECTORY_SEPARATOR . 'cache.log', $jsonurl . ': ' . $cache_file . "\n", FILE_APPEND);
try{
$response = $this->fetchUrl($jsonurl);
} catch(Exception $ex){
return true;
}
file_put_contents($cache_file, $response);
}
elseif(file_exists($cache_file)){
$response = file_get_contents($cache_file);
}
$json_output = json_decode($response, true);
if(empty($json_output)){
unlink($cache_file);
}
return $json_output;
}
private function fetchUrl($url) {
$curl = curl_init($url);
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true
));
$response = curl_exec($curl);
if (!$response) {
$exception = new Exception(curl_error($curl) ?: 'Empty response', curl_errno($curl));
curl_close($curl);
throw $exception;
}
curl_close($curl);
return $response;
}
Locally it works fine but on the live server i retrieve NULL. When i put the jsonurl in the browser it returns valid json. So maybe it has something to do with the fetchUrl function and the curl_setopt_array?
Please help me with this going crazy!
I have a cURL call to this services/data/v28.0/query/?q=SELECT Id,Name,LastModifiedDate FROM Territory and the response looks like:
{
"totalSize": 6911,
"done": false,
"nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-2000",
"records": [ ... ]
}
That means complete set of records will have 6911 items but on first request just the first 2000 are return, now if I change a bit the cURL call into this /services/data/v28.0/query/01g8000002eI8dMAAS-2000 I will get the next 2000 items for the first 6911 and so on.
I should call the cURL recursive until done = true or nextRecordsUrl will be NULL or doesn't exists anymore on the response, how? I need some advice or pseudo-code that illustrate me how to achieve this since I am a bit stucked.
This shows the complete set of recursive calls I should perform (this could be dynamic so hard code won't work):
call:
/services/data/v28.0/query/?q=SELECT Id,Name,LastModifiedDate FROM Territory
response:
{
"totalSize": 6911,
"done": false,
"nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-2000",
"records": [ ... ]
}
call:
/services/data/v28.0/query/01g8000002eI8dMAAS-2000
response:
{
"totalSize": 6911,
"done": false,
"nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-4000",
"records": [ ... ]
}
call:
/services/data/v28.0/query/01g8000002eI8dMAAS-4000
response:
{
"totalSize": 6911,
"done": false,
"nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-6000",
"records": [ ... ]
}
call:
/services/data/v28.0/query/01g8000002eI8dMAAS-6000
response:
{
"totalSize": 6911,
"done": true,
"records": [ ... ]
}
UPDATE
I have figured out, more or less, how to achieve this but now the my problem turns in how to merge recursive the values from each response. See code below:
$soqlQuery2 = "SELECT Id,Name,LastModifiedDate FROM Territory";
$soqlUrl2 = $instanceUrl.'/services/data/v28.0/query/?q='.urlencode($soqlQuery2);
$curl = curl_init($soqlUrl2);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));
$jsonResponse = curl_exec($curl);
curl_close($curl);
$soqlObj2 = json_decode($jsonResponse, true);
$this->performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $soqlObj2['nextRecordsUrl']);
Above in $soqlObj2['done'] and $soqlObj2['nextRecordsUrl'] I will have the values I need for the second and recursive calls. So, I built this function:
public function performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $nextRecordsUrl)
{
if (isset($nextRecordsUrl) && $nextRecordsUrl !== null && $nextRecordsUrl !== "") {
$nextRecordsUrlSOQLQuery = $instanceUrl.$nextRecordsUrl;
$curl = curl_init($nextRecordsUrlSOQLQuery);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));
$jsonResponse = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status != 200) {
$respObj['error'] = "Error: call to token URL $tokenUrl failed with status $status, response $jsonResponse, curl_error ".curl_error(
$curl
).", curl_errno ".curl_errno($curl);
return $respObj;
}
curl_close($curl);
$nextRecordsUrlObj = json_decode($jsonResponse, true);
while ($nextRecordsUrlObj['done'] !== true) {
$this->performPaginateSOQLQuery($veevaToken, $instanceUrl ,$tokenUrl, $nextRecordsUrlObj['nextRecordsUrl']);
}
return $nextRecordsUrlObj;
}
}
But I need to merge the whole $soqlObj2 with $nextRecordsUrlObj from each iteration on performPaginateSOQLQuery() call, how? Any help?
UPDATE 2: Losing values on 1st iteration
I've updated my code to this:
public function performPaginateSOQLQuery(
$veevaToken,
$instanceUrl,
$tokenUrl,
&$nextRecordsUrl,
&$dataToSave = array()
) {
if (isset($nextRecordsUrl) && $nextRecordsUrl !== null && $nextRecordsUrl !== "") {
$nextRecordsUrlSOQLQuery = $instanceUrl.$nextRecordsUrl;
$curl = curl_init($nextRecordsUrlSOQLQuery);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));
$jsonResponse = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status != 200) {
$respObj['error'] = "Error: call to token URL $tokenUrl failed with status $status, response $jsonResponse, curl_error ".curl_error(
$curl
).", curl_errno ".curl_errno($curl);
return $respObj;
}
curl_close($curl);
$nextRecordsUrlObj = json_decode($jsonResponse, true);
echo $nextRecordsUrlObj['nextRecordsUrl'] . "\n";
print_r($nextRecordsUrlObj);
$dataToSave[] = $nextRecordsUrlObj;
$i = 0;
while ($nextRecordsUrlObj['done'] !== true) {
echo "time ".$i;
$i++;
$this->performPaginateSOQLQuery(
$veevaToken,
$instanceUrl,
$tokenUrl,
$nextRecordsUrlObj['nextRecordsUrl'],
$dataToSave
);
}
return array('url' => $nextRecordsUrlObj, 'data' => $dataToSave);
}
}
But on iteration time 1 I am getting this error:
[Symfony\Component\Debug\Exception\ContextErrorException]
Notice: Undefined index: nextRecordsUrl
Why is that?
You can use a while loop with a boolean variable.
Once the response you get is the last one (done property is true) change the value of that boolean variable and the loop should stop.
<?php
//Assuming $response contains the response you're getting
//and that it's JSON-encoded.
$keepRequesting = true;
while($keepRequesting){
//Your curl code over here
// ...
$response = json_decode($response);
if($response->done == true) {
$keepRequesting = false;
}
}
Regarding your update:
While I don't think you should use recursive methods for this problem,
just add the data you want to "save" as a reference to the function and use array_merge. Something like that:
public function performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $nextRecordsUrl, &$dataToSave = array()) { //1 new parameters.
//More code here...
$nextRecordsUrlObj = json_decode($jsonResponse, true);
$dataToSave[] = $nextRecordsUrlObj;
while ($nextRecordsUrlObj['done'] !== true) {
$this->performPaginateSOQLQuery($veevaToken, $instanceUrl ,$tokenUrl, $nextRecordsUrlObj['nextRecordsUrl'], $dataToSave);
}
return array('url' => $nextRecordsUrlObj, 'data' => $dataToSave);
The problem is that you should return it, otherwise it will get lost.
You'll have to change the function a bit so it would return the URL and the data you want.
Maybe this post would help you:
php recursion global variable?
I am trying to but the prints from this php code into seperate html div's so I can customize them with css. I got a css file made and it shows but everything is printed out into one div called body class=" hasGoogleVoiceExt".
<?php
class Bot {
public $botHost = '127.0.0.1';
public $botPort = 8087;
public $botId = NULL;
public $token = NULL;
public function __construct($botHost = '127.0.0.1', $botPort = 8087, $botId = NULL) {
$this->botHost = $botHost;
$this->botPort = $botPort;
if ($botId == NULL) {
$botId = $this->DefaultBot();
}
$this->botId = $botId;
}
public function DefaultBot() {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => 'http://'.$this->botHost.':'.$this->botPort.'/api/v1/botId',
CURLOPT_RETURNTRANSFER => 1
));
$data = curl_exec($ch);
curl_close($ch);
$json = json_decode($data, TRUE);
return $json['defaultBotId'];
}
public function Login($username, $password) {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => 'http://'.$this->botHost.':'.$this->botPort.'/api/v1/bot/login',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POSTFIELDS => json_encode(array('username' => $username, 'password' => $password, 'botId' => $this->botId)),
CURLOPT_HTTPHEADER => array('Content-Type: application/json')
));
$data = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200) return NULL;
$this->token = json_decode($data, TRUE)['token'];
}
public function GetInstances() {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => 'http://'.$this->botHost.':'.$this->botPort.'/api/v1/bot/instances',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_HTTPHEADER => array('Authorization: bearer '.$this->token)
));
$data = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200) return NULL;
$json = json_decode($data, TRUE);
return $json;
}
public function GetInstanceStatus($instanceId) {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => 'http://'.$this->botHost.':'.$this->botPort.'/api/v1/bot/i/'.$instanceId.'/status',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_HTTPHEADER => array('Authorization: bearer '.$this->token)
));
$data = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200) return NULL;
$json = json_decode($data, TRUE);
return $json;
}
}
$bot = new Bot('127.0.0.1', 8087);
$bot->Login('admin', 'foobar');
$instances = $bot->GetInstances();
for ($i = 0; $i < count($instances); $i++) {
$info = $bot->GetInstanceStatus($instances[$i]['uuid']);
if ($info['currentTrack'] != NULL && $info['playing']) {
printf("%s is playing %s by %s\n", $instances[$i]['nick'], $info['currentTrack']['title'], $info['currentTrack']['artist']);
} else {
printf("%s is not playing anything right now\n", $instances[$i]['nick']);
}
echo '<link href="botcss/styles.css" rel="stylesheet" type="text/css" />';
}
I'm currently testing it out here http://theunlighted.com/nowplaying.php
First things first: Your <link [...]> needs to be output before the for() loop.
Secondly, to output divs in a way (that I think you're meaning to do) is simple:
for($i = 0; $i < 123; $i++) {
echo '<div class="foo foo_'.$i.'">';
// do other output here.
echo '</div>';
}
I have been running unit tests using Selenium Server 2.32 and Firefox 24.4 (on CentOS 5) -- just updated Firefox, and moved to Selenium 2.41, and now Selenium won't open a URL. I assume something has changed in either Firefox or Selenium that I need to adapt to, but can't figure out what.
I created as clean a test program as I could, which follows. It works (opens google.com in a Firefox window) using Selenium 2.32, but not in Selenium 2.41. As best I can tell from looking at the Selenium output it is getting a 404 error, but no idea way.
Any help gratefully appreciated !
Test Case in php:
$seleniumUrl = "http://mydomain.com:4444/wd/hub";
$desired_capabilities = array('browserName' => 'firefox');
$results = mycurl(
$seleniumUrl,
'POST',
'/session',
array('desiredCapabilities' => $desired_capabilities),
array(CURLOPT_FOLLOWLOCATION => true));
$seleniumUrl = $results['info']['url'];
$goToUrl = "http://google.com";
mycurl($seleniumUrl, 'POST', '/url', array('url' => $goToUrl));
Here is the source to mycurl function:
function mycurl(
$seleniumUrl,
$http_method,
$command,
$params = null,
$extra_opts = array()) {
if ($params && is_array($params) && $http_method !== 'POST') {
throw new Exception(sprintf(
'The http method called for %s is %s but it has to be POST' .
' if you want to pass the JSON params %s',
$command,
$http_method,
json_encode($params)));
}
$url = sprintf('%s%s', $seleniumUrl, $command);
if ($params && (is_int($params) || is_string($params))) {
$url .= '/' . $params;
}
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt(
$curl,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json;charset=UTF-8',
'Accept: application/json'));
if ($http_method === 'POST') {
curl_setopt($curl, CURLOPT_POST, true);
if ($params && is_array($params)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
}
} else if ($http_method == 'DELETE') {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
}
foreach ($extra_opts as $option => $value) {
curl_setopt($curl, $option, $value);
}
$raw_results = trim(curl_exec($curl));
$info = curl_getinfo($curl);
if ($error = curl_error($curl)) {
$msg = sprintf(
'Curl error thrown for http %s to %s',
$http_method,
$url);
if ($params && is_array($params)) {
$msg .= sprintf(' with params: %s', json_encode($params));
}
throw new Exception($msg . "\n\n" . $error);
}
curl_close($curl);
$results = json_decode($raw_results, true);
$value = null;
if (is_array($results) && array_key_exists('value', $results)) {
$value = $results['value'];
}
$message = null;
if (is_array($value) && array_key_exists('message', $value)) {
$message = $value['message'];
}
return array('value' => $value, 'info' => $info);
}
Hi I am sending the push notification using below code. I've a problem in this code.
<?php
class GCMPushMessage
{
var $url = 'http://android.googleapis.com/gcm/send';
var $serverApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
var $devices = array();
function setDevices($deviceIds)
{
if (is_array($deviceIds)) {
$this->devices = $deviceIds;
} else {
$this->devices = array(
$deviceIds
);
}
}
function send($message)
{
if (!is_array($this->devices) || count($this->devices) == 0) {
$this->error("No devices set");
}
if (strlen($this->serverApiKey) < 8) {
$this->error("Server API Key not set");
}
$fields = array(
'registration_ids' => $this->devices,
'data' => array(
"msg" => $message
)
);
$headers = array(
'Authorization: key=' . $this->serverApiKey,
'Content-Type: application/json'
);
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
// Execute post
$result = curl_exec($ch);
$this->StripResponseFromGCM(json_decode($result));
// Close connection
curl_close($ch);
return $result;
}
function error($msg)
{
echo "Android send notification failed with error:";
echo "\t" . $msg;
exit(1);
}
function StripResponseFromGCM($response)
{
//canonicalID's are the
if ($response->failure == 0 && $response->canonical_ids == 0)
return;
for ($i = 0; $i < sizeof($response->results); $i++) {
if (isset($response->results[$i]->registration_id)) { //if new registrationID is sent as canonicalID
//update this registrationID in the database
} else if ($response->results[$i]->error == "Unavailable") {
// user with index == $i is unavailable
} else if ($response->results[$i]->error == "InvalidRegistration") {
// user with index == $i has InvalidRegistration ID
} else if ($response->results[$i]->error == "NotRegistered") {
// user with index == $i is not registered
}
}
}
}
$msg = array(
'data' => array(
'msg' => 'just a simple message'
)
);
require_once('connection.php');
$sql = mysql_query("select gcmid from gcmid");
$new_array = mysql_fetch_array($sql);
print_r($new_array);
$obj = new GCMPushMessage();
$obj->setDevices($new_array);
$obj->send($msg);
?>
If i put a single id in setDevices method then it is working fine but if i
fetching the gcm ids from database and passing it to method setDevices then the code is not working.It suppose to send push notification to devices but it is not working.