cURL vs “file_get_contents()” in Google App Engine – Performance analysis

We all know that to do any kinds of external HTTP request from your PHP application (deployed in Google App Engine a.k.a GAE) we have three options basically. PHP native cURL extension, “cURL Lite” provided by Google and the native http:// and https:// PHP stream handlers.

cURL requires a valid billing profile and only you can enable it in your Google Cloud paid project. And that’s why Google’s custom cURL Lite actually use Google’s urlfetch service that you can use in your application free version.

But recent days, our engineering team was just wondering which can be little bit faster among cURL or cURL Lite or PHP native PHP HTTP handler, in this sense little bit faster meaning we also count even 50ms latency. That’s why I was running some test with a single script hosted on Google App Engine (PHP Standard Runtime environment). We had lots of PHP microservice apps hosted on Google App Engine and all services at a certain time needs to talk each other via HTTP external request. But sometimes, we were aware that latency is killing some communication.

So we just built 2 files basically in PHP. One is using cURL to post some foobar json data to an external URL (postb.in) and another one was using the native http:// and https:// PHP stream handlers. Let’s see what was our experimental scripts look like.

<?php

/**
 * Using CURL
 */

$data = array("foo" => "bar");
$data_string = json_encode($data);

$ch = curl_init('http://postb.in/xxxxxx');
//$ch = curl_init('/post.php');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($data_string)
    )
);

$result = curl_exec($ch);
<?php

/**
 * php_http_stream.php
 *
 * using cURL lite. It use google's urlfetch service
 */

$url = 'http://postb.in/xxxxxx';
$data = array("foo" => "bar");
$data_string = json_encode($data);

$contentLength = strlen($data_string);

$headers = "accept: */*\r\n" .
    "Content-Type: application/json\r\n" .
    "Content-Length: $contentLength\r\n";

$context = [
    'http' => [
        'method' => 'POST',
        'header' => $headers,
        'content' => $data_string,
    ]
];
$context = stream_context_create($context);
$result = file_get_contents($url, false, $context);

And here is the trace report of those two call.

@0 ms
/php_http_stream.php
Summary
Name			RPCs	Total Duration (ms)
/curl_lite.php		1	450
/urlfetch.Fetch		1	333
Details
Timestamp		xxxx-xx-xx (xx:xx:xx.xxx)
Traced time 		333 ms
Untraced time 		117 ms

http/response/size	25
@0 ms
/curl.php
Summary
Name				RPCs	Total Duration (ms)
/curl.php			1	753
/remote_socket.Close		4	4
/remote_socket.Connect		10	157
/remote_socket.CreateSocket	4	10
/remote_socket.GetSocketOptions	1	1
/remote_socket.Poll		10	469
/remote_socket.Receive		2	2
/remote_socket.Send		2	2
/remote_socket.SetSocketOptions	1	1
Details
Timestamp	2017-xx-xx (xx:xx:xx.xxx)
Traced time 	646 ms
Untraced time 	107 ms

http/response/size		25

So what does it mean to you? It means a lot for me. Obviously cURL Lite is saving me couple milliseconds. And also I don’t need to be afraid of my “socket operation” quota that was used in cURL.

So in this, what should I say? file_get_contents() is more optimized? Of course, I am just talking how it’s performing for little external URL call with Google’s urlfetch service.

So if your application needs to interact with external service with less configuration and options, then I would prefer to use native PHP HTTP stream handler and make all external http call with file_get_contents() function. file_get_contents() use urlfetch service and you don’t need to enable cURL extension in your application.