如何将Facebook PHP SDK与Laravel 5.4集成? [英] How to integrate Facebook PHP SDK with Laravel 5.4?

查看:67
本文介绍了如何将Facebook PHP SDK与Laravel 5.4集成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种将 Facebook PHP SDK 与Laravel 5.4集成的简便方法.本质上,我想在Laravel应用程序中将其作为服务提供.当然,在github上有 SammyK/LaravelFacebookSdk .但是由于某种原因,我不想使用它.我觉得安装程序增加了我必须理解的另一层,并且可以在限制条件下工作.

还有Laravel自己的 Socialite 软件包.但这本质上仅用于简单身份验证.如果我要上传照片,评论,进行批处理请求,则这些都是不可能的.社交名流不会将Facebook的PHP SDK用作依赖项.它使用Guzzle软件包仅向身份验证发出直接API请求.

由于没有简单的SO答案以最少的步骤直接集成Facebook SDK,所以我想写这篇文章.

解决方案

首先,在项目的根文件夹中编辑composer.json以包括Facebook SDK:

{
  "require" : {
    "facebook/graph-sdk" : "~5.0"
  }
}

下一步,在外壳程序提示符下运行composer update,将sdk插入供应商文件夹.

现在,我们想在我们的应用程序中使用Facebook SDK作为服务提供商.但是在此之前,让我们设置app_idapp_secretdefault_graph_version,这是向Facebook API发出请求时所需的参数.可以通过在 Facebook Developers 网站上注册来获取app_id和app_secret.

一旦有了来自Facebook的这些凭据,我们现在将在项目的根文件夹中编辑.env文件.将它们添加到末尾:

FACEBOOK_APP_ID=xxxxxxxxxxxxxxxx
FACEBOOK_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FACEBOOK_DEFAULT_GRAPH_VERSION=v2.8

用提供给您的值替换xxx...请注意,变量名只是我自己创建的.您可以随意命名.现在,我们必须使用这些变量来设置单独的配置文件.我们需要这样做,以便我们可以使用Laravel的 config()帮助函数来在应用中我们想要的任何地方检索值.因此,让我们在config文件夹中创建facebook.php并添加以下内容:

<?php

return [
    'config' => [
        'app_id' => env('FACEBOOK_APP_ID', null),
        'app_secret' => env('FACEBOOK_APP_SECRET', null),
        'default_graph_version' => env('FACEBOOK_DEFAULT_GRAPH_VERSION', 'v2.8'),
    ],
];

通过这种简单的设置,我们现在可以从应用程序中的任何位置调用config('facebook.config').它将返回数组以及从.env文件匹配的相关值.

现在让我们将其设置为服务提供商,这样就不必在每次调用Facebook API时都检索这些凭据并构建新的Facebook对象.

在Laravel 5.4中,打开文件app\Providers\AppServiceProvider.php.如果您没有此文件或想要创建一个单独的文件,则可以在shell上创建一个新的服务提供者:

php artisan make:provider FacebookServiceProvider

我们现在可以在Providers文件夹中编辑FacebookServiceProvider.php.唯一的区别是我们需要在我们的config/app.php文件中注册它.您将在$providers数组的末尾添加以下内容:

App\Providers\FacebookServiceProvider::class,

要继续相关代码,请在AppServiceProvider.php或新的FacebookServiceProvider.php中首先包括:use Facebook\Facebook;在顶部.然后在register() method中添加以下内容:

$this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });

您可能会注意到我将类绑定为singleton,因为对于我的应用程序,我想重用服务容器中的同一对象. Laravel提供了其他类型的绑定,您可能想签出. >

整个代码如下所示(我正在使用AppServiceProvider.php):

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Facebook\Facebook;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });
    }
}

就是这样.现在,我们可以使用Facebook作为该应用程序的服务.现在,我们可以在想使用的任何地方注入 facebook对象它在我们的应用程序中.从这里开始,您只需遵循 Facebook文档中的说明来调用其API. >

额外的东西,例如:

在继续之前,我想提一下,我发现Symfony的人们撰写的系列文章对理解Service ContainerDependency Injection的概念非常有帮助.您可以在此处查找

现在让我们尝试执行一项基本操作,例如从facebook检索一个人的名字.为了获取有关Facebook用户的信息,我们需要通过发送基本参数来调用Facebook API:用户的Facebook ID和访问令牌.我们分别称这些uidaccess_token.您将需要使用Facebook的一种方法来检索这些文件:

  1. FacebookRedirectLoginHelper-当您希望从服务器端进行Facebook身份验证时.
  2. FacebookCanvasHelper-用于基于客户端画布的应用程序身份验证
  3. FacebookJavaScriptHelper-用于客户端javascript身份验证

您可以按照Facebook 入门<指南.

我的应用程序非常简单,因此我使用了客户端javascript身份验证.我也一起使用jQuery.由于我使用Laravel的刀片引擎,因此我的javascript直接嵌入在视图文件中,因此我可以包含Laravel的csrf_token()并使用其他辅助功能,例如url().客户端javascript如下所示.请记住用您的值替换appId并将文件另存为login.blade.php.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<button id="btn-login" type="button" class="btn btn-primary btn-lg">
    <span> Login with Facebook</span>
</button>

<script>
$(document).ready(function() {
    $.ajaxSetup({ cache: true }); // since I am using jquery as well in my app
    $.getScript('//connect.facebook.net/en_US/sdk.js', function () {
        // initialize facebook sdk
        FB.init({
            appId: 'xxxxxxxxxxxxxxxx', // replace this with your id
            status: true,
            cookie: true,
            version: 'v2.8'
        });

        // attach login click event handler
        $("#btn-login").click(function(){
            FB.login(processLoginClick, {scope:'public_profile,email,user_friends', return_scopes: true});  
        });
    });

// function to send uid and access_token back to server
// actual permissions granted by user are also included just as an addition
function processLoginClick (response) {    
    var uid = response.authResponse.userID;
    var access_token = response.authResponse.accessToken;
    var permissions = response.authResponse.grantedScopes;
    var data = { uid:uid, 
                 access_token:access_token, 
                 _token:'{{ csrf_token() }}', // this is important for Laravel to receive the data
                 permissions:permissions 
               };        
    postData("{{ url('/login') }}", data, "post");
}

// function to post any data to server
function postData(url, data, method) 
{
    method = method || "post";
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", url);
    for(var key in data) {
        if(data.hasOwnProperty(key)) 
        {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", data[key]);
            form.appendChild(hiddenField);
         }
    }
    document.body.appendChild(form);
    form.submit();
}

</script>
</body>
</html>

如果您的应用具有用户所需的不同权限集,请编辑scope字段.对于所有可用的Facebook权限,请参见此处.

所以基本上,我的代码有一个登录按钮,当用户单击它时,javascript sdk会弹出并弹出一个登录窗口.用户登录后,我将数据发布回服务器,就像发布表单一样.

现在回到服务器端,因为我们有uidaccess_token,所以我们可以将它们存储到数据库中,然后从我们的服务器中简单地调用Facebook API.在routes/web.php中设置一条路线以接收表单数据:

Route::post('login', 'FacebookUser@store');

在外壳上创建FacebookUser控制器:

php artisan make:controller FacebookUser

控制器的代码如下:

<?php

namespace App\Http\Controllers;

use Request;
use App\User; // you need to define the model appropriately
use Facebook\Facebook;

class FacebookUser extends Controller
{
    public function store(Facebook $fb) //method injection
    {
        // retrieve form input parameters
        $uid = Request::input('uid');
        $access_token = Request::input('access_token');
        $permissions = Request::input('permissions');

        // assuming we have a User model already set up for our database
        // and assuming facebook_id field to exist in users table in database
        $user = User::firstOrCreate(['facebook_id' => $uid]); 

        // get long term access token for future use
        $oAuth2Client = $fb->getOAuth2Client();

        // assuming access_token field to exist in users table in database
        $user->access_token = $oAuth2Client->getLongLivedAccessToken($access_token)->getValue();
        $user->save();

        // set default access token for all future requests to Facebook API            
        $fb->setDefaultAccessToken($user->access_token);

        // call api to retrieve person's public_profile details
        $fields = "id,cover,name,first_name,last_name,age_range,link,gender,locale,picture,timezone,updated_time,verified";
        $fb_user = $fb->get('/me?fields='.$fields)->getGraphUser();
        dump($fb_user);
    }    
}

请注意,通过使用setDefaultAccessToken(),可以在应用程序代码库的后续处理的任何部分中从服务容器中检索$ fb对象. $ fb可直接用于发出Facebook API请求.无需使用app_id,app_secret再次构建$ fb,也无需在当前请求-响应生命周期中为当前用户再次设置访问令牌.这是因为$ fb是单例,因此在当前请求-响应生命周期中为Facebook服务调用服务容器时会返回相同的对象.

如果您无法通过方法注入来获取$ fb对象,则可以使用其他方式解决它的问题.我个人最喜欢使用resolve()助手,因为它可以工作,而与对象上下文或类中的静态函数无关.

$fb = resolve('Facebook\Facebook');

I was searching for an easy way to integrate Facebook PHP SDK with Laravel 5.4. Essentially, I wanted to make it available as a service within my Laravel app. Of course there is SammyK/LaravelFacebookSdk on github. But for some reason I didn't want to use it. I felt the setup was adding another layer that I would have to understand, and work within the constraints.

There is also Laravel's own Socialite package. But this is essentially for simple authentication only. If I want to upload photos, comments, make batch requests, these are not possible. Socialite does not use Facebook's PHP SDK as a dependency. It uses Guzzle package to make direct API requests for authentication only.

Since there is no simple SO answer to directly integrating Facebook SDK in least number of steps, I thought I'd write this.

解决方案

First, edit composer.json in the project's root folder to include the Facebook SDK:

{
  "require" : {
    "facebook/graph-sdk" : "~5.0"
  }
}

Next run composer update at shell prompt to pull in the sdk to the vendor folder.

Now we would like to use the Facebook SDK within our app as a service provider. But before doing that, let us setup our app_id, app_secret and default_graph_version which are parameters required while making requests to Facebook API. The app_id and app_secret can be obtained by registering at Facebook Developers website.

Once we have these credentials from Facebook, we would now edit .env file in the project's root folder. Add them to the end:

FACEBOOK_APP_ID=xxxxxxxxxxxxxxxx
FACEBOOK_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FACEBOOK_DEFAULT_GRAPH_VERSION=v2.8

Replace the xxx.. with the values provided to you. Note that the variable names are just my own creation. You can name them whatever you'd like. We would now have to use these variables to setup a separate config file. We need to do this so that we can use Laravel's config() helper function to retrieve the values wherever we want within the app. So let's create facebook.php in the config folder and add the following:

<?php

return [
    'config' => [
        'app_id' => env('FACEBOOK_APP_ID', null),
        'app_secret' => env('FACEBOOK_APP_SECRET', null),
        'default_graph_version' => env('FACEBOOK_DEFAULT_GRAPH_VERSION', 'v2.8'),
    ],
];

With this simple setup we can now call config('facebook.config') from anywhere in the app. It would return the array along with the relevant values matched from the .env file.

Now let us set this up as a service provider so that we don't have to retrieve these credentials and build new Facebook object every time we are making a call to the Facebook API.

In Laravel 5.4, open the file app\Providers\AppServiceProvider.php. If you don't have this file or want to make a separate one, then you could create a new service provider at shell:

php artisan make:provider FacebookServiceProvider

We can now edit FacebookServiceProvider.php in the Providers folder instead. The only difference is that we need to register this in the our config/app.php file. You would add the following at the end of the $providers array:

App\Providers\FacebookServiceProvider::class,

To continue with the relevant code, in either AppServiceProvider.php or our new FacebookServiceProvider.php we first include: use Facebook\Facebook; at the top. Then within the register() method add the following:

$this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });

