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

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

问题描述

我一直在寻找一种将 Facebook PHP SDK 与 Laravel 5.4 集成的简单方法.本质上,我想让它在我的 Laravel 应用程序中作为服务提供.当然,github 上有 SammyK/LaravelFacebookSdk.但出于某种原因,我不想使用它.我觉得这个设置增加了另一个我必须理解的层,并在限制范围内工作.

还有 Laravel 自己的 Socialite 包.但这本质上仅用于简单的身份验证.如果我想上传照片,评论,批量请求,这些都是不可能的.Socialite 不使用 Facebook 的 PHP SDK 作为依赖项.它使用 Guzzle 包来发出仅用于身份验证的直接 API 请求.

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

解决方案

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

<代码>{要求" : {facebook/graph-sdk":~5.0"}}

接下来在 shell 提示下运行 composer update 以将 sdk 拉入供应商文件夹.

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

一旦我们从 Facebook 获得这些凭据,我们现在将编辑项目根文件夹中的 .env 文件.将它们添加到最后:

FACEBOOK_APP_ID=xxxxxxxxxxxxxxxxFACEBOOK_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFACEBOOK_DEFAULT_GRAPH_VERSION=v2.8

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

['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 中,打开文件 appProvidersAppServiceProvider.php.如果你没有这个文件或者想制作一个单独的文件,那么你可以在 shell 中创建一个新的服务提供者:

php artisan make:provider FacebookServiceProvider

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

AppProvidersFacebookServiceProvider::class,

要继续使用相关代码,在 AppServiceProvider.php 或我们新的 FacebookServiceProvider.php 中,我们首先包括:use FacebookFacebook; 在顶部.然后在 register() 方法 中添加以下内容:

$this->app->singleton(Facebook::class, function ($app) {返回新的 Facebook(config('facebook.config'));});

您可能会注意到,我将类绑定为 singleton,因为对于我的应用程序,我想重用来自服务容器的相同对象.您可能需要查看 Laravel 提供的其他类型的绑定.>

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

app->singleton(Facebook::class, function ($app) {返回新的 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.

<头><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css"/><身体><button id="btn-login" type="button" class="btn btn-primary btn-lg"><跨度>使用 Facebook 登录</span><脚本>$(document).ready(function() {$.ajaxSetup({ cache: true });//因为我也在我的应用程序中使用 jquery$.getScript('//connect.facebook.net/en_US/sdk.js', function () {//初始化facebook sdkFB.init({appId: 'xxxxxxxxxxxxxxxx',//用你的 id 替换它状态:真实,饼干:是的,版本:'v2.8'});//附加登录点击事件处理程序$("#btn-login").click(function(){FB.login(processLoginClick, {scope:'public_profile,email,user_friends', return_scopes: true});});});//将 uid 和 access_token 发送回服务器的函数//用户授予的实际权限也作为附加项包括在内函数 processLoginClick(响应){var uid = response.authResponse.userID;var access_token = response.authResponse.accessToken;var 权限 = response.authResponse.grantedScopes;var 数据 = { uid:uid,访问令牌:访问令牌,_token:'{{ csrf_token() }}',//这对 Laravel 接收数据很重要权限:权限};postData("{{ url('/login') }}", data, "post");}//将任何数据发布到服务器的函数函数 postData(网址,数据,方法){方法 = 方法 ||邮政";var form = document.createElement("form");form.setAttribute("方法", 方法);form.setAttribute("action", url);for(数据中的var键){if(data.hasOwnProperty(key)){var hiddenField = document.createElement("输入");hiddenField.setAttribute("类型", "隐藏");hiddenField.setAttribute("name", key);hiddenField.setAttribute("value", data[key]);form.appendChild(hiddenField);}}document.body.appendChild(form);表单提交();}

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

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

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

Route::post('登录', 'FacebookUser@store');

在 shell 中制作 FacebookUser 控制器:

php artisan make:controller FacebookUser

控制器的代码如下:

 $uid]);//获取长期访问令牌以备将来使用$oAuth2Client = $fb->getOAuth2Client();//假设access_token 字段存在于数据库的users 表中$user->access_token = $oAuth2Client->getLongLivedAccessToken($access_token)->getValue();$user->save();//为所有未来对 Facebook API 的请求设置默认访问令牌$fb->setDefaultAccessToken($user->access_token);//调用 api 来检索个人的 public_profile 详细信息$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();转储($fb_user);}}

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

如果无法通过方法注入获取$fb对象,那么还有其他方式解决它.我个人最喜欢使用 resolve() 帮助器,因为它的工作与类中的对象上下文或静态函数无关.

$fb = resolve('FacebookFacebook');

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 appProvidersAppServiceProvider.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:

AppProvidersFacebookServiceProvider::class,

To continue with the relevant code, in either AppServiceProvider.php or our new FacebookServiceProvider.php we first include: use FacebookFacebook; 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 AppProviders;

use IlluminateSupportServiceProvider;
use FacebookFacebook;

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 AppHttpControllers;

use Request;
use AppUser; // you need to define the model appropriately
use FacebookFacebook;

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('FacebookFacebook');

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

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