Skip to content

Commit 08bf82c

Browse files
Jerry CainJerry Cain
authored andcommitted
Adding support for the JS cookie and its use in the PHP SDK
1 parent afa1534 commit 08bf82c

File tree

3 files changed

+120
-12
lines changed

3 files changed

+120
-12
lines changed

readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,8 @@ We are including this in the open source repository to assure you of our
7070
commitment to quality, but also with the hopes that you will contribute back to
7171
help keep it stable. The easiest way to do so is to file bugs and include a
7272
test case.
73+
74+
The tests can be executed by using this command from the base directory:
75+
76+
phpunit --stderr --bootstrap tests/bootstrap.php tests/tests.php
77+

src/base_facebook.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ abstract class BaseFacebook
120120
/**
121121
* Version.
122122
*/
123-
const VERSION = '3.0.1';
123+
const VERSION = '3.1.0';
124124

125125
/**
126126
* Default options for curl.
@@ -129,7 +129,7 @@ abstract class BaseFacebook
129129
CURLOPT_CONNECTTIMEOUT => 10,
130130
CURLOPT_RETURNTRANSFER => true,
131131
CURLOPT_TIMEOUT => 60,
132-
CURLOPT_USERAGENT => 'facebook-php-3.0',
132+
CURLOPT_USERAGENT => 'facebook-php-3.1',
133133
);
134134

135135
/**
@@ -372,15 +372,19 @@ protected function getUserAccessToken() {
372372
}
373373

374374
/**
375-
* Get the data from a signed_request token.
375+
* Retrieve the signed request, either from a request parameter or,
376+
* if not present, from a cookie.
376377
*
377-
* @return string The base domain
378+
* @return string the signed request, if available, or null otherwise.
378379
*/
379380
public function getSignedRequest() {
380381
if (!$this->signedRequest) {
381382
if (isset($_REQUEST['signed_request'])) {
382383
$this->signedRequest = $this->parseSignedRequest(
383384
$_REQUEST['signed_request']);
385+
} else if (isset($_COOKIE[$this->getSignedRequestCookieName()])) {
386+
$this->signedRequest = $this->parseSignedRequest(
387+
$_COOKIE[$this->getSignedRequestCookieName()]);
384388
}
385389
}
386390
return $this->signedRequest;
@@ -461,6 +465,13 @@ protected function getUserFromAvailableData() {
461465
public function getLoginUrl($params=array()) {
462466
$this->establishCSRFTokenState();
463467
$currentUrl = $this->getCurrentUrl();
468+
469+
// if 'scope' is passed as an array, convert to comma separated list
470+
$scopeParams = isset($params['scope']) ? $params['scope'] : null;
471+
if ($scopeParams && is_array($scopeParams)) {
472+
$params['scope'] = implode(',', $scopeParams);
473+
}
474+
464475
return $this->getUrl(
465476
'www',
466477
'dialog/oauth',
@@ -530,6 +541,19 @@ public function api(/* polymorphic */) {
530541
}
531542
}
532543

544+
/**
545+
* Constructs and returns the name of the cookie that
546+
* potentially houses the signed request for the app user.
547+
* The cookie is not set by the BaseFacebook class, but
548+
* it may be set by the JavaScript SDK.
549+
*
550+
* @return string the name of the cookie that would house
551+
* the signed request value.
552+
*/
553+
protected function getSignedRequestCookieName() {
554+
return 'fbsr_'.$this->getAppId();
555+
}
556+
533557
/**
534558
* Get the authorization code from the query parameters, if it exists,
535559
* and otherwise return false to signal no authorization code was

tests/tests.php

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class PHPSDKTestCase extends PHPUnit_Framework_TestCase {
2525
private static $kExpiredAccessToken = '206492729383450|2.N4RKywNPuHAey7CK56_wmg__.3600.1304560800.1-214707|6Q14AfpYi_XJB26aRQumouzJiGA';
2626
private static $kValidSignedRequest = '1sxR88U4SW9m6QnSxwCEw_CObqsllXhnpP5j2pxD97c.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEyODEwNTI4MDAsIm9hdXRoX3Rva2VuIjoiMTE3NzQzOTcxNjA4MTIwfDIuVlNUUWpub3hYVVNYd1RzcDB1U2g5d19fLjg2NDAwLjEyODEwNTI4MDAtMTY3Nzg0NjM4NXx4NURORHBtcy1nMUM0dUJHQVYzSVdRX2pYV0kuIiwidXNlcl9pZCI6IjE2Nzc4NDYzODUifQ';
2727
private static $kNonTosedSignedRequest = 'c0Ih6vYvauDwncv0n0pndr0hP0mvZaJPQDPt6Z43O0k.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiJ9';
28+
private static $kSignedRequestWithBogusSignature = '1sxR32U4SW9m6QnSxwCEw_CObqsllXhnpP5j2pxD97c.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEyODEwNTI4MDAsIm9hdXRoX3Rva2VuIjoiMTE3NzQzOTcxNjA4MTIwfDIuVlNUUWpub3hYVVNYd1RzcDB1U2g5d19fLjg2NDAwLjEyODEwNTI4MDAtMTY3Nzg0NjM4NXx4NURORHBtcy1nMUM0dUJHQVYzSVdRX2pYV0kuIiwidXNlcl9pZCI6IjE2Nzc4NDYzODUifQ';
2829

2930
public function testConstructor() {
3031
$facebook = new TransientFacebook(array(
@@ -183,6 +184,39 @@ public function testGetLoginURLWithExtraParams() {
183184
$this->assertEquals(strlen($query_map['state']), $num_characters = 32);
184185
}
185186

187+
public function testGetLoginURLWithScopeParamsAsArray() {
188+
$facebook = new Facebook(array(
189+
'appId' => self::APP_ID,
190+
'secret' => self::SECRET,
191+
));
192+
193+
// fake the HPHP $_SERVER globals
194+
$_SERVER['HTTP_HOST'] = 'www.test.com';
195+
$_SERVER['REQUEST_URI'] = '/unit-tests.php';
196+
$scope_params_as_array = array('email','sms','read_stream');
197+
$extra_params = array('scope' => $scope_params_as_array,
198+
'nonsense' => 'nonsense');
199+
$login_url = parse_url($facebook->getLoginUrl($extra_params));
200+
$this->assertEquals($login_url['scheme'], 'https');
201+
$this->assertEquals($login_url['host'], 'www.facebook.com');
202+
$this->assertEquals($login_url['path'], '/dialog/oauth');
203+
// expect api to flatten array params to comma separated list
204+
// should do the same here before asserting to make sure API is behaving
205+
// correctly;
206+
$extra_params['scope'] = implode(',', $scope_params_as_array);
207+
$expected_login_params =
208+
array_merge(
209+
array('client_id' => self::APP_ID,
210+
'redirect_uri' => 'http://www.test.com/unit-tests.php'),
211+
$extra_params);
212+
$query_map = array();
213+
parse_str($login_url['query'], $query_map);
214+
$this->assertIsSubset($expected_login_params, $query_map);
215+
// we don't know what the state is, but we know it's an md5 and should
216+
// be 32 characters long.
217+
$this->assertEquals(strlen($query_map['state']), $num_characters = 32);
218+
}
219+
186220
public function testGetCodeWithValidCSRFState() {
187221
$facebook = new FBCode(array(
188222
'appId' => self::APP_ID,
@@ -234,6 +268,30 @@ public function testGetUserFromSignedRequest() {
234268
'Failed to get user ID from a valid signed request.');
235269
}
236270

271+
public function testGetSignedRequestFromCookie() {
272+
$facebook = new FBGetSignedRequestCookieFacebook(array(
273+
'appId' => self::APP_ID,
274+
'secret' => self::SECRET,
275+
));
276+
277+
$_COOKIE[$facebook->publicGetSignedRequestCookieName()] =
278+
self::$kValidSignedRequest;
279+
$this->assertNotNull($facebook->publicGetSignedRequest());
280+
$this->assertEquals('1677846385', $facebook->getUser(),
281+
'Failed to get user ID from a valid signed request.');
282+
}
283+
284+
public function testGetSignedRequestWithIncorrectSignature() {
285+
$facebook = new FBGetSignedRequestCookieFacebook(array(
286+
'appId' => self::APP_ID,
287+
'secret' => self::SECRET,
288+
));
289+
290+
$_COOKIE[$facebook->publicGetSignedRequestCookieName()] =
291+
self::$kSignedRequestWithBogusSignature;
292+
$this->assertNull($facebook->publicGetSignedRequest());
293+
}
294+
237295
public function testNonUserAccessToken() {
238296
$facebook = new FBAccessToken(array(
239297
'appId' => self::APP_ID,
@@ -350,7 +408,7 @@ public function testGraphAPIMethod() {
350408
} catch(FacebookApiException $e) {
351409
// ProfileDelete means the server understood the DELETE
352410
$msg =
353-
'OAuthException: An access token is required to request this resource.';
411+
'OAuthException: A user access token is required to request this resource.';
354412
$this->assertEquals($msg, (string) $e,
355413
'Expect the invalid session message.');
356414
}
@@ -426,13 +484,24 @@ public function testGraphAPIWithOnlyParams() {
426484
'secret' => self::SECRET,
427485
));
428486

429-
$response = $facebook->api('/331218348435/feed',
430-
array('limit' => 1, 'access_token' => ''));
431-
$this->assertEquals(1, count($response['data']), 'should get one entry');
432-
$this->assertTrue(
433-
strpos($response['paging']['next'], 'limit=1') !== false,
434-
'expect the same limit back in the paging urls'
435-
);
487+
$response = $facebook->api('/jerry');
488+
$this->assertTrue(isset($response['id']),
489+
'User ID should be public.');
490+
$this->assertTrue(isset($response['name']),
491+
'User\'s name should be public.');
492+
$this->assertTrue(isset($response['first_name']),
493+
'User\'s first name should be public.');
494+
$this->assertTrue(isset($response['last_name']),
495+
'User\'s last name should be public.');
496+
$this->assertFalse(isset($response['work']),
497+
'User\'s work history should only be available with '.
498+
'a valid access token.');
499+
$this->assertFalse(isset($response['education']),
500+
'User\'s education history should only be '.
501+
'available with a valid access token.');
502+
$this->assertFalse(isset($response['verified']),
503+
'User\'s verification status should only be '.
504+
'available with a valid access token.');
436505
}
437506

438507
public function testLoginURLDefaults() {
@@ -839,3 +908,13 @@ public function publicGetCurrentUrl() {
839908
return $this->getCurrentUrl();
840909
}
841910
}
911+
912+
class FBGetSignedRequestCookieFacebook extends TransientFacebook {
913+
public function publicGetSignedRequest() {
914+
return $this->getSignedRequest();
915+
}
916+
917+
public function publicGetSignedRequestCookieName() {
918+
return $this->getSignedRequestCookieName();
919+
}
920+
}

0 commit comments

Comments
 (0)