Monday, September 11, 2017

Inconsistent error with Facebook Graph API in PHP - Failed to connect to graph.facebook.com port 443: Connection timed out

Leave a Comment

I am integrating a Facebook login option on a site I'm working on and I've run into a bit of an issue when making calls to Facebook's API in PHP. The actual error I get is the following:

Failed to connect to graph.facebook.com port 443: Connection timed out

I've verified that the timeout value on the curl calls is correct, I tried checking the connection directly from the server's command prompt via SSH (pings correctly, the port seems to be open and processes are listening on it, etc). However, using a simple curl snippet I found online by others who had similar issues, I managed to test it easily and it seems like the issues is intermittent/inconsistent: sometimes it works flawlessly and quickly, and sometimes it loads for a few seconds and fails with the above error.

I highly doubt that the error is on Facebook's side, but I can't figure out what it is I'm doing wrong. I've worked with the Facebook SDK in PHP before and it's the first time I see this error.

Has anyone else faced this problem before and fixed it?

Quick note: it's the first time I work with Facebook in a project based on Symfony - don't think it's relevant in this case but throwing it out there just in case.

Relevant snippets:

$fb = new \Facebook\Facebook(['app_id' => '[withheld]',                                       'app_secret' => '[withheld]',                                       'default_graph_version' => 'v2.10',]); $fb->setDefaultAccessToken($accessToken); # Access token obtained from Facebook Login in JS, passed in post data.  try {     $basic_info_response = $fb->get('/me?fields=id,first_name,last_name,email,website');      if ($with_picture)         $profile_picture_response = $fb->get('/me/picture?width=720&height=720');      if ($with_friends)         $friends_response = $fb->get('/me/friends'); } catch(\Facebook\Exceptions\FacebookResponseException $e) {     echo 'Graph returned an error: ' . $e->getMessage();     exit; } catch(\Facebook\Exceptions\FacebookSDKException $e) {     echo 'Facebook SDK returned an error: ' . $e->getMessage();     exit; } 

In this code, it fails at any of the $fb->get() calls - not always the same one, sometimes on the first one, sometimes on the picture one, sometime on the friends one.

[Update]

The error is still happening, on around 90% of my calls. I tried to do curl calls directly on the server via SSH (curl -v graph.facebook.com) and got the two following results:

* Rebuilt URL to: graph.facebook.com/ *   Trying 31.13.91.2... * TCP_NODELAY set *   Trying 2a03:2880:f01b:1:face:b00c:0:1... * TCP_NODELAY set * Immediate connect fail for 2a03:2880:f01b:1:face:b00c:0:1: Network is unreachable * Connected to graph.facebook.com (31.13.91.2) port 80 (#0) > GET / HTTP/1.1 > Host: graph.facebook.com > User-Agent: curl/7.50.2 > Accept: */* >  < HTTP/1.1 400 Bad Request < WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "Unsupported get request. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api" < Access-Control-Allow-Origin: * < Pragma: no-cache < Cache-Control: no-store < x-fb-rev: 3274377 < Content-Type: application/json; charset=UTF-8 < x-fb-trace-id: A2OYZzFP3v8 < facebook-api-version: v2.4 < Expires: Sat, 01 Jan 2000 00:00:00 GMT < Vary: Accept-Encoding < X-FB-Debug: z9FEtq3Rlh8LyFn6pOIBZ5ZMCX+TY1jUD7iZ7ZRZ8/YGAsi035TbCP3qdBzqxDryvjJhKoKxnbAdvcxY/7r3Vg== < Date: Mon, 04 Sep 2017 19:51:40 GMT < Transfer-Encoding: chunked < Connection: keep-alive <  * Curl_http_done: called premature == 0 * Connection #0 to host graph.facebook.com left intact 

and

* Rebuilt URL to: graph.facebook.com/ *   Trying 31.13.91.2... * TCP_NODELAY set * Connected to graph.facebook.com (31.13.91.2) port 80 (#0) > GET / HTTP/1.1 > Host: graph.facebook.com > User-Agent: curl/7.50.2 > Accept: */* >  < HTTP/1.1 400 Bad Request < WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "Unsupported get request. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api" < Access-Control-Allow-Origin: * < Pragma: no-cache < Cache-Control: no-store < x-fb-rev: 3274377 < Content-Type: application/json; charset=UTF-8 < x-fb-trace-id: BrIDaH8D8D5 < facebook-api-version: v2.4 < Expires: Sat, 01 Jan 2000 00:00:00 GMT < Vary: Accept-Encoding < X-FB-Debug: tYvsf7Nn2PVnHFkV40UUddjQGKzPl8XKfdNeiqu1CXZck5WuUUlcG9hoCAZQrOX93uS19m2JpAEu9DJ/YhSIeg== < Date: Mon, 04 Sep 2017 19:54:54 GMT < Transfer-Encoding: chunked < Connection: keep-alive <  * Curl_http_done: called premature == 0 * Connection #0 to host graph.facebook.com left intact 

Does anyone have any more information or possible explanations for this issue?

3 Answers

Answers 1

As it turns out, a hardcoded CURLOPT_CONNECTTIMEOUT is set in Facebook's SDK in addition to the regular timeout - that seemed to be what was causing the issue. Whenever the connection between my server and the Facebook API was too slow (10s+), it would time out because 10s is the default value in the SDK.

I changed this value to cURL's default value for this option, which is 300, and it started working again. This value is set in Facebook's SDK in the FacebookCurlHttpClient class, in the openConnection method.

Now, for what causes the connection to be this slow at some times, that remains unknown, but at least it doesn't crash anymore when that happens.

You can redefine the methods of the SDK's cURL wrapper, as shown here: https://www.sammyk.me/how-to-inject-your-own-http-client-in-the-facebook-php-sdk-v5#customizing-the-curl-predefined-constants

For example, here's my redefined methods to allow much longer time periods before timeouts:

<?php  namespace AppBundle\Lib\Facebook;  class CustomCurlOptsHttpClient extends \Facebook\HttpClients\FacebookCurlHttpClient {     public function send($url, $method, $body, array $headers, $timeOut)     {         $timeOut *= 5;         return parent::send($url, $method, $body, $headers, $timeOut);     }      public function openConnection($url, $method, $body, array $headers, $timeOut)     {         $timeOut *= 5;         parent::openConnection($url, $method, $body, $headers, $timeOut);          $options = [             CURLOPT_CONNECTTIMEOUT => 300,         ];          $this->facebookCurl->setoptArray($options);     } } 

You can also use batch requests in the Facebook SDK if you have multiple requests to make one after the other. That will help speed up the process and prevent you from hitting to timeouts.

Hope that helps anyone else out there who's facing the same issue!

Answers 2

I can't comment, but can you provide some code? Will be happy to help and debug the issue.

Also, Facebook Graph API does return this error when something is blocking your request. For example,file_get_contents is blocked on a lot of shared hosting servers.

You should also handle the error.

Answers 3

Here is a sample snippet i am using and working fine for me.

<?php     include 'configs.php';     include_once "Facebook/autoload.php";     $swipe=1;     $goto=null;     try {         if (!isset($_SESSION['FACEBOOK_SESSION_TOKEN'])) {             $fb = new Facebook\Facebook([                 'app_id' => APP_ID,                 'app_secret' => APP_SECRET,                 'default_graph_version' => 'v2.5',             ]);             $helper = $fb->getRedirectLoginHelper();             $permissions = ["user_about_me","publish_actions" , "user_photos"];             $loginUrl = $helper->getLoginUrl( CALLBACK_URL ,  $permissions);             $swipe=0;          }     }     catch(Facebook\Exceptions\FacebookResponseException $e) {         echo 'Graph returned an error: ' . $e->getMessage();         exit;     } catch(Facebook\Exceptions\FacebookSDKException $e) {         echo 'Facebook SDK returned an error: ' . $e->getMessage();         exit;     }?> 

Config.php

<?php      define("CALLBACK_URL", "http://{domain}/facebookredirect.php");     define("RESULT_PAGE", "http://{domain}//profile.php");     define("LOGIN_URI" , "http://{domain}//index.html");     define("APP_ID" , "########");     define("APP_SECRET" ,"#####");    ?> 

Also, The Graph API doesn't have 100% uptime. Check your server as curl working properly.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment