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.

还有拉维尔自己的Socialite套餐.但这基本上只用于简单的身份验证.如果我想上传照片、 comments 、批量请求,这些都是不可能的.Socialite不使用Facebook的PHP SDK作为依赖项.它使用Guzzle包直接请求API进行身份验证.

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

推荐答案

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

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

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

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

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

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.

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

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,

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

$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.

整个代码如下所示(我使用的是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 documentation中的说明调用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

现在让我们试着做一个基本的操作,比如从facebook检索一个人的名字.为了获取facebook用户的信息,我们需要通过发送基本参数来调用facebook API:用户的facebook id和访问令牌.让我们分别称之为uidaccess_token.你需要使用Facebook的一种方法来检索这些信息:

  1. FacebookRedirectLoginHelper - when you want facebook authentication to happen from server side.
  2. FacebookCanvasHelper-用于基于客户端画布的应用程序身份验证
  3. FacebookJavaScriptHelper-用于客户端javascript身份验证

你可以按照Facebook的getting started指南中提供的步骤设置你想要的身份验证类型.

我的应用程序非常简单,所以我使用了客户端javascript身份验证.我还同时使用jquery.因为我使用了Laravel的blade引擎,所以我的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>

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

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

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);
    }    
}

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

如果您无法执行方法注入来获取$fb对象,那么有other ways of resolving it个.我个人最喜欢使用resolve()helper,因为它与类中的对象上下文或静电函数无关.

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

Laravel相关问答推荐

Livewire 3软件包开发

Laravel phpunit 测试失败并出现 PDOException:SQLSTATE[HY000]:一般错误:1 接近0:语法错误

阻止用户查看其他用户正在查看的内容的最佳方法是什么?

在 Laravel 中设置多个 Vue 组件的问题

为什么 Laravel 5 会自动更新我的日期字段?

Laravel 5.1 是否与 PHP 7 兼容

Laravel 5.x 中 onUpdate / onDelete 的可用操作

Laravel 5 - 在控制器文件中为多个路由定义中间件

如何在 Eloquent 上设置条件关系

laravel Blade中多选选项中的旧值

如何访问 Carbon 对象类型?

Laravel 在特定文件夹中创建迁移文件

Laravel 中的填充方法不起作用?

如何在 Laravel 5 中的每个相关输入字段旁边显示验证错误?

Laravel/PHPUnit:断言 json 元素存在而不定义值

如何判断是否在laravel中使用了分页

Laravel 单元测试依赖注入

如何访问 Laravel 集合中的第 n 个项目?

Laravel:如何在 PhpUnit 上启用堆栈跟踪错误

为什么`catch (Exception $e)` 不处理这个`ErrorException`?