horde/service_facebook
Composer 安装命令:
composer require horde/service_facebook
包简介
Facebook Graph API client library
README 文档
README
A modern PSR-4 client for Facebook's Graph API. Targets Graph v25 for now but is ready to actively support for a rolling window of prior versions once graph v26 is out.
Integrates with horde/oauth for OAuth2/OIDC flows and horde/jwt for
id_token verification.
Status: Partial
The legacy PSR-0 tree under
lib/Horde/Service/Facebook/ targets Facebook's REST API (retired
2020) and FQL (retired 2016) and does not work against modern Facebook.
The new PSR-4 tree under src/ is the supported surface. New and updated code
should use Horde\Service\Facebook\FacebookApiClient
The legacy Horde_Service_Facebook classes are kept around to prevent code breaking on "unknown class", i.e. when it shipped the old client as a side concern and didn't really exercise facebook REST API.
Installation
composer require horde/service_facebook
Requires PHP 8.1+. The library is strict-PSR at runtime. Bring your own
PSR-18 client (any conforming implementation. horde/http, Guzzle,
Symfony HttpClient). Bring your own PSR-17 request and stream
factories. The Facebook client wires everything through them.
Batteries-included wiring with horde/http:
composer require horde/service_facebook horde/http
Quick Start
Fetch the current user's profile:
use Horde\Http\Client; use Horde\Http\RequestFactory; use Horde\Http\StreamFactory; use Horde\OAuth\Client\AuthenticatedHttpClient; use Horde\OAuth\Client\TokenSet; use Horde\Service\Facebook\FacebookApiClient; // Bearer-authenticated PSR-18 client. $tokenSet = new TokenSet( accessToken: $userAccessToken, tokenType: 'Bearer', expiresAt: null, refreshToken: null, scope: null, ); $httpClient = new AuthenticatedHttpClient(new Client(), $tokenSet); $fb = FacebookApiClient::create( httpClient: $httpClient, requestFactory: new RequestFactory(), streamFactory: new StreamFactory(), ); $me = $fb->getMe(['id', 'name', 'email']); echo $me->name; // "Ada Lovelace" echo $me->email; // "ada@example.org" (if the token holds the email scope)
Version Pinning
The default version comes from GraphApiVersion::default() (currently
v25.0). To pin to an older supported version:
use Horde\Service\Facebook\Graph\GraphApiVersion; $fbV24 = $fb->withVersion(GraphApiVersion::V24_0); $events = iterator_to_array($fbV24->listMyUpcomingEvents());
withVersion() returns a new immutable client. The original client
remains pinned to its previous version. You can hold two client
instances side by side without interference.
Supported versions are exposed as enum cases:
GraphApiVersion::V25_0(current default)GraphApiVersion::V24_0GraphApiVersion::V23_0GraphApiVersion::V22_0
Note: The older APIs aren't really supported - This feature is designing against a foreaseeable shift on facebook side to V26 or V27 while still supporting V25 for a reasonable time.
Attempting to pass a version the library doesn't ship is a
compile-time error. You cannot construct an unknown enum case.
Whether Meta still accepts your pinned version on the wire is Meta's
business. If they reject the request you get a GraphErrorException
like any other server error.
See doc/VERSIONING.md for how new Facebook versions land in the library and when old ones eventually leave.
API Methods
The MVP surface is deliberately narrow. The endpoints Meta still supports for third-party apps on modern Graph API, plus the token-management primitives.
getMe(array $fields = []): User
GET /me. Empty $fields defers to Meta's default projection. Include
fields you want back. email requires the email scope. Name
breakdown requires public_profile. And so on. Meta silently omits
fields the token cannot see rather than raising an error, so a
stripped-down response usually means a stripped-down scope grant.
listMyUpcomingEvents(?Cursor $cursor = null, array $fields = []): PagedIterator
GET /me/events. Requires the user_events permission on the access
token (App Review gated by Meta post-2018). Returns a lazy iterator
over Event value objects. Paging is handled transparently. The
iterator walks Meta's paging.next URLs so callers get every page or
break out early to bound cost.
use Horde\Service\Facebook\Graph\Pagination\Cursor; foreach ($fb->listMyUpcomingEvents(new Cursor(limit: 25)) as $event) { echo $event->name, ' @ ', $event->startTime->format('Y-m-d H:i'), "\n"; }
listMyPermissions(): list<Permission>
GET /me/permissions. Meta returns a small, unpaginated list. This
method materialises the full array of Permission value objects. Each
has name(), status(), and an isGranted() convenience.
foreach ($fb->listMyPermissions() as $perm) { if (!$perm->isGranted()) { echo $perm->name(), ' status: ', $perm->status(), "\n"; } }
revokePermission(string $permission): void
DELETE /me/permissions/{permission}. Revokes a previously-granted
scope from the current token. The token itself remains valid but loses
access to the revoked scope. Meta returns {"success":true} on
success. Anything else raises GraphErrorException.
debugToken(string $inputToken, string $appAccessToken): DebugTokenInfo
GET /debug_token. Introspects a token. The one being examined
($inputToken) is usually a user or client token whose fitness you
want to verify. The second token ($appAccessToken) is your app-level
token authorising the introspection call (typically
"{$appId}|{$appSecret}").
$info = $fb->debugToken($someUserToken, $appId . '|' . $appSecret); if (!$info->isValid()) { // Reject the request. The caller's token is no good. } if ($info->expiresAt !== null && $info->expiresAt <= new DateTimeImmutable('+5 minutes')) { // Nearly expired. Trigger a refresh. }
OAuth2 and OIDC
The Facebook package does not re-implement OAuth2. It provides a
FacebookProviderConfig factory that returns a
Horde\OAuth\Client\ProviderConfig pre-populated with Meta's versioned
endpoint URLs. Callers wire the actual authorization flow with
Horde\OAuth\Client\OAuth2Client.
Authorization flow
use Horde\OAuth\Client\OAuth2Client; use Horde\Service\Facebook\Graph\GraphApiVersion; use Horde\Service\Facebook\OAuth\FacebookProviderConfig; $providerConfig = FacebookProviderConfig::forVersion(GraphApiVersion::V25_0); $oauth = new OAuth2Client( $httpClient, $requestFactory, $streamFactory, $providerConfig, clientId: getenv('FB_APP_ID'), clientSecret: getenv('FB_APP_SECRET'), ); // 1. Redirect the user to Facebook. $state = bin2hex(random_bytes(16)); $authUrl = $oauth->getAuthorizationUrl( redirectUri: 'https://example.org/callback', scopes: ['public_profile', 'email', 'user_events'], state: $state, ); header('Location: ' . $authUrl); // 2. In the callback handler, exchange the code for a TokenSet. $tokenSet = $oauth->exchangeCode($_GET['code']); // 3. Store $tokenSet->accessToken (and $tokenSet->refreshToken if present). // 4. Wrap your PSR-18 client and hand it to FacebookApiClient::create().
id_token verification (Facebook Login with openid scope)
When you request the openid scope, Meta returns an id_token
alongside the access token. The id_token is a signed JWT carrying
user identity claims (sub, aud, iss, exp, iat, plus any
nonce you passed).
Verification via FacebookOidcSupport:
use Horde\Service\Facebook\OAuth\FacebookOidcSupport; use Horde\Service\Facebook\OAuth\FacebookProviderConfig; $oidc = new FacebookOidcSupport($httpClient, $requestFactory); $verified = $oidc->verifyIdToken($idToken, [ 'verify_iss' => FacebookProviderConfig::ISSUER, 'verify_aud' => getenv('FB_APP_ID'), ]); $userId = $verified->getSubject(); $claims = $verified->getClaims();
The helper fetches Meta's JWKS document, selects the key matching the
token's kid header, and delegates to Horde\Jwt\TokenDecoder for
signature and claims verification. Nonce verification is left to the
caller because it involves state you stored between the authorize
redirect and the callback.
Error Handling
Every wire error carrying a Meta error envelope becomes a
GraphErrorException:
use Horde\Service\Facebook\Graph\GraphErrorException; try { $events = iterator_to_array($fb->listMyUpcomingEvents()); } catch (GraphErrorException $e) { if ($e->error()->isTokenExpired()) { // Refresh the token, then retry. } if ($e->error()->isRateLimit()) { // Back off. Check e->error()->isAppRateLimit() vs isUserRateLimit() // for the specific limit. } if ($e->error()->isPermissionMissing()) { // Ask the user to grant the missing scope. } throw $e; }
Predicates on GraphError:
isAuth().code === 190(any OAuthException-family).isTokenExpired().code === 190with subcode 463 or 467.isRateLimit().codein{4, 17, 32, 613}.isAppRateLimit().code === 4.isUserRateLimit().code === 17.isPermissionMissing().code === 200.isTransient().code === 1orcode === 2.
Do not string-match $e->getMessage(). Meta rewords error messages
without notice. Use the predicates.
Malformed error responses (HTTP 4xx/5xx with no parseable Meta
envelope) throw the plain FacebookApiException base class instead.
Catch that if you want to handle every failure mode uniformly.
Value Objects
Return types are per-version concrete classes under
Horde\Service\Facebook\Graph\Endpoint\V{N}\Value\. For the current
default that means V25\Value\User, V25\Value\Event,
V25\Value\Permission, and V25\Value\DebugTokenInfo. Each carries
version-specific fields as public readonly properties.
For version-portable signatures, type-hint the shared interfaces in
Horde\Service\Facebook\Graph\Value\. User, Event, Permission,
DebugTokenInfo. These expose only fields present on every supported
version's response, via method accessors:
use Horde\Service\Facebook\Graph\Value\Event; // Version-portable. Accepts any V{N}\Value\Event. function renderEventSummary(Event $event): string { return $event->name() . ' @ ' . $event->startTime()->format('Y-m-d H:i'); }
When you need v25-specific fields (rsvpStatus, placeName,
coverPhotoUrl), type-hint the concrete class directly and read the
public properties OR reflect on capability interfaces
Value objects are pure data holders. They construct from decoded JSON
via ::fromApiResponse(object $data): self and have no dependency on
the HTTP client, config, or version enum. That makes them independently
useful for hydrating stored payloads (database rows, cache entries,
replay fixtures), not only live API responses.
Profile URL Helpers
Two pure URL builders. No API call, no token required. For rendering
Facebook profile links and profile picture URLs. Corresponds to the
legacy client's getProfileLink() and getThumbnail() methods, the
only members of the legacy Users module that ported cleanly.
use Horde\Service\Facebook\Graph\GraphApiVersion; use Horde\Service\Facebook\Graph\ProfileUrls; // Link to a user's public profile page. $link = ProfileUrls::profileLink('12345'); // => https://www.facebook.com/12345 $link = ProfileUrls::profileLink('zuck'); // => https://www.facebook.com/zuck // Profile picture URL. Meta serves a 302 to the actual image. $thumb = ProfileUrls::thumbnailUrl('12345'); // => https://graph.facebook.com/v25.0/12345/picture // With size/type options. $thumb = ProfileUrls::thumbnailUrl('12345', GraphApiVersion::V25_0, [ 'type' => 'large', ]); $thumb = ProfileUrls::thumbnailUrl('12345', null, [ 'width' => 200, 'height' => 200, ]);
What This Library Does Not Do
Explicitly out of scope for the MVP:
- Photo/video multipart upload.
- Batch requests (
/?batch=[...]). - The
pages_*capability tree (page-content management is a separate product surface and will be scoped separately when a caller needs it). - Webhooks / real-time updates.
The legacy lib/Horde/Service/Facebook/ tree that targets these
features is retained for one release cycle for backward autoload
compatibility. Do not use it in new code. It calls endpoints
Facebook no longer serves.
For the full catalog of features the library does not currently ship, including known deferrals (long-lived token exchange, batch requests) and larger capability areas (Login-with-Facebook identity mapping, Pages, Meta Business Manager), see doc/MISSING_FEATURES.md.
Legacy Coexistence
The lib/ PSR-0 tree stays in place though largely defunct. The src/ PSR-4 tree is the
supported surface. There is no forwarding between them. New callers
use the PSR-4 namespace. Old callers keep syntactically correct (against dead
endpoints) so no code breaks by merely depending on the classes. Still migration is due.
Migrating existing callers off lib/? Start with
doc/UPGRADING.md for the class-to-class map and
concrete migration examples.
Testing
composer install phpunit
Uses PHPUnit 11+. Tests run against test/unit. Integration tests
under test/integration require live Facebook credentials via
environment variables and are excluded from the default suite.
License
BSD-2-Clause. See LICENSE.
horde/service_facebook 适用场景与选型建议
horde/service_facebook 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 1, 最近一次更新时间为 2023 年 12 月 22 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「oauth2」 「facebook」 「graph」 「meta」 「oidc」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 horde/service_facebook 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 horde/service_facebook 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 horde/service_facebook 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Netgen Open Graph Bundle is an Ibexa Platform bundle that allows simple integration with Open Graph protocol.
Simple Sharing generates social media share links within CP entry pages, allowing you to quickly & easily share entries.
A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.
A tool for scraping URL resources (oEmbed, OpenGraph, Twitter cards, JSON-LD)
Email Toolkit Plugin for CakePHP
Magento 2 Social Login extension is designed for quick login to your Magento 2 store without procesing complex register steps
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 5
其他信息
- 授权协议: BSD-2-Clause
- 更新时间: 2023-12-22