0

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;
hakre
  • 193,403
  • 52
  • 435
  • 836
Rohit
  • 3,018
  • 2
  • 29
  • 58
  • Can you share the URL ? – Shankar Narayana Damodaran Nov 01 '13 at 14:57
  • http://api.eveonline.com/account/Characters.xml.aspx?userID=8166034&characterID=91242713&apiKey=B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282 – Rohit Nov 01 '13 at 15:24
  • Are you asking about how to get the HTTP status code of the last file_get_contents operation? Yes, `FALSE` means failure, the exact status code is part of [`$http_response_headers` (special reserved variable)](http://php.net/reserved.variables.httpresponseheader), see [here for an example how to parse it and obtain the status code](http://stackoverflow.com/a/7566440/367456) (via: http://stackoverflow.com/q/9724924/367456). – hakre Nov 02 '13 at 11:23
  • I'll try that today, and if it works, mark accordingly. – Rohit Nov 02 '13 at 16:52

1 Answers1

0

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.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • If you're interested in the example's code, you can find more here: https://gist.github.com/hakre/b654d1b7366273335dfd – hakre Nov 02 '13 at 13:20
  • That's pretty awesome; I'll look at it in depth. But on immediate review, I don't see how that addresses the issue of simplexml_load_file not loading a 403 error'ed response? Could you point that out to me? Or do you mean to just handle that with an exception, even if it doesn't get back a response? – Rohit Nov 02 '13 at 19:21
  • @RhoVisions: Sorry, I thought it was clear that this is exactly like done in the duplicate question: http://stackoverflow.com/questions/6040978/need-response-body-of-http-500-with-file-get-contents-php - you meed to set PHP's http wrapper context option to *ignore errors*, that is the important setting. See as well: [HEAD first with PHP Streams](http://hakre.wordpress.com/2011/09/17/head-first-with-php-streams/) where that setting is explained in greater detail as well. And if you do not want to use `file_get_contents` but `simplexml_load_file`, you need to change the default context. – hakre Nov 02 '13 at 19:22
  • Compare with this line ff.: https://gist.github.com/hakre/b654d1b7366273335dfd#file-eveapi-simplexml-errors-php-L149 – hakre Nov 02 '13 at 19:26
  • Ah, that was the problem. I misread your code. I saw the simplexml_load_file and missed the file_get_contents. Thanks! – Rohit Nov 02 '13 at 19:52
  • Yes, either `file_get_contents` or for `simplexml_load_file` with [`stream_context_set_default`](http://php.net/stream_context_set_default). – hakre Nov 02 '13 at 20:08
  • Here is another one: [`libxml_set_streams_context()`](http://php.net/libxml_set_streams_context) - this is perhaps the best way for SimpleXML. – hakre Nov 03 '13 at 15:29