You might notice that I am binding the class as a singleton since for my app I would like to reuse the same object from the service container. There are other types of bindings provided by Laravel that you might want to check out.

The whole code would look like below (I am using AppServiceProvider.php):

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Facebook\Facebook;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });
    }
}

That's about it. We now have Facebook available as a service to the app. We can now inject the facebook object wherever we would like to use it within our app. From here on one can simply follow instructions from Facebook documentation to call their API.'

Extra Stuff, just as an example:

Before proceeding, I'd like to mention that I found the series of posts written by the folks at Symfony to be very helpful to understand the concepts of Service Container and Dependency Injection. You can find them here

Let's now try to do a basic operation such as retrieving a person's name from facebook. In order to get information about a facebook user we would need to call the Facebook API by sending basic parameters: user's facebook id along with an access token. Let's call these uid and access_token respectively. You would need to retrieve these using one of Facebook's methods:

  1. FacebookRedirectLoginHelper - when you want facebook authentication to happen from server side.
  2. FacebookCanvasHelper - for client side canvas based app authentication
  3. FacebookJavaScriptHelper - for client side javascript authentication

You can set up the kind of authentication you want by following the steps provided in Facebook's getting started guide.

My app is pretty simple and so I went with client side javascript authentication. I also use jquery alongside. Since I use Laravel's blade engine, my javascript was embedded in the view file directly so that I could include Laravel's csrf_token() and use other helper functions such as url(). The client side javascript looks like below. Remember to replace appId with your values and save the file as login.blade.php.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<button id="btn-login" type="button" class="btn btn-primary btn-lg">
    <span> Login with Facebook</span>
</button>

<script>
$(document).ready(function() {
    $.ajaxSetup({ cache: true }); // since I am using jquery as well in my app
    $.getScript('//connect.facebook.net/en_US/sdk.js', function () {
        // initialize facebook sdk
        FB.init({
            appId: 'xxxxxxxxxxxxxxxx', // replace this with your id
            status: true,
            cookie: true,
            version: 'v2.8'
        });

        // attach login click event handler
        $("#btn-login").click(function(){
            FB.login(processLoginClick, {scope:'public_profile,email,user_friends', return_scopes: true});  
        });
    });

// function to send uid and access_token back to server
// actual permissions granted by user are also included just as an addition
function processLoginClick (response) {    
    var uid = response.authResponse.userID;
    var access_token = response.authResponse.accessToken;
    var permissions = response.authResponse.grantedScopes;
    var data = { uid:uid, 
                 access_token:access_token, 
                 _token:'{{ csrf_token() }}', // this is important for Laravel to receive the data
                 permissions:permissions 
               };        
    postData("{{ url('/login') }}", data, "post");
}

// function to post any data to server
function postData(url, data, method) 
{
    method = method || "post";
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", url);
    for(var key in data) {
        if(data.hasOwnProperty(key)) 
        {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", data[key]);
            form.appendChild(hiddenField);
         }
    }
    document.body.appendChild(form);
    form.submit();
}

</script>
</body>
</html>

If your app has a different set of permissions needed from user, then edit the scope field. For all available facebook permissions see here.

So basically, my code has a login button and when user clicks it, the javascript sdk kicks in and pops up a login window. Once user logs in, I post the data back to server as if a form is being posted.

Now back to server side, since we have uid and access_token we can store these to database and then make a simple call to Facebook API from our server. Set up a route in routes/web.php to receive the form data:

Route::post('login', 'FacebookUser@store');

Make FacebookUser controller at shell:

php artisan make:controller FacebookUser

And the controller's code is as follows:

<?php

namespace App\Http\Controllers;

use Request;
use App\User; // you need to define the model appropriately
use Facebook\Facebook;

class FacebookUser extends Controller
{
    public function store(Facebook $fb) //method injection
    {
        // retrieve form input parameters
        $uid = Request::input('uid');
        $access_token = Request::input('access_token');
        $permissions = Request::input('permissions');

        // assuming we have a User model already set up for our database
        // and assuming facebook_id field to exist in users table in database
        $user = User::firstOrCreate(['facebook_id' => $uid]); 

        // get long term access token for future use
        $oAuth2Client = $fb->getOAuth2Client();

        // assuming access_token field to exist in users table in database
        $user->access_token = $oAuth2Client->getLongLivedAccessToken($access_token)->getValue();
        $user->save();

        // set default access token for all future requests to Facebook API            
        $fb->setDefaultAccessToken($user->access_token);

        // call api to retrieve person's public_profile details
        $fields = "id,cover,name,first_name,last_name,age_range,link,gender,locale,picture,timezone,updated_time,verified";
        $fb_user = $fb->get('/me?fields='.$fields)->getGraphUser();
        dump($fb_user);
    }    
}

Note that by using setDefaultAccessToken() the $fb object can be retrieved from service container in any part of subsequent processing of app's codebase. $fb can be used directly to make a Facebook API request. No need to build $fb again using app_id, app_secret and no need to set access token again for the current user during the current request-response lifecycle. This is because $fb is singleton and so the same object is returned when service container is called for Facebook service during current request-response lifecycle.

If you are unable to do method injection to get the $fb object, then there are other ways of resolving it. My personal favourite is to use the resolve() helper since it works irrespective of object context or static function in a class.

$fb = resolve('Facebook\Facebook');

这篇关于如何将Facebook PHP SDK与Laravel 5.4集成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