SimpleXMLElement - HTTP status code? - php

I'm working with the PHP Steam Condenser library, to grab some Steam details about a user. I've successfully implemented this and everything is working. However I started to notice an error being thrown every so often, from Steam Condenser.
What's happening is, when I call the SteamId class with a param, the library generates a URL and makes a request to it, using SimpleXMLElement (as can be seen here). Now most of the time, the URL returns XML and so my application works fine, however every so often Steam throws back a 503 Service Unavailable back, causing it to fail.
try {
return #new SimpleXMLElement($url, 0, true);
} catch (Exception $e) {
$errorMessage = "XML could not be parsed: " . $e->getMessage();
if ((float) phpversion() < 5.3) {
throw new SteamCondenserException($errorMessage, 0);
} else {
throw new SteamCondenserException($errorMessage, 0, $e);
}
}
In my cause, the PHP version is correct, so it throws the bottom custom Exception:
SteamCondenserException
XML could not be parsed: String could not be parsed as XML
/home/user/public_html/acme/vendor/koraktor/steam-condenser/lib/steam/community/XMLData.php (Line 38)
Although this is technically the correct exception, it isn't very meaningful since the request was just "Unavailable" and therefore couldn't gather the XML.
How would I go about editing this code to first check what the status code of the request is, if it's a 302 or 200 (since it redirects), then proceed to check the XML, otherwise if it's a 503, respond with a more genuine error (The Steam Community API is currently down) - or something.
I've Google'd my ass off, but can't see anything. Ideally I'd like it all to be done in the same request, since Steam can be a little slow sometimes.
Cheers

Don't use SimpleXMLElement to also do the HTTP request.
Use curl (because it's fast) to fetch the XML plain-text and SimpleXML to parse it.
That way you can separate service availability from transmission errors (or XML errors).

Related

How to handle errors in Zapier?

I am building an integration with Zapier (https://zapier.com/platform) and I want to throw an error but it seems like it's not working properly.
My authentication code (dumbed down for the purpose of this post):
if($_POST['api_key'] === $row['api_key']) {
$array = ['success' => 'yes'];
echo json_encode($array);
} else {
echo "Sorry but that is the invalid API token. Please try something else";
}
When I try to test that in the Zapier developer platform, I get this message from them:
Error parsing response. We got: "Sorry but that is the invalid API token. Please try something else". This is likely a problem with the app. Please contact support at contact#zapier.com
But Zapier wants me to throw an error that does not have the "Error parsing response" and "This is likely a problem with the app..." parts....
How can I fix this?
Simply sending a message that the auth was unsuccessful isn't enough - you need to also send the appropriate HTTP response code. In this case, you probably want 403 or 401. I'm not sure how to do that, but there plenty of questions that'll point you in the right direction.
Additionally, you probably want to send back JSON rather than plain text. This could be as simple as: {"message": "invalid token"}. This'll help the client better surface that info to the user.

Laravel forcing json response for api

I'm building an api at my company using laravel.
The problem I'm encountering is that if you send an api request without defining the correct header with the request you will get html back if there is a failure e.g. authorization failure or findOrFail() failure.
My thinking is that you never want to return html (even if the user has the wrong header).
I have a couple of solutions. In BeforeMiddleware.php I can manually insert a header into the request such as:
// Check if we are on an api route
$apiRoute = strncmp($uri, '/api/', 5) == 0;
// Insert the request header to force json response
if ($apiRoute){
$language = $request->header->add('Accept', 'application/json');
}
The 2nd solutions would be to throw an error if they don't have the correct header.
What would be the best way to enforce a json response, what is a good practice for handling api responses in laravel?
Once you detected that you are on your api path you are out of the woods and can indeed tackle your problem in the app\Exceptions\Handler.php file like suggested on How do you force a JSON response on every response in Laravel?.
For an open source project I created JSON exception objects by Microsoft format as output, but you can choose the jsonapi format (http://jsonapi.org/examples/#error-objects-basics) as you like:
https://github.com/StadGent/laravel_site_opening-hours/blob/develop/app/Exceptions/Handler.php
(note that on this implementation it is indeed depending from the headers, but you can use your path detection I think)

SoapClient call returns 500 Internal Server Error

I am trying to connect to an API using PHP and its built-in SoapClient. I have checked against the url I was given through the ill-formatted documents the client gave and $client->__getFunctions() returns a list of three functions. HelloWorld($name), which responds with Hello ~name~, shows me that I am communicating with the server through the SoapClient call and the URL is correct.
However, when I try to access one of the other methods that __getFunctions() gives me, even after copy/pasting the XML from the docs and putting in my own credentials, I am still being given an Internal Server Error faultstring and 500 as faultcode from the SoapFault object.
I am sure that it is my own XML string that is causing the issue but I cannot for the life of me figure out how. Reaching out to the API provider directly hasn't proven helpful. This is my first time dealing with Soap/Web Services so I am unsure of where to go from here.
I did wget http//xxx.xxx.xxx?wsdl and it returned me what looks like a valid XML response, the same one I get when I go directly to the url in the browser. What should I be looking into in order to solve this issue? All of the past API's I've dealt with have been JSON/RESTful so I feel out of my element trying to debug PHP errors.
Edit
I have slowly deleted parts of my method call and parts of my XML string, trying to trigger a different error or something in order to find what I need to fix. What I have found is that by not passing in my XML string, I get a valid response from the $client->FunctionCall(...). It's an "this isn't right" message but it's a message! In fact, passing that function ANYTHING for the xml parameter causes the 500 http faultcode/faultstring. Does this mean that my XMl is poorly formatted or does it mean that there is an issue on their end handling requests?
Second Edit
If I make my $client decleration as follows, I get the faultstring Could not connect to host
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client = new SoapClient($CREDS['orderingWSDL'], array (
"encoding"=>"ISO-8859-1",
'stream_context' => stream_context_create($opts),
'exceptions'=>true,
));
I am getting more confused the longer I try to fix this.
Sometimes a 500 status coming from a SOAP service could be a SoapFault exception being thrown. To help your troubleshooting, you'll want to be able to inspect both your request XML, and the response XML.
Put your code in try/catch blocks, and use $client->__getLastRequest() and $client->__getLastResponse() to inspect the actual XML.
Example:
$client = new SoapClient('http//xxx.xxx.xxx?wsdl', array('soap_version'=>SOAP_1_1,'trace' => 1,'exceptions' => true));
try {
$response = $client->someFunction();
var_dump($response);
} catch (Exception $e) {
var_dump($e->getMessage());
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}

Get external page content regardless of response type [duplicate]

This question already has an answer here:
Need response body of HTTP 500 with file_get_contents (PHP)
(1 answer)
Closed 8 years ago.
I'm working with an API that I recently noticed is failing in the code some of the time. I retrieve it via file_get_contents, and I'm getting the error "failed to open stream: HTTP request failed!"
I plugged the URL into the browser directly and I get back a response, so I was confused. I thought to check the headers, and I noticed its coming up 403, and I have to assume that's why its failing? When its not 403, it does work. The 403 only comes up when the API authentication fails, and I have code to check if the XML that comes back says its a failure.
So really the question is, how can I get back the code, regardless of if its a 403 or not. I was going to start using simplexml_load_file since I'm loading it into SimpleXML anyway, but if there is another method I can/should use, that advice would be great too.
EDIT: I've attempted a simple curl request, but unless I've done it wrong, its also failed:
$curlObject = curl_init('https://api.eveonline.com/account/Characters.xml.aspx?userID=8166034&characterID=91242713&apiKey=B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282');
curl_setopt($curlObject, CURLOPT_RETURNTRANSFER, 1);
$fileContents = curl_exec($curlObject);
curl_close($curlObject);
echo $fileContents;
I would wrap the handling as specified in the duplicate question and then throw a dedicated exception when you trigger that error-response:
$legacyKey = [
'userID' => '8166034',
'apiKey' => 'B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282',
];
$api = new EveApi($legacyKey);
$api->define('getAccountCharacters', 'account/Characters.xml.aspx', ['characterID']);
try {
$characters = $api->getAccountCharacters($characterID = '91242713');
} catch(Exception $exception) {
printf("Exception: %s; Code: %s; Message: %s\n", get_class($exception), $exception->getCode(), $exception->getMessage());
throw $exception;
}
In this example, the default handling from the EveApi would be to throw exceptions on such errors:
<?xml version="1.0" encoding="UTF-8"?>
<eveapi version="2">
<currentTime>2013-11-02 13:06:53</currentTime>
<error code="203">Authentication failure.</error>
<cachedUntil>2013-11-03 13:06:53</cachedUntil>
</eveapi>
Can be turned into an EveApiError then as this output shows:
Exception: EveApiError; Code: 203; Message: Authentication failure.
Fatal error: Uncaught exception 'EveApiError' with message
'Authentication failure.' in ...
That would not only wrap the error handling but also the API access allowing you to inject your own API for testing purposes.
Additionally you can wrap the different but common return types.

Android how to catch an exception thrown from php rest

I have a PHP RESTful API, which returns JSON objects.
I have an Android client requesting REST requests from that API
Till now if there was a problem in the server side then the API returned a booleanic response "false"
I want to change the flow of the API, so instead of sending a JSON response containing "false" it will throw and Exception, and I want the android side to catch the exception.
So basically, i want something like the following Android code:
try {
php_api.getUsers();
} catch (Exception ex) {
// TODO
}
Can it be done?
Will any PHP exception be caught in this way?
I haven't worked with Java but I don't think that you can do that.
When PHP throws an exception, it will still produce an output of some sort, depending on how you set up exception handling.
It could show the exception message with a stack trace or something similar.
But on the client (your Java app) side, this is nothing more than text.
However, a rest response should always have headers that you can check. Take a look at this: http://blog.zenika.com/index.php?post/2011/05/18/Error-handling-with-REST
By following what is written there, your Java-to-PHP api would always read the response headers before returning the content. If a 500 or 400 showed up, you'd throw a java exception from the api which you could catch in the code that uses it.
If your PHP side is not sending the headers you want, you can always override PHP's error/exception handling to produce custom output (including headers).

Categories