Wednesday, October 6, 2010

file_get_contents acting very slow

Lately i have been working on a simple REST-like service interface to an existing product at work. I admit, I found some code online that I modified. No need to do work already done, right? ;-)

The problem arose when i tried to call my brand new web service. I got extremely long waiting time (about 15 secs to precise), before the resource was returned. The code I used look like this:

$result = file_get_contents('http://example.com/service/');

As simple as it gets. When I tried calling the service directly from my browser, the result came back instantly.

I turned to my old friend Google to look for an answer. Most of the answers i got was that the DNS lookup was slow. So i tried my script from all the different servers I have access to, but with the same result.

The solution was quite simple, when I finally found it. In my REST-like service I set the follow header:

header('HTTP/1.1 200 OK');

By doing this I force the connection to use HTTP 1.1. This is pretty standard, but apparently by doing this I use the default behaviour of HTTP 1.1 and that is to keep the connection alive. The same as setting:

header('Connection: keep-alive');

So the connection started by file_get_contents() is keept open, until it times out. Timeout is set to 15 secs on the server!! So the solution was to put the following header in my service:

header('Connection: close');

A w00p w00p the result was returned instantly.

A quick tip if you run into this problem, and the service is not your own, is to set the header yourself. You can do this by giving a context to the file_get_contents. This can be done by doing the following:

$opts = array(

'http'=>array(
header' => 'Connection: close'
)
);
$context = stream_context_create($opts);

$result = file_get_contents('http://example.com/service/', false, $context);

This will force the connection to close immediately after the resource have been retrived. Al option that can be set in a context (for HTTP) can be found here: http://php.net/manual/en/context.http.php

5 comments:

SuhisLover said...

Hi

i have the same problem of performance and tried to apply your advice, but my problem is not solved....

Can you help me please ?

Russ said...

I too am having the same issue even after applying your advice. I've tried:
- Using an IP address rather than a DNS name.
- Setting the 'Connection: close' header in the context as you suggest.
- Using simplexml_load_file() instead of file_get_contents().

No matter what I do it takes several seconds for PHP to respond with something that is instant through the Web browser!

moffe42 said...

I have to admit that I am no expert on HTTP, so my knowledge in this area is very limited. You could try to force the connection over to HTTP 1.0, that might work, but no guarantee. If you re not controlling the the actual service yourself, you might not have any options, since it is up to the service to actually adhere to the headers you send.

If you find the course or solution to your problem, please let me know. I had to dig very deep, to find the solution that worked for me, so any additional info on these kind of problems should be spread.

oangia said...
This comment has been removed by the author.
le fitta said...

This worked like a charm for me! Thanks!