Accessing object returned from GraphQL using curl - php

I have returned data using GraphQL / curl that looks like this:
{
"data" : {
"publisher" : {
"contracts" : {
"totalCount" : 11,
"count" : 1,
"resultList" : [
I want to get the resultList array and keep getting an error 'Warning: Attempt to read property "data" on string' when trying to do $result->data to move into the first object. What am I doing wrong?
My variable from the curl request is $result.
Update: I HAVE TRIED DECODING AND THE RETURNED DATA IS OF TYPE INT? How?
function getData($data_String){
$endpoint = "https://programs.api.cj.com/query";
$authToken = "pass";
$qry = '{"query":"{ publisher { contracts(publisherId: \"xxxxxxx\", limit: 1, filters: {advertiserId: \"'.$advertiser_id.'\"}) { totalCount count resultList { startTime endTime status advertiserId programTerms { id name specialTerms { name body } isDefault actionTerms { id actionTracker { id name description type } lockingMethod { type durationInDays } performanceIncentives { threshold { type value } reward { type commissionType value } currency } commissions { rank situation { id name } itemList { id name } promotionalProperties { id name } rate { type value currency } } } } } } } }","variables":null}';
$headers = array();
$headers[] = 'Content-Type: application/json';
$headers[] = 'Authorization: Bearer '.$authToken;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $qry);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
$data = json_decode($result);
return $data;
}

First, be sure to check if the result is a valid json.
Then use json_decode to get an object
$result = json_decode($result);
if (is_object($result)) {
if (!empty($result->data->publisher->contracts->resultList)) {
$resultList = $result->data->publisher->contracts->resultList;
}
} else {
// Log or something
error_log("json decode return: " . print_r($result, true))
}

Related

Trying to access array offset on value of type null & isset problem in API call loop - 504 Gateway Time-out server

I am building cron job with API calls in loop for DB entries and Have performance issues.
Particularly in this part:
if (!empty($sudCode) && !empty($sudBroj) && isset($sudCode) && isset($sudBroj)) {
// echo $sudCode . "<br>";
// echo $sudBroj . "<br>";
$epredmet = ePredmeti($sudCode, $sudBroj);
// print_r($epredmet);
// echo "<br>";
if (isset($epredmet["data"]["prvi"]["lastUpdateTime"])) {
$lastUpdateTime = $epredmet["data"]["prvi"]["lastUpdateTime"];
$dateTime = str_replace("T", " ", $lastUpdateTime);
echo $nas . " - " . $dateTime . "<br>";
}
}
on line:
if (isset($epredmet["data"]["prvi"]["lastUpdateTime"])) {
I have few Databases and on one when this line is reached sever goes to 504 Gateway Time-out after 2 minutes.
Hosting company said that it goes in timeout because Apache web server waits for PHP parser to process data, what ever that means.
What is strange, is if I leave out that if check i script finishes and I get results but with Notice: Trying to access array offset on value of type null in
because I expect that $epredmet after API call looks like this:
- array(1) { ["data"]=> array(1) { ["prvi"]=> NULL } } // case not found
- array(1) { ["data"]=> array(1) { ["prvi"]=> array(1) { ["lastUpdateTime"]=> NULL } } } // case found but lastUpdateTime is not set, null
- array(1) { ["data"]=> array(1) { ["prvi"]=> array(1) { ["lastUpdateTime"]=> string(23) "2021-06-14T22:51:22.171" } } } // case found and lastUpdateTime is set
So what I need to do is filter out just last case where lastUpdateTime is set, and all that I read is suggesting to solve it with isset but that breaks my script for some reason.
PHP V 7.4
Please advise.
Im attaching full script in case someone notices problem somewhere else:
function eSudovi()
{
$endpoint = "xxx";
$qry = '{"query":"query{sudovi {id, sudNaziv}}"}';
$headers = array();
$headers[] = 'Content-Type: application/json';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $qry);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
}
$eSudovi = eSudovi()["data"]["sudovi"];
function findSudCode($val, $eSudovi)
{
foreach ($eSudovi as $key => $value) {
if ($value["sudNaziv"] == $val) {
return $value["id"];
}
}
}
function ePredmeti($sud, $pred)
{
$endpoint = "xxx";
$qry = '{"query":"query{ prvi:predmet(sud: ' . $sud . ', oznakaBroj: \"' . $pred . '\") {lastUpdateTime}}"}';
$headers = array();
$headers[] = 'Content-Type: application/json';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $qry);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
}
$results = mysqli_query($con, "
SELECT DISTINCT predf_nas_br, predf_odv, predf_SUD, predf_SUDBROJ
FROM PREDMETIFView
WHERE predf_SUD <> '' AND predf_SUDBROJ <> '' AND predf_SUDBROJ NOT LIKE '% %'
UNION ALL
SELECT DISTINCT predp_nas_br, predp_odv, predp_SUD, predp_SUDBROJ
FROM PREDMETIPView
WHERE predp_SUD <> '' AND predp_SUDBROJ <> '' AND predp_SUDBROJ NOT LIKE '% %'
;");
while ($row = $results->fetch_assoc()) {
foreach ($row as $key => $value) {
if ($key == "predf_nas_br") {
$nas = $value;
}
if ($key == "predf_SUD") {
$sud = trim($value);
if (!empty($sud) && isset($sud)) {
$sudCode = findSudCode($sud, $eSudovi);
}
};
if ($key == "predf_SUDBROJ") {
$sudBroj = trim($value);
};
if (!empty($sudCode) && !empty($sudBroj) && isset($sudCode) && isset($sudBroj)) {
// echo $sudCode . "<br>";
// echo $sudBroj . "<br>";
$epredmet = ePredmeti($sudCode, $sudBroj);
print_r($epredmet);
echo "<br>";
if (isset($epredmet["data"]["prvi"]["lastUpdateTime"])) {
$lastUpdateTime = $epredmet["data"]["prvi"]["lastUpdateTime"];
$dateTime = str_replace("T", " ", $lastUpdateTime);
echo $nas . " - " . $dateTime . "<br>";
}
}
}
};
// preg_match('/\s/', $sudBroj)
Edit:
I also tried this:
if (isset($epredmet["data"]["prvi"]["lastUpdateTime"]) && !empty($epredmet["data"]["prvi"]["lastUpdateTime"])) {
and this:
if (isset($epredmet["data"]["prvi"]) && !empty($epredmet["data"]["prvi"])) {
if (isset($epredmet["data"]["prvi"]["lastUpdateTime"]) && !empty($epredmet["data"]["prvi"]["lastUpdateTime"])) {
Same thing, it hangs, but without it all it work with erros.
Something like this would do to reuse the curl handle (note: haven't had time to test it, but you'll get the idea).
class ePredmeti{
public $epredmet;
private $curl,$ini_opt;
function __construct(){
$endpoint ='xxx';
$headers = ['Content-Type: application/json'];
$timeout = 30;
$this->curl= curl_init();
$this->ini_opt=[
CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_TIMEOUT => $timeout
];
}
public function _exec($sud, $pred){
$start=microtime(true);
$this->epredmet = null;
$query_opt=[
CURLOPT_POSTFIELDS=>
'{"query":"query{ prvi:predmet(sud: ' . $sud . ', oznakaBroj: \"' . $pred . '\") {lastUpdateTime}}"}'
];
curl_reset($this->curl);
curl_setopt_array($this->curl, $this->ini_opt);
curl_setopt_array($this->curl, $query_opt);
$ret = curl_exec($ch);
if (!curl_errno($this->curl)){
if(curl_getinfo($this->curl, CURLINFO_HTTP_CODE)!==200){
echo 'HTTP error: '.$http_code.'<br>';
}
else{
$this->epredmet = json_decode($ret,true);
}
}
else{
echo curl_error($this->curl).'<br>';
}
echo 'Took: '.(microtime(true)-$start).'<br>';
}
}
before the while() put something like:
$mycurl = new ePredmeti();
and instead of $epredmet = ePredmeti($sudCode, $sudBroj); use
$mycurl->_exec($sudCode, $sudBroj);
Finally, instead of if (isset($epredmet["data"]["prvi"]["lastUpdateTime"])) { you can use
if( isset($mycurl->epredmet["data"]["prvi"]["lastUpdateTime"]) ) {
The last one works because the class returns null on any error and isset() checks if a variable exists and is not null.

Update Values in Database after getting success message using curl

i am getting below message after passing values in url with curl:
{"AddManifestDetails":[{"AuthKey":"Valid","ReturnMessage":"successful",}]
If ReturnMessage is successful , than i want to update values in database, i tried below code :
<?php
$data =
array (
'OrderNo' => $order_id,
'AirWayBillNO' => $resultc[0]['awb'],
);
$url = "http://114.143.206.69:803/StandardForwardStagingService.svc/AddManifestDetails";
$data = json_encode($data);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$curl_response = curl_exec($curl);
curl_close($curl);
echo $curl_response ."\n";
$res=json_decode($curl_response);
foreach ($res->curl_response as $values)
{
if($values->ReturnMessage=='successful')
{
$usql="update do_order set tracking_id='".$resultc[0]['awb']."',shipping_name='xpress', where order_id='".$order_id."'";
$result=$db_handle->executeUpdate($usql);
echo "1";die;
}
else
{
echo $values->ReturnMessage;die;
}
}
Here is full code : https://pastebin.com/EvcEY0xp
Result :
Notice: Undefined property: stdClass::$curl_response
Warning: Invalid argument supplied for foreach()
$res will already contain decoded response from curl request, which will have only 1 property - AddManifestDetails.
Try following:
<?php
$data =
array (
'OrderNo' => $order_id,
'AirWayBillNO' => $resultc[0]['awb'],
);
$url = "http://114.143.206.69:803/StandardForwardStagingService.svc/AddManifestDetails";
$data = json_encode($data);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$curl_response = curl_exec($curl);
curl_close($curl);
echo $curl_response ."\n";
$res=json_decode($curl_response);
if($res->AddManifestDetails[0]->ReturnMessage=='successful')
{
$usql="update do_order set tracking_id='".$resultc[0]['awb']."',shipping_name='xpress' where order_id='".$order_id."'";
$result=$db_handle->executeUpdate($usql);
echo "1";
die;
}
else
{
echo $res->AddManifestDetails[0]->ReturnMessage;
die;
}

Recursive call until value is not more on response

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?

How to develop user defined menu on wechat

here is my sample code. my developer mode is already enabled but there is no menu tabs options.
you can also add me on wechat so I can elaborate my problems in this matter, here is my wechat ID VinceZen. I badly need some help guys. Thank you in advance.
<?php
$data[] = '772134292672v';
$data[] = $_GET['timestamp'];
$data[] = $_GET['nonce'];
asort($data);
$strData = '';
$d = '';
$authString = '';
foreach($data as $d)
{
$authString .= $d;
}
//verify the signature
if(sha1($authString) == $_GET['signature'])
{
//check the echostr
if(!empty($_GET['echostr']))
{
echo $_GET['echostr'];
die();
}
else
{
//logic
//Getting access_token from customize menus
static function get_access_token($appid,$secret){
$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
$json=http_request_json($url);//here cannot use file_get_contents
$data=json_decode($json,true);
if($data['access_token']){
return $data['access_token'];
}else{
return "Error occurred while geting the access_token";
}
}
//Though URL request is https',cannot use file_get_contents.Using CURL while asking the JSON data
function http_request_json($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$return = "<xml>
<ToUserName><![CDATA['.$toUser.']]</ToUserName>
<FromUserName><![CDATA['.$fromUser.']]</FromUserName>
<CreateTime>'.time.'</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA['.text.']]</Content>
<FuncFlag>0</FuncFlag>
</xml>";
echo $return;
{
"button":[
{
"type":"click",
"name":"Daily Song",
"key":"V1001_TODAY_MUSIC"
},
{
"type":"click",
"name":" Artist Profile",
"key":"V1001_TODAY_SINGER"
},
{
"name":"Menu",
"sub_button":[
{
"type":"view",
"name":"Search",
"url":"http://www.soso.com/"
},
{
"type":"view",
"name":"Video",
"url":"http://v.qq.com/"
},
{
"type":"click",
"name":"Like us",
"key":"V1001_GOOD"
}]
}]
}
}
}
else
{
die('Access Denied');
}`enter code here`
?>

Get array from mysql and pass it to a method

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.

Categories