Skip to content

Instantly share code, notes, and snippets.

@khalid05
Created August 15, 2011 13:44
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khalid05/1146781 to your computer and use it in GitHub Desktop.
Save khalid05/1146781 to your computer and use it in GitHub Desktop.
<?php
namespace Facebook;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Util\String;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use JMS\DiExtraBundle\Annotation as DI;
/**
* @DI\Service("facebook.callback_server")
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CallbackServer
{
private $facebook;
private $router;
private $verifyToken;
private $callbackRoute;
private $logger;
/**
* @DI\InjectParams({
* "facebook" = @DI\Inject("fos_facebook.api"),
* "verifyToken" = @DI\Inject("%my.facebook_callback_token%"),
* "callbackRoute" = @DI\Inject("%my.facebook_callback_route%"),
* })
*
* @param string $verifyToken
*/
public function __construct(\BaseFacebook $facebook, RouterInterface $router, LoggerInterface $logger, $verifyToken, $callbackRoute)
{
$this->facebook = $facebook;
$this->router = $router;
$this->logger = $logger;
$this->verifyToken = $verifyToken;
$this->callbackRoute = $callbackRoute;
}
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function subscribe($object, $fields)
{
if (!is_string($object)) {
throw new \RuntimeException(sprintf('$object must be a string, but got %s.', gettype($object)));
}
if (!is_string($fields)) {
throw new \RuntimeException(sprintf('$fields must be a string, but got %s.', gettype($fields)));
}
$callbackUrl = $this->router->generate($this->callbackRoute, array(), true);
$this->logger->debug(sprintf('Subscribing to Facebook notifications for object "%s" and fields "%s"...', $object, $fields));
$this->logger->debug(sprintf('Using callback url "%s".', $callbackUrl));
$this->facebook->api($this->facebook->getAppId().'/subscriptions', 'POST', array(
'object' => $object,
'fields' => $fields,
'callback_url' => $callbackUrl,
'verify_token' => $this->verifyToken,
));
}
public function processRequest(Request $request)
{
if ('GET' === $request->getMethod()) {
return $this->processVerificationRequest($request);
} else if ('POST' === $request->getMethod()) {
return $this->processSentData($request);
}
}
private function processSentData(Request $request)
{
if ('application/json' !== $request->headers->get('Content-Type')) {
return new Response('Unsupported content type.', 406);
}
$payload = $request->getContent();
if (!String::equals('sha1='.hash_hmac('sha1', $payload, $this->facebook->getApiSecret()), $request->headers->get('X-Hub-Signature'))) {
return new Response('Invalid signature', 400);
}
$data = json_decode($payload, true);
if (null === $data) {
return new Response('Invalid data', 400);
}
$this->logger->debug(sprintf('Processing data from Facebook: %s', $payload));
// TODO: Process
}
private function processVerificationRequest(Request $request)
{
if ('subscribe' !== $request->query->get('hub_mode')) {
return new Response(sprintf('Invalid hub mode "%s".', $request->query->get('hub_mode')), 400);
}
if (!String::equals($this->verifyToken, $request->query->get('hub_verify_token'))) {
return new Response('Invalid token', 400);
}
return new Response($request->query->get('hub_challenge'));
}
}
<?php
namespace Tests\Facebook;
use Facebook\CallbackServer;
use Symfony\Component\HttpFoundation\Request;
class CallbackServerTest extends \PHPUnit_Framework_TestCase
{
public function testProcessWithCallbackVerification()
{
$request = Request::create('/', 'GET', array(
'hub_mode' => 'subscribe',
'hub_challenge' => 'baz',
'hub_verify_token' => 'foobar',
));
$response = $this->getServer()->processRequest($request);
$this->assertEquals('baz', $response->getContent());
$this->assertEquals(200, $response->getStatusCode());
}
public function testProcessWithInvalidCallbackVerification()
{
$request = Request::create('/', 'GET', array(
'hub_mode' => 'subscribe',
'hub_challenge' => 'baz',
'hub_verify_token' => 'foo',
));
$response = $this->getServer()->processRequest($request);
$this->assertEquals(400, $response->getStatusCode());
}
private function getServer()
{
$facebook = $this->getMock('BaseFacebook');
$router = $this->getMock('Symfony\Component\Routing\RouterInterface');
$logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface');
return new CallbackServer($facebook, $router, $logger, 'foobar', '');
}
}
@ugljanin
Copy link

Hi,

I am not using this framework but I managed to connect all and receive information about changes on pages via webhooks. The problem I am facing is that sometimes I get same info about change several times in different time period. Is there a chance to inform facebook that I have processed that request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment