PHP Function - Trapping for Error or Success Result - php

I'm working on my first function with PHP - it's a login function that calls cURL to login to an API. This is all working well so far, but I would like to add some error checking so that if the login fails or succeeds I can branch for that.
There's 2 possible types of errors that I can see:
cURL errors
API login errors
If there are no cURL errors the API will return a response in JSON like this for a successful login:
{
"token": "6a2b4af445bb7e02a77891a380f7a47a57d3f99ff408ec57a62a",
"layout": "Tasks",
"errorCode": "0",
"result": "OK"
}
and this for a failed login:
{
"errorMessage": "Invalid user account and/or password; please try again",
"errorCode": "212"
}
so that should be easy enough to trap for by the error code or result value. If there is a cURL error there could be many types of errors.
Here's the outline of my function at the moment:
function Login ($username, $password, $layout) {
$curl = curl_init();
// set curl options
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
return json_decode($response, true);
}
}
and I call it via:
$login = Login($username, $password, $layout);
Looking for advice on how I can return an error if there was a curl error and check the response on the calling page that calls the function.

As suggested by #larwence-cherone in the comments, you should throw and catch exceptions.
// note: made the method name lowercase, because uppercase usually indicates a class
function login ($username, $password, $layout) {
$curl = curl_init();
// set curl options
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
throw new Exception($err);
} else {
// returns an associative array
$result = json_decode($response, true);
// the status was not OK or if we received an error code.
// Check the API doc for a recommended way to do this
if ($result['result'] !== 'OK' || $result['errorCode'] > 0) {
$errorMessage = $result['errorMessage'];
// no error message: return a genuine error
if (!$errorMessage) {
$errorMessage = 'An undefined error occurred';
}
throw new Exception($errorMessage);
}
// if no error occurred, return the API result as an
return $result;
}
}
call the method in a try/catch block:
try {
$login = login($username, $password, $layout);
print_r($login);
} catch (Exception $error) {
echo $error;
}
If you want to refine it, you could create your own exception(s) by extending the SPL Exception class.

Related

Code that works fine on local but not on server

So the purpose of my code is to get response from curl.
Here is a reference method
public function waybill($waybill, $courier)
{
$curl = curl_init();
curl_setopt_array($curl, array(
[Some CURLOPT here..]
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
return "cURL Error #:" . $err;
} else {
return $response;
}
}
And from here i call the method
public function getWaybill($carrier, $tracking_number)
{
$waybill = $tracking_number;
$courier = strtolower($carrier);
$response = $this->helper->waybill($waybill, $courier);
$response = json_decode($response, true);
$response = $response['rajaongkir']['result'];
$response = $response['summary']['status'];
if (!empty($response)) {
return $response;
} else {
return "Invalid tracking data";
}
}
In local appear "Invalid tracking data" if response is empty, however in server does not appear anything.
Try creating another page with just this on it
<?php
if (in_array ('curl', get_loaded_extensions())) {
echo true;
}
else {
echo false;
}
This will let you know if curl is enabled (if get_loaded_extensions() isn't disabled) ... Might be your issue..
Otherwise the old
<?php phpinfo();
and search for curl would work too (if phpinfo is allowed on your server)

500 internal server error with POST request - Slim framework

I'm trying to build a simple REST application with Slim framework, but I'm getting a 500 error when I try to execute the POST request. So far, I've implemented two working GET requests. Here is the code:
index.php:
require_once '../include/DbHandler.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->get("/", function () {
echo "<h1>Hello!!!!</h1>";
});
/**
* Get all the events
* method GET
* url /events
*/
$app->get('/events', function() {
$db = new DbHandler();
$response = array();
// fetch events
$result = $db->getAllEvents();
if ($result != NULL) {
$response["error"] = false;
$response = $result;
echoResponse(200, $response);
} else {
$response["error"] = true;
$response["message"] = "The requested resource doesn't exists";
echoResponse(404, $response);
}
});
$app->get('/event/:id', function ($id) {
$response = array();
$db = new DbHandler();
// fetch event
$result = $db->getEvent($id);
if ($result != NULL) {
$response["error"] = false;
$response = $result;
echoResponse(200, $response);
} else {
$response["error"] = true;
$response["message"] = "The requested resource doesn't exists";
echoResponse(404, $response);
}
});
$app->post('/events', function() {
// opening db connection
$db = new DbConnect();
//$db = new DbHandler();
$request = Slim::getInstance()->request();
//$result = $db->addEvent($request);
$event = json_decode($request->getBody());
$img = " ";
$sql = "INSERT INTO event (title, location, date_event, ageMin, ageMax, groupSize, limited, maxParticipants, joining, description, img, type, language) VALUES (".$event->title.", ".$event->location.", ".$event->date_event.", ".$event->ageMin.", ".$event->ageMax.", ".$event->ageMax.", ".$event->limited.", ".$event->maxParticipants.", ".$event->joining.", ".$event->description.", ".$img.", "$event->type", ".$event->language.")";
try {
//$db = $this->conn;
$conn = $db->connect();
$result = $conn->query($sql);
$event->id = $conn->lastInsertId();
echoResponse(200, $event->id);
} catch(PDOException $e) {
echoResponse(404, '{"error":{"text":'. $e->getMessage() .'}}');
}
});
/**
* Echoing json response to client
* #param String $status_code Http response code
* #param Int $response Json response
*/
function echoResponse($status_code, $response) {
$app = \Slim\Slim::getInstance();
// Http response code
$app->status($status_code);
// setting response content type to json
$app->contentType('application/json');
echo json_encode($response);
}
$app->run();
?>
As I said before, the two GET methods are working, but when I try to add a row with the POST method using this data:
{"title": "Test 1", "location": “Rome, Italy", "date_event": "2016-05-12", "time": "22:00:00", "ageMin": 21, "ageMax": 27, "groupSize": "3", "limited": false, "maxParticipants": "", "joining": "2", "description": "Description test 1", "img": "", "type": "hanging out", "language": "Italian/English"}
I get 500 Internal Server Error and I cannot understand why.
Where am I doing wrong?
Thanks!
You've missed concatenation dots around "$event->type" in your $sql assignment.
While developing I recommend you to enable error and warning messages adding
error_reporting(E_ALL);
ini_set('display_errors', 1);
to your code.
PHP Syntax Check: Parse error: syntax error, unexpected '$event' (T_VARIABLE) in your code on line 62.
is more likely understandable than
500 Internal Server Error.
As an alternative, if you have a small piece of code to check, you can use some online tool like http://phpcodechecker.com/

Handling errors in a PHP class

I try to handle errors in a class written in PHP and using curl, this class uses 3 functions (init, sendFirstForm, sendSecondForm) dependent on one another, I test result via nested statements.
I want to manage two types of errors (Curl connection errors and form errors) that requires the sending of an email so I can fix them.
This code does not work.
class Sender {
public $error;
public function __construct() {
$this->error = '';
}
public function send() {
if($this->init() === TRUE) /* account login and retrieval of the cookie */
{
if($this->sendFirstForm() === TRUE) /* sending the first form if connection */
{
if($this->sendSecondForm() === TRUE) /* sending the second form if connection */
{
echo 'Annonce publiée avec succès.';
}
}
}
}
public function init() {
// CuRL : account login and retrieval of the cookie
// ...
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
$result = curl_exec($ch);
if(curl_errno($ch))
{
$this->error = 'CuRL Error : ' . curl_error($ch);
return $this->error;
}
elseif(preg_match("/\bError\b/i", $result)) /* $ _POST data missing and / or incorrect */
{
$this->error = 'Error in the login form';
return $this->error;
mail('name#domain.com', 'Error Curl', 'Error connecting to the account, here are the data sent : ' . $postfields);
}
}
public function sendFirstForm() {
// CuRL : sending the first form
// ...
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
$result = curl_exec($ch);
if(curl_errno($ch))
{
$this->error = 'CuRL Error : ' . curl_error($ch);
return $this->error;
}
elseif(preg_match("/\bError\b/i", $result)) /* $ _POST data missing and / or incorrect */
{
$this->error = 'Error in the first form';
return $this->error;
mail('name#domain.com', 'Error Curl', 'Error sending first form, here are the data sent : ' . $postfields);
}
}
public function sendSecondForm() {
// CuRL : sending the second form
// ...
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
$result = curl_exec($ch);
if(curl_errno($ch))
{
$this->error = 'CuRL Error : ' . curl_error($ch);
return $this->error;
}
elseif(preg_match("/\bError\b/i", $result)) /* $ _POST data missing and / or incorrect */
{
$this->error = 'Error in the second form';
return $this->error;
mail('name#domain.com', 'Error Curl', 'Error sending second form, here are the data sent : ' . $postfields);
}
}
}
$send = new Sender();
$send->Send();
if(empty($send->error))
{
// MySQL treatment
}
else
{
echo $send->error;
}

What is the proper way to capture a "Response too large to return error" in Google BigQuery API for PHP?

In the Google BigQuery web interface, if I run a query that returns a response that is too large, I receive the message:
Error: Response too large to return. Consider setting allowLargeResults to true in your job configuration.
How can I capture this error message in the Google BigQuery API interface when running a query that does not have allowLargeResults set in the job configuration?
In respective BigQuery API - Jobs: get this info is in status.errorResult
Respectivelly in
reason property: responseTooLarge
message property: Response too large to return. Consider setting allowLargeResults to true in your job configuration. For more details, ...
You can also check status.errors for more details for all errors encountered during job execution
We use this fragment to handle errors, and it helped out:
We have also when we place the job, and later when we check the status of the job in a loop, as that error popups up when the job is done.
try {
try {
$job = $bq->jobs->insert(PROJECT_ID, $job);
} catch (Google_IO_Exception $e) {
$this->e('Exception: ' . $e->getMessage(), 'red');
$this->e('Strace: ' . $e->getTraceAsString());
if ($e->getMessage() == 'SSL connect error') {
$this->clearTokenFile();
$this->releaseJob();
}
return false;
}
$status = new Google_Service_Bigquery_JobStatus();
$status = $job->getStatus();
if (0 != $status->count()) {
$err_res = $status->getErrorResult();
$this->e($err_res->getMessage(), 'red');
return false;
}
} catch (Google_Service_Exception $e) {
$this->e('Exception: ' . $e->getMessage(), 'red');
return false;
}
on and insertAll we have, here pay attention to the reason field:
try {
$resp = new Google_Service_Bigquery_TableDataInsertAllResponse();
$resp = $bq->tabledata->insertAll($project_id, $dataset_id, static::tableId(), $request);
$errors = new Google_Service_Bigquery_TableDataInsertAllResponseInsertErrors();
$errors = #$resp->getInsertErrors();
if (!empty($errors)) {
$error_msg = "\r\nRequest Headers: \r\n" . json_encode($client->request->getRequestHeaders()) . "\r\nResponse Headers: \r\n" . json_encode($client->request->getResponseHeaders()) . "\r\nRequest Body:\r\n" . $client->request->getPostBody() . "\r\nResponse Body:\r\n" . $client->request->getResponseBody() . "\r\n";
if (is_array($errors)) {
foreach ($errors as $eP) {
$arr = $eP->getErrors();
$line = $eP->getIndex();
if (is_array($arr)) {
foreach ($arr as $e) {
switch ($e->getReason()) {
case "stopped":
break;
case "timeout":
$failed_lines[] = $line;
$last_reason = $e->getReason();
$error_msg.= sprintf("Timeout on line %s, reason: %s, msg: %s\r\n", $line, $e->getReason(), $e->getMessage());
break;
default:
$error_msg.= sprintf("Error on line %s, reason: %s, msg: %s\r\n", $line, $e->getReason(), $e->getMessage());
break;
}
}
} else {
$error_msg.= json_encode($arr) . "\r\n";
}
}
$this->setErrorMessage($error_msg);
} else {
$this->setErrorMessage($errors);
}
//print_r($errors);
//exit;
$success = false;
}
return $ret;
} catch (Google_Service_Exception $e) {
$this->setErrors($e->getErrors())->setErrorMessage($e->getMessage());
throw $e;
}
Answering my own question: Here's a summary of what resolved it for me. In summary, I couldn't get it to throw an error for Synchronous Queries, but was able to get it to throw for Asynchronous Queries.
Here is a sample query with a response too large to return:
$query = "SELECT * FROM [publicdata:samples.github_timeline] LIMIT 1000000;"
Synchronous Queries
Running a synchronous query with jobs.query:
try {
$query_request = new Google_Service_Bigquery_QueryRequest();
$query_request->setQuery($query);
$res = $this->gbq_service->jobs->query($this->_project_id, $query_request);
return $res;
} catch (Exception $e){
echo $e->getMessage());
}
The response I receive is:
{
"cacheHit": null,
"jobComplete": false,
"kind": "bigquery#queryResponse",
"pageToken": null,
"totalBytesProcessed": null,
"totalRows": null
}
So in this case, I still don't receive the desired "response too large to return".
Asynchronous Queries
If I run the job as an asynchronous query, the job status is eventually set to DONE, and on checking the results, an error is thrown with message:
{
"error": "Error calling GET https://www.googleapis.com/bigquery/v2/projects/.../queries/job_2VICoK6yX0YMM_zRkJ10hT9mom8?timeoutMs=1000000&maxResults=100: (403) Response too large to return. Consider setting allowLargeResults to true in your job configuration. For more information, see https://cloud.google.com/bigquery/troubleshooting-errors",
}
Telling me that I need to save the results as a table and set allowLargeResults to true.
So, the short answer is- run your queries as asynchronous queries.
Update
I've contacted google and they mentioned it may be a bug in the php api. They have said they will forward it to the php gbq API people.

How to override the Exception Class and not to display the Fatal error

I am trying to write a class that communicate with an API. I would like to override the standard Exception class in PHP to return the message, error code that I want.
I have added this extension
<?php namespace API;
/**
* API Exception
*
* #package ICWS
*/
class ApiException extends \Exception
{
public function __construct($message, $code = 0)
{
// Custom ICWS API Exception Message
$apiMessage = 'ICWS API Error: ' . $message;
//More code to come to custom the error message/code.....
// Run parent construct using custom message
parent::__construct($apiMessage, $code);
}
}
?>
Then when needed I create new ApiException like so
throw new ApiException($errorMessage, $errorNo);
Finally I wrap the function that throws an exception by try{} catch() block to capture the exception.
However, I still get the a fatal error instead of just the message that I provided.
Here is my code
public function createSession($userID, $password){
$data = array('userID' => $userID,
'password' => $password);
try {
$data = $this->_makeCall('POST', 'connection', $data);
$this->_csrfToken = $data['csrfToken'];
$this->_sessionId = $data['sessionId'];
$this->_alternateHostList = $data['alternateHostList'];
} catch (Exception $e){
$this->_displayError($e);
}
}
private function _makeCall($uri, $data = false, $header = array())
{
$ch = curl_init();
$url = $this->_baseURL . $uri;
//disable the use of cached connection
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_URL, $url);
//return the respond from the API
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if(!empty($header)){
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($ch, CURLOPT_POST, true);
if ($data){
$JSON = json_encode( $data );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $JSON );
}
$result = curl_exec($ch);
//throw cURL exception
if($result === false){
$errorNo = curl_errno($ch);
$errorMessage = curl_error($ch);
throw new ApiException($errorMessage, $errorNo);
}
$result = json_decode($result, true);
//throw API exception
if( $this->_hasAPIError($result) )
){
throw new ApiException($result['message'], 0);
}
return $result;
}
private function _displayError(Exception $e){
echo 'Error Number: ' . $e->getCode() . "\n";
echo 'Error Description: ' . $e->getMessage() . "\n\n";
}
private function _hasAPIError($result){
if( isset($result['errorId']) && !empty($result['errorId'])
&& isset($result['errorCode']) && !empty($result['errorCode'])
&& isset($result['message']) && !empty($result['message'])
){
return true;
}
return false;
}
I would like to see something like this at then end "if there is an error"
Error Number: 0
Error Description: ICWS API Error: The authentication process failed
This is what I currently get
Fatal error: Uncaught exception 'API\ApiException' with message 'ICWS API Error: The authentication process failed.' in C:\phpsites\icws\API\ICWS.php:130 Stack trace: #0 C:\phpsites\icws\API\ICWS.php(57): API\ICWS->_makeCall('connection', Array) #1 C:\phpsites\icws\index.php(17): API\ICWS->createSession('user', 'pass') #2 {main} thrown in C:\phpsites\icws\API\ICWS.php on line 130
You did not import the Exception class into your namespace, so when doing catch (Exception $e), Exception is an unknown class (because PHP is assuming API\Exception) and PHP will not notice that APIException is a subclass of Exception. Curiously, PHP does not complain about catching a non-existing class (I've just confirmed this locally with PHP 5.6.8).
The following should work:
catch (\Exception $e) {
// ...
}
Alternatively:
use Exception;
// ...
catch (\Exception $e) {
// ...
}
The error is that you are catching Exception, not ApiException. Try this:
try {
$data = $this->_makeCall('POST', 'connection', $data);
$this->_csrfToken = $data['csrfToken'];
$this->_sessionId = $data['sessionId'];
$this->_alternateHostList = $data['alternateHostList'];
} catch (ApiException $e){ // Here is the change: Exception to ApiException
$this->_displayError($e);
}

Categories