如何将 Facebook PHP SDK 与 Laravel 5.4 集成?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42945596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to integrate Facebook PHP SDK with Laravel 5.4?
提问by Adam Ranganathan
I was searching for an easy way to integrate Facebook PHP SDKwith Laravel 5.4. Essentially, I wanted to make it available as a service within my Laravel app. Of course there is SammyK/LaravelFacebookSdkon 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.
我正在寻找一种将Facebook PHP SDK与 Laravel 5.4集成的简单方法。本质上,我想让它在我的 Laravel 应用程序中作为服务提供。当然github上有SammyK/LaravelFacebookSdk。但出于某种原因,我不想使用它。我觉得这个设置增加了另一个我必须理解的层,并在约束范围内工作。
There is also Laravel's own Socialitepackage. 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.
还有 Laravel 自己的Socialite包。但这本质上仅用于简单的身份验证。如果我想上传照片,评论,批量请求,这些都是不可能的。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.
由于没有简单的 SO 答案以最少的步骤直接集成 Facebook SDK,我想我会写这个。
回答by Adam Ranganathan
First, edit composer.json in the project's root folder to include the Facebook SDK:
首先,编辑项目根文件夹中的 composer.json 以包含 Facebook SDK:
{
"require" : {
"facebook/graph-sdk" : "~5.0"
}
}
Next run composer update
at shell prompt to pull in the sdk to the vendor folder.
接下来composer update
在 shell 提示符下运行以将 sdk 拉入供应商文件夹。
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 Developerswebsite.
现在我们想在我们的应用程序中使用 Facebook SDK 作为服务提供者。但在此之前,让我们设置我们的app_id
,app_secret
以及default_graph_version
向 Facebook API 发出请求时所需的参数。app_id 和 app_secret 可以通过在Facebook Developers网站上注册获得。
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 获得这些凭据,我们现在将编辑.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:
将 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'),
],
];
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.
通过这个简单的设置,我们现在可以config('facebook.config')
从应用程序的任何地方调用。它将返回数组以及从 .env 文件匹配的相关值。
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.
现在让我们将其设置为服务提供者,这样我们就不必在每次调用 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:
在 Laravel 5.4 中,打开文件app\Providers\AppServiceProvider.php
. 如果你没有这个文件或者想制作一个单独的文件,那么你可以在 shell 中创建一个新的服务提供者:
php artisan make:provider FacebookServiceProvider
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:
我们现在可以FacebookServiceProvider.php
在 Providers 文件夹中进行编辑。唯一的区别是我们需要在我们的config/app.php
文件中注册它。您将在$providers
数组末尾添加以下内容:
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:
要继续相关代码,在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 bindingsprovided by Laravel that you might want to check out.
您可能会注意到,我将类绑定为 a,singleton
因为对于我的应用程序,我想重用来自服务容器的相同对象。还有其他类型的绑定由Laravel前提是你可能要退房。
The whole code would look like below (I am using AppServiceProvider.php):
整个代码如下所示(我使用的是 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 injectthe facebook object wherever we would like to use it within our app. From here on one can simply follow instructions from Facebook documentationto call their API.'
就是这样。我们现在可以将 Facebook 作为应用程序的服务。我们现在可以将facebook 对象注入到我们想要在我们的应用程序中使用它的任何地方。从这里开始,人们可以简单地按照Facebook 文档中的说明调用他们的 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
在开始之前,我想提一提,我发现了一系列在Symfony的乡亲们撰写的文章中是非常有助于理解的概念Service Container
和Dependency Injection
。你可以在这里找到它们
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:
现在让我们尝试做一个基本的操作,比如从 facebook 检索一个人的名字。为了获取有关 facebook 用户的信息,我们需要通过发送基本参数来调用 Facebook API:用户的 facebook id 以及访问令牌。让我们分别称它们为uid
和access_token
。您需要使用 Facebook 的一种方法来检索这些:
- FacebookRedirectLoginHelper - when you want facebook authentication to happen from server side.
- FacebookCanvasHelper - for client side canvas based app authentication
- FacebookJavaScriptHelper - for client side javascript authentication
- FacebookRedirectLoginHelper - 当您希望从服务器端进行 facebook 身份验证时。
- FacebookCanvasHelper - 用于基于客户端画布的应用程序身份验证
- FacebookJavaScriptHelper - 用于客户端 javascript 身份验证
You can set up the kind of authentication you want by following the steps provided in Facebook's getting startedguide.
您可以按照 Facebook入门指南中提供的步骤设置所需的身份验证类型。
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
.
我的应用程序非常简单,所以我使用了客户端 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>
If your app has a different set of permissions needed from user, then edit the scope
field. For all available facebook permissions see here.
如果您的应用程序需要用户设置不同的权限,请编辑该scope
字段。有关所有可用的 facebook 权限,请参见此处。
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.
所以基本上,我的代码有一个登录按钮,当用户点击它时,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:
现在回到服务器端,因为我们uid
和access_token
我们可以将这些存储到数据库中,然后使我们的服务器给Facebook API的简单调用。设置路由 inroutes/web.php
接收表单数据:
Route::post('login', 'FacebookUser@store');
Make FacebookUser
controller at shell:
FacebookUser
在外壳上制作控制器:
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.
请注意,通过使用setDefaultAccessToken()
$fb 对象,可以在应用程序代码库的后续处理的任何部分中从服务容器中检索。$fb 可直接用于发出 Facebook API 请求。无需使用 app_id、app_secret 再次构建 $fb,也无需在当前请求-响应生命周期中为当前用户再次设置访问令牌。这是因为 $fb 是单例的,因此在当前请求-响应生命周期中为 Facebook 服务调用服务容器时会返回相同的对象。
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()
helper,因为它的工作与类中的对象上下文或静态函数无关。
$fb = resolve('Facebook\Facebook');