Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using CodeIgniter + Facebook PHP SDK: getUser() always returns 0

I am attempting to use the Facebook PHP SDK in conjunction with CodeIgniter to allow users to login to my site using Facebook Connect. No matter what I try, getUser() always returns 0, even after (apparently) successful authentication via Facebook.

CodeIgniter version: 2.1.3

Facebook PHP SDK version: 3.2.2

I have created a config file, facebook.php, in the application/config folder and I am loading the Facebook PHP SDK via CodeIgniter's $this->load->library(...) method. The library is indeed getting loaded and I can successfully call many of the get...() methods including getAccessToken(), getAppId() and getAppSecret(), all of which return their expected values.

Here is a stripped down version of my login controller: (note that I also provide an alternate method of logging in via email, hence the CodeIgniter session code sprinkled throughout)

class Login extends CI_Controller {

    public function __construct()
    {
        //Call parent constructor
        parent::__construct();

        //Magic sauce - not sure if this is required but a lot of other people
        //are recommending it to be included (happy to remove it if necessary)
        parse_str($_SERVER['QUERY_STRING'], $_REQUEST);

        //Load facebook library
        $facebook_config = $this->load->config('facebook');
        $this->load->library('facebook', $facebook_config);
    }

   public function index()
    {
        //Check if user is logged in
        $user_id = $this->session->userdata('user_id');
        $is_logged_in = $this->session->userdata('is_logged_in');

        if(($is_logged_in) && ($user_id != 0)) {
            //Logged in - redirect to game
            redirect('game');
        } else {
            //Not logged in
            //Get facebook login url
            $facebook_data = array(
                'redirect_uri' => 'hxxp://xxxxxxxx.com/facebook_login/',
                'scope' => 'email'
            );
            $data['facebook_login_url'] = $this->facebook->getLoginUrl($facebook_data);
            //Redirect to login form
            $this->load->view('login/login_form', $data);
        }
    }

    public function facebook_login()
    {
        //Always returns 0!! Even after authenticating via facebook!
        $facebook_user_id = $this->facebook->getUser();

        if ($facebook_user_id) {
            try {
                $user_profile = $this->facebook->api('/me');
                print_r($user_profile);
            } catch (FacebookApiException $e) {
                echo $e->getMessage();
            }
        } else {
            echo "Could not log in with Facebook";
        }
    }
}

The stripped down view (login_form.php) is as follows:

<html>
    <head>
        <title>Facebook Connect Test</title>
    </head>
    <body>
        <a href='<? echo $facebook_login_url; ?>'>Login with Facebook</a>
   </body>
</html>

I have a route that redirects hxxp://xxxxxxxx.com/facebook_login to the login/facebook_login method, which is working.

I am running this code on a live development server.

My current flow is as follows:

  1. Load hxxp://xxxxxxxx.com/ (Routes to login controller, which loads login_form view)
  2. Click "Login with Facebook" link
  3. Facebook asks me to login (which I do)
  4. Facebook asks me to give permission to my app (which I do)
  5. Facebook redirects me to the url specified in the redirect_uri parameter, which is identical to the one on the app settings page

And here's where it all goes wrong. The $this->facebook->getUser() method ALWAYS returns 0, even after authentication.

I have been scouring the Facebook developer documentation and everywhere else on the internet I can think of trying to find an answer to this. I have come across many posts similar to this and have tried to apply the solutions suggested, but to no avail.

What am I doing wrong?

like image 743
Max Power Avatar asked Jun 02 '26 15:06

Max Power


2 Answers

The getCode() method in base_facebook.php uses the $_REQUEST global to store data. PHP 5.3.0 and greater uses the "request_order" param in php.ini, and by default $_REQUEST does not contain Cookie variables.

Per php.net (http://php.net/manual/en/ini.core.php#ini.request-order):

"This directive describes the order in which PHP registers GET, POST and Cookie variables into the _REQUEST array. Registration is done from left to right, newer values override older values.

If this directive is not set, variables_order is used for $_REQUEST contents.

Note that the default distribution php.ini files does not contain the 'C' for cookies, due to security concerns."

So it looks like your options are to modify the getCode() method like Max Power did above, or update your php.ini and add the "C" value to the request_order setting.

like image 54
gbruins Avatar answered Jun 04 '26 05:06

gbruins


I managed to solve my problem. The questions linked to by Qweick and Stéphane Bruckert had the solution. The problem lies in the getCode() function of the base_facebook.php file.

The getCode() function needs to be modified. The modifications I used are listed below.

Existing non-working code:

protected function getCode() {
    if (isset($_REQUEST['code'])) {
        if ($this->state !== null &&
                isset($_REQUEST['state']) &&
                $this->state === $_REQUEST['state']) {

            // CSRF state has done its job, so clear it
            $this->state = null;
            $this->clearPersistentData('state');
            return $_REQUEST['code'];
        } else {
            self::errorLog('CSRF state token does not match one provided.');
            return false;
        }
    }

    return false;
}

Modified working code:

protected function getCode() {
    $server_info = array_merge($_GET, $_POST, $_COOKIE);

    if (isset($server_info['code'])) {
        if ($this->state !== null &&
                isset($server_info['state']) &&
                $this->state === $server_info['state']) {

            // CSRF state has done its job, so clear it
            $this->state = null;
            $this->clearPersistentData('state');
            return $server_info['code'];
        } else {
            self::errorLog('CSRF state token does not match one provided.');
            return false;
        }
    }

    return false;
}

The getUser() call now returns a valid user Id and the Facebook API calls now return valid data.

Thanks to everyone that helped point me in the right direction!

like image 36
Max Power Avatar answered Jun 04 '26 06:06

Max Power



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!