Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

new Facebook SDK 4 throw exception about PHP_SESSION_ACTIVE in laravel

I wanted implement the new facebook API v 4.0.0 on my project laravel.

Setting all the necessary informations and credentials for access to my app, when is time to call the function for the login:

$helper = new FacebookRedirectLoginHelper('http://mywebsite.dev');
$loginUrl = $helper->getLoginUrl();

It throw me an exception

FacebookSDKException 'Session not active, could not store state.'

So I dig in to the SDK class of facebook on that line and there is a check about session precisely this one:

 if (session_status() !== PHP_SESSION_ACTIVE) {
      throw new FacebookSDKException(
        'Session not active, could not store state.'
      );
    }

Then I didn't know why this happen so i tried to put the same check on a clean route and see the result

Route::get('test',function() {

   if (session_status() !== PHP_SESSION_ACTIVE)
    {
        return "is not active";
    }

    return "is active";

});

And it return is not active why this happen? in this way I cannot use the new facebook API with laravel?

like image 466
Fabrizio Fenoglio Avatar asked May 06 '14 18:05

Fabrizio Fenoglio


3 Answers

Sharing how I implemented Facebook SDK V4 on Laravel 4.

Here's what I added on default composer.json

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php"
    ],
    "psr-4" : {
        "Facebook\\":"vendor/facebook/php-sdk-v4/src/Facebook/"
    }
},

Added Facebook initialization on my index.php, like this :

/*
|--------------------------------------------------------------------------
| Initialized Facebook PHP SDK V4
|--------------------------------------------------------------------------
|
*/

//Initialize
use Facebook\FacebookSession;
FacebookSession::setDefaultApplication(Config::get('facebook.AppId'),Config::get('facebook.AppSecret'));

And for the Session, Laravel doesn't use $_SESSION so you don't need to do session_start at all. For you to be able to use Laravel session on Facebook PHP SDK V4, you need to extend Facebook's FacebookRedirectLoginHelper class. Here's how how to subclass FacebookRedirectLoginHelper and overwrite Session handling.

class LaravelFacebookRedirectLoginHelper extends \Facebook\FacebookRedirectLoginHelper
{

  protected function storeState($state)
  {
    Session::put('state', $state);
  }

  protected function loadState()
  {
    $this->state = Session::get('state');
    return $this->state;
  }


  protected function isValidRedirect()
  {

    return $this->getCode() && Input::has('state')
        && Input::get('state') == $this->state;

  }



  protected function getCode()
  {
    return Input::has('code') ? Input::get('code') : null;
  }


  //Fix for state value from Auth redirect not equal to session stored state value
  //Get FacebookSession via User access token from code
  public function getAccessTokenDetails($app_id,$app_secret,$redirect_url,$code)
  {

        $token_url = "https://graph.facebook.com/oauth/access_token?"
          . "client_id=" . $app_id . "&redirect_uri=" . $redirect_url
          . "&client_secret=" . $app_secret . "&code=" . $code;

        $response = file_get_contents($token_url);
        $params = null;
        parse_str($response, $params);

        return $params;
   }


}

And one more step, you need to do a composer command to regenerate autoload files :

composer dump-autoload -o

Ok, if all goes right, you are now ready to start using the SDK, here's a sample

Here's an excerpt from one of my project classes :

namespace Fb\Insights;

//Facebook Classes
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookSDKException;


//Our Facebook Controller
use FbController;

class PagePosts extends \Facebook\GraphObject {

    /*
        Get Page Posts Impression
        https://developers.facebook.com/docs/graph-api/reference/v2.0/insights#post_impressions     


    */
    public static function getPagePostsImpressions($postid = null) {

        $fbctrl = new FbController();

        $metricNames = array(
            'post_impressions',
            'post_impressions_unique',
            'post_impressions_paid',
            'post_impressions_paid_unique',
            'post_impressions_fan',
            'post_impressions_fan_unique',
            'post_impressions_fan_paid',
            'post_impressions_fan_paid_unique',
            'post_impressions_organic',
            'post_impressions_organic_unique',
            'post_impressions_viral',
            'post_impressions_viral_unique',
            'post_impressions_by_story_type',
            'post_impressions_by_story_type_unique',
            'post_impressions_by_paid_non_paid',
            'post_impressions_by_paid_non_paid_unique'
        );

        $postsInsights = array();       
        $batch = array();
        $limit = $fbctrl->FacebookGraphDateLimit();     


        //craft our batch API call
        for($i=0; $i<count($metricNames); $i++) {       
            $batch[] = json_encode(array('method' => 'GET','relative_url' => $postid . '/insights/' . $metricNames[$i] . '?since=' . $limit['since'] . '&until=' . $limit['until'] ));
        }
        $params = array( 'batch'    => '[' . implode(',',$batch ) . ']' );      

        $session = new FacebookSession($fbctrl->userAccessToken);

        try {

            $res = (new FacebookRequest($session,'POST','/',$params))
                ->execute()
                ->getGraphObject();

        } catch(FacebookRequestException $ex) {
            //log this error
            echo $ex->getMessage();
        } catch(\Exception $ex) {
            //log this error
            echo $ex->getMessage();
        }

        //Collect data
        for($i=0; $i<count($batch); $i++) {

            $resdata = json_decode(json_encode($res->asArray()[$i]),true);

            $fbctrl->batchErrorDataChecker($resdata,$postsInsights,$metricNames[$i]);

        }

        return $postsInsights;

    }

Feel free comment or suggest so I can also improve my code. Happy coding.

like image 193
kaixersoft Avatar answered Oct 17 '22 23:10

kaixersoft


I solve extending that class and overwriting the following 2 methods that require native sessions.

    protected function storeState($state)
    {
        Session::put('facebook.state', $state);
    }

    protected function loadState()
    {
        return $this->state =  Session::get('facebook.state');
    }
like image 42
Fabrizio Fenoglio Avatar answered Oct 18 '22 00:10

Fabrizio Fenoglio


I used follow steps using Composer and had problem "Session not active, could not store state" so session_start() fixed my issue.

require_once './vendor/autoload.php';

use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;

session_start();
FacebookSession::setDefaultApplication('apid', 'appscret');
$helper = new FacebookRedirectLoginHelper("callbackurl", $apiVersion = NULL);
try {
    $session = $helper->getSessionFromRedirect();
} catch (FacebookRequestException $ex) {
    // When Facebook returns an error
} catch (\Exception $ex) {
    // When validation fails or other local issues
}
if (isset($session)) {

    $request = new FacebookRequest($session, 'GET', '/me');
    $response = $request->execute();
    $graphObject = $response->getGraphObject();
    var_dump($graphObject);
} else {
    echo '<a href="' . $helper->getLoginUrl() . '">Login with Facebook</a>';
}
like image 4
Ramratan Gupta Avatar answered Oct 17 '22 23:10

Ramratan Gupta