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.

Android – Get current location of user by using LocationManager API

Sometimes we need to get user current location from Android device. Its very simple while we use LocationManager API of Android. We just need a custom location manager and a location listener with  necessary permission in Manifest.xml file.  lets see how to do it.

Step-1: Follow the code in manifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.previewtechs.bornolipi">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <uses-feature android:name="android.hardware.location.gps" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.NoActionBar">
        <activity android:name=".MainActivity" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

  
        <activity android:name=".HomeActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
</manifest>

Step-2: Follow these code for TestLocationManager.Java

public class TestLocationManager {

private int minDistanceForUpdateLocation;
private int minTimeForUpdateLocastion;
LocationManager locationManager;
TestLocationListener locationListener;
Context ctx;
private boolean isGPSProviderEnable, isNetworkProviderEnable;

//COnstructor
public TestLocationManager(Context ctx){
this.ctx = ctx;
}

public TestLocationManager(Context ctx, int minTimeForUpdateLocastion, int minDistanceForUpdateLocation ){
this.minDistanceForUpdateLocation =minDistanceForUpdateLocation;
this.minTimeForUpdateLocastion= minTimeForUpdateLocastion;
this.ctx = ctx;
}

//Set Location Manager and Listener
public void setLocationManagerAndListener(){
this.locationListener = new TestSendLocationListener(this.ctx);
this.locationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);

isGPSProviderEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkProviderEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

if(isGPSProviderEnable){
this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTimeForUpdateLocastion, minDistanceForUpdateLocation, locationListener);
}else if(isNetworkProviderEnable){
this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, minTimeForUpdateLocastion, minDistanceForUpdateLocation, locationListener);
}

}

//Get Minimum Distance for updating location
public int getMinDistanceForUpdateLocation() {
return minDistanceForUpdateLocation;
}
//Set Minimum Distance for updating location
public void setMinDistanceForUpdateLocation(int minDistanceForUpdateLocation) {
this.minDistanceForUpdateLocation = minDistanceForUpdateLocation;
}

//Get Minimum Time for updating location
public int getMinTimeForUpdateLocastion() {
return minTimeForUpdateLocastion;
}

//Set Minimum Time for updating location
public void setMinTimeForUpdateLocastion(int minTimeForUpdateLocastion) {
this.minTimeForUpdateLocastion = minTimeForUpdateLocastion;
}
}

Step:3- Follow these code for TestLocationListener.java

public class TestLocationListener implements LocationListener {

private double lat, lng, alt, acc, time;
Context ctx;
ConnectivityDetector connectivityDetector;

public TestLocationListener(Context ctx){
this.ctx = ctx;
}

@Override
public void onLocationChanged(Location location) {
this.lat = location.getLatitude();
this.lng = location.getLongitude();
this.alt = location.getAltitude();
this.acc = location.getAccuracy();
this.time = location.getTime();

Toast.makeText(ctx, “Lat : “+this.lat+” \n Lng : “+this.lng+” \nAlt : “+this.alt+” \n Acc : “+this.acc+” \n Time : “+this.time, Toast.LENGTH_LONG).show();

//to whatever you want with location

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}
}

Step:4 – There is the code for MainActivity.java . where we will implement our TesetLocationManager and TestLocationListener .

public class MainActivity extends AppCompatActivity{

    private Toolbar toolbar;
    private Location mLastLocation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

 // setup toolbar
 toolbar = (Toolbar) findViewById(R.id.toolbar);
 setSupportActionBar(toolbar);


 navigationView = (NavigationView) findViewById(R.id.menu_main);
 navigationView.setNavigationItemSelectedListener(this);
 //Set default item selected on nivigation
 navigationView.getMenu().performIdentifierAction(R.id.menu_home, 0);
 setTitle("");

 //get real time permission for location
 getPermissionForLocation();
 }

 protected void onStart() {
 super.onStart();
 }

 protected void onStop() {
 super.onStop();
 }

 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 switch (requestCode) {
 case ConstantCollection.PERMISSION_REQUEST_LOCATION_COARSE: {
 // If request is cancelled, the result arrays are empty.
 if (grantResults.length > 0
 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 Toast.makeText(getApplicationContext(), "Permission granted", Toast.LENGTH_LONG).show();

 //setup location manager and listener
 setupLocationManagerAndListener();

 //get last known location
 //mLastLocation = getUserLocation();
 //storeUserLocation(mLastLocation);


 } else {
 MainActivity.this.finish();
 Toast.makeText(getApplicationContext(), "Permission denied! You must have to allow this permission", Toast.LENGTH_LONG).show();
 }
 return;
 }
 }
 }


 //Check Permission and get call log list
 private void getPermissionForLocation() {
 // Here, thisActivity is the current activity
 if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION)
 != PackageManager.PERMISSION_GRANTED
 && ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
 != PackageManager.PERMISSION_GRANTED) {

 // Should we show an explanation?
 if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
 Manifest.permission.ACCESS_COARSE_LOCATION) ||
 ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
 Manifest.permission.ACCESS_FINE_LOCATION)) {

 // Show an expanation to the user *asynchronously* -- don't block
 // this thread waiting for the user's response! After the user
 // sees the explanation, try again to request the permission.

 ActivityCompat.requestPermissions(MainActivity.this,
 new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
 ConstantCollection.PERMISSION_REQUEST_LOCATION_COARSE);

 } else {
 // No explanation needed, we can request the permission.
 ActivityCompat.requestPermissions(MainActivity.this,
 new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
 ConstantCollection.PERMISSION_REQUEST_LOCATION_COARSE);

 }
 } else {
 //Check permission for location
 setupLocationManagerAndListener();
 
 }
 }

 //setup location location manager and listener
 private void setupLocationManagerAndListener(){
 TestLocationManager locationManager = new TestLocationManager(MainActivity.this, 10000, 10);
 TestLocationListener locationListener = new TestLocationListener(getApplicationContext());
 locationManager.setLocationManagerAndListener();
 }

}

We can find our expected location on onLocationChanged() method of TestLocationListener.java file. So i think you got your expected result. If you have any question then put it on comment box. Thanks.

Create Custom Filter in Twig Inside Slim Framework

As we know twig is the most powerful, fastest, secured, modern templating engine. It comes with a lot’s of built-in features like block, extends, import, filter etc (see the reference docs). Also, it has the option to add the custom filter based on your need. So the developers can create their own filter based on their needed. This article will help you to do that. Here I am using Twig with Slim framework (version 3.X).

An example Custom Filter:

https://gist.github.com/sohelrana820/be49697a0b246ba7fc88d27f5a9719dc

From the above snippet, you can see a filter is created called ‘twig_custom_filter‘ and then added that into the twig environment.  To use this filter into view just call it. (e.g. {{some_variable | twig_custom_filter}})

 

Getting Website’s Network Information in PHP

Sometimes we need to know website’s network information while we developing an application. Here I have included a code snippet for getting network information of a website (domain).

https://gist.github.com/sohelrana820/33db071427e14d571e9f9ff857a00df5

You can use this snippet for getting network information of a website.

PHP Recursive Function with Example

In a sentence, The recursive function is a function that calling by itself. That means if a function/method keeps calling itself that called recursive function. The recursive function is useful when something needs to do again and again until they terminated.

The skeleton of Recursive Function:

A recursive function must have to call by itself. And there also have to have a terminating condition, causes if there is no condition for terminating then it goes to infinity.

Example:

Factorials are a very easy maths concept. I using a recursive function to implement the factorial concept. Suppose you are written like 5! and this means 5 * 4 * 3 * 2 * 1. So 6! is 720 and 4! is 24.