0

I've got PHP5.2 currently. I ultimately want to use json_decode, to parse the contents of a JSON file obtained via HTTP request.

json_decode requires the JSON to be in a string and passed as a parameter, so I'm reading in the file to a string via file_get_contents.

Think of it as:

$JSON = file_get_contents($URL);

Where $JSON is the storage string for the file contents, and $URL is the target URL to fetch the file via HTTP request. Regarding file_get_contents the PHP manual states:

The function returns the read data or FALSE on failure.

As far as failure goes, I'm assuming this returns FALSE on either a timeout (could not reach server at $URL), a 404 (reached server, but file did not exist at $URL), a 503 (reached server, but was too busy to respond properly), or a 500 (internal server error, generally shouldn't happen).

Anyways, of the errors above I'm most concerned with the 503, the server I am hitting occasionally throws this on HTTP request. When this happens, I want to try again.

So I came up with this:

$JSON = null; //Initially set to null as we have not fetched it

for($attempt = 0; $attempt < 3; $attempt++) //Try 3 times to fetch it
    if($JSON = file_get_contents($URL)) break; //If we fetch it, stop trying to

//Kill the script if we couldn't fetch it within 3 tries
if($JSON == null) die("Could not get JSON file"); 

This sort of does the job, but I don't think it's very solid. I was reading more about the contexts, but I don't fully follow how to use them in PHP. Is there some way I can handle this type of thing in a much better way?

user17753
  • 3,083
  • 9
  • 35
  • 73

2 Answers2

2

PHP creates a variable called $http_response_header after a file_get_contents() call to a URL, you should be able to use this to your favor.

function read_json_data($url, $attempts = 0) {

    $json = file_get_contents($url);

    if (!$json && isset($http_response_header) && strstr($http_response_header[0], '503') && $attempts++ <= 2) {

        return read_json_data($url, $attempts);

    }

    if (!$json) {

        throw new Exception("Maximum attempts or not a 503 status code.");

    }

    return json_decode($json);

}

Usage:

$json = read_json_data($url);

Runs up to three times when hitting 503's.

Björn
  • 29,019
  • 9
  • 65
  • 81
  • I'm thinking the `read_data` ought have `json` in there (for recursion). The concept of `$http_response_header` is what I needed! I didn't see it obvious on the manual page for `file_get_contents`. This is exactly what I needed, thanks! – user17753 Oct 01 '12 at 15:04
1

I'd say a much better way would be to actually take the HTTP status code into account before trying again.

The re-try makes only sense in that specific case you get a 503 but not - for example - a 404.


Similar to the existing answer I'd also say that $http_response_header is a good place to fetch the status code from which is fairly easy to capture.

Also you can create the context to specify additional options, you can have file_get_contents for example return different than false on diverse status codes, too (e.g. 404).

$context = stream_context_create(['http' => ['ignore_errors' => 1]]);

$data = file_get_contents($url, null, $context);

$code = null;

$http_response_header 
    && sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code)
;

Apart from status-code you might want to check the mime-type that is being returned, you could fetch that from the response headers, too, a function to parse the full array has been outlined in a related question/answer.

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836