Skip to content
This repository was archived by the owner on Jan 13, 2022. It is now read-only.

Commit 2c14499

Browse files
committed
Merge pull request #552 from SammyK/remove-mb-string
Remove mb-string dependency
2 parents 38fd718 + 4d81ee1 commit 2c14499

File tree

10 files changed

+98
-149
lines changed

10 files changed

+98
-149
lines changed

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
}
1313
],
1414
"require": {
15-
"php": ">=5.4.0",
16-
"ext-mbstring": "*"
15+
"php": ">=5.4.0"
1716
},
1817
"require-dev": {
1918
"phpunit/phpunit": "~4.0",
@@ -26,7 +25,8 @@
2625
"autoload": {
2726
"psr-4": {
2827
"Facebook\\": "src/Facebook/"
29-
}
28+
},
29+
"files": ["src/Facebook/polyfills.php"]
3030
},
3131
"autoload-dev": {
3232
"psr-4": {

src/Facebook/Helpers/FacebookRedirectLoginHelper.php

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -235,27 +235,19 @@ public function getAccessToken($redirectUrl = null)
235235
protected function validateCsrf()
236236
{
237237
$state = $this->getState();
238-
$savedState = $this->persistentDataHandler->get('state');
239-
240-
if (!$state || !$savedState) {
241-
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
238+
if (!$state) {
239+
throw new FacebookSDKException('Cross-site request forgery validation failed. Required GET param "state" missing.');
242240
}
243-
244-
$savedLen = strlen($savedState);
245-
$givenLen = strlen($state);
246-
247-
if ($savedLen !== $givenLen) {
248-
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
241+
$savedState = $this->persistentDataHandler->get('state');
242+
if (!$savedState) {
243+
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing from persistent data.');
249244
}
250245

251-
$result = 0;
252-
for ($i = 0; $i < $savedLen; $i++) {
253-
$result |= ord($state[$i]) ^ ord($savedState[$i]);
246+
if (\hash_equals($savedState, $state)) {
247+
return;
254248
}
255249

256-
if ($result !== 0) {
257-
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
258-
}
250+
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
259251
}
260252

261253
/**

src/Facebook/HttpClients/FacebookCurlHttpClient.php

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,6 @@ class FacebookCurlHttpClient implements FacebookHttpClientInterface
5353
*/
5454
protected $facebookCurl;
5555

56-
/**
57-
* @const Curl Version which is unaffected by the proxy header length error.
58-
*/
59-
const CURL_PROXY_QUIRK_VER = 0x071E00;
60-
61-
/**
62-
* @const "Connection Established" header text
63-
*/
64-
const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";
65-
6656
/**
6757
* @param FacebookCurl|null Procedural curl as object
6858
*/
@@ -164,47 +154,10 @@ public function compileRequestHeaders(array $headers)
164154
*/
165155
public function extractResponseHeadersAndBody()
166156
{
167-
$headerSize = $this->getHeaderSize();
168-
169-
$rawHeaders = mb_substr($this->rawResponse, 0, $headerSize);
170-
$rawBody = mb_substr($this->rawResponse, $headerSize);
157+
$parts = explode("\r\n\r\n", $this->rawResponse);
158+
$rawBody = array_pop($parts);
159+
$rawHeaders = implode("\r\n\r\n", $parts);
171160

172161
return [trim($rawHeaders), trim($rawBody)];
173162
}
174-
175-
/**
176-
* Return proper header size
177-
*
178-
* @return integer
179-
*/
180-
private function getHeaderSize()
181-
{
182-
$headerSize = $this->facebookCurl->getinfo(CURLINFO_HEADER_SIZE);
183-
// This corrects a Curl bug where header size does not account
184-
// for additional Proxy headers.
185-
if ($this->needsCurlProxyFix()) {
186-
// Additional way to calculate the request body size.
187-
if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) {
188-
$headerSize = mb_strlen($this->rawResponse) - $m[1];
189-
} elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) {
190-
$headerSize += mb_strlen(self::CONNECTION_ESTABLISHED);
191-
}
192-
}
193-
194-
return $headerSize;
195-
}
196-
197-
/**
198-
* Detect versions of Curl which report incorrect header lengths when
199-
* using Proxies.
200-
*
201-
* @return boolean
202-
*/
203-
private function needsCurlProxyFix()
204-
{
205-
$ver = $this->facebookCurl->version();
206-
$version = $ver['version_number'];
207-
208-
return $version < self::CURL_PROXY_QUIRK_VER;
209-
}
210163
}

src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorTrait.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ public function validateLength($length)
5454
*/
5555
public function binToHex($binaryData, $length)
5656
{
57-
if (true !== extension_loaded('mbstring')) {
58-
throw new \RuntimeException('Multibyte support required');
59-
}
60-
return \mb_substr(\bin2hex($binaryData), 0, $length);
57+
return \substr(\bin2hex($binaryData), 0, $length);
6158
}
6259
}

src/Facebook/SignedRequest.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,8 @@ protected function hashSignature($encodedData)
268268
*/
269269
protected function validateSignature($hashedSig, $sig)
270270
{
271-
if (mb_strlen($hashedSig) === mb_strlen($sig)) {
272-
$validate = 0;
273-
for ($i = 0; $i < mb_strlen($sig); $i++) {
274-
$validate |= ord($hashedSig[$i]) ^ ord($sig[$i]);
275-
}
276-
if ($validate === 0) {
277-
return;
278-
}
271+
if (\hash_equals($hashedSig, $sig)) {
272+
return;
279273
}
280274

281275
throw new FacebookSDKException('Signed request has an invalid signature.', 602);

src/Facebook/polyfills.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Copyright 2016 Facebook, Inc.
4+
*
5+
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
6+
* use, copy, modify, and distribute this software in source code or binary
7+
* form for use in connection with the web services and APIs provided by
8+
* Facebook.
9+
*
10+
* As with any software that integrates with the Facebook platform, your use
11+
* of this software is subject to the Facebook Developer Principles and
12+
* Policies [http://developers.facebook.com/policy/]. This copyright notice
13+
* shall be included in all copies or substantial portions of the software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
* DEALINGS IN THE SOFTWARE.
22+
*
23+
*/
24+
25+
/**
26+
* @see https://github.com/sarciszewski/php-future/blob/master/src/Security.php#L37-L51
27+
*/
28+
if (!function_exists('hash_equals')) {
29+
function hash_equals($knownString, $userString)
30+
{
31+
if (function_exists('mb_strlen')) {
32+
$kLen = mb_strlen($knownString, '8bit');
33+
$uLen = mb_strlen($userString, '8bit');
34+
} else {
35+
$kLen = strlen($knownString);
36+
$uLen = strlen($userString);
37+
}
38+
if ($kLen !== $uLen) {
39+
return false;
40+
}
41+
$result = 0;
42+
for ($i = 0; $i < $kLen; $i++) {
43+
$result |= (ord($knownString[$i]) ^ ord($userString[$i]));
44+
}
45+
46+
// They are only identical strings if $result is exactly 0...
47+
return 0 === $result;
48+
}
49+
}

tests/FacebookTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ public function testSettingAnInvalidHttpClientHandlerThrows()
120120

121121
public function testCurlHttpClientHandlerCanBeForced()
122122
{
123+
if (!extension_loaded('curl')) {
124+
$this->markTestSkipped('cURL must be installed to test cURL client handler.');
125+
}
123126
$config = array_merge($this->config, [
124127
'http_client_handler' => 'curl'
125128
]);

tests/HttpClients/FacebookCurlHttpClientTest.php

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class FacebookCurlHttpClientTest extends AbstractTestHttpClient
4343

4444
public function setUp()
4545
{
46+
if (!extension_loaded('curl')) {
47+
$this->markTestSkipped('cURL must be installed to test cURL client handler.');
48+
}
4649
$this->curlMock = m::mock('Facebook\HttpClients\FacebookCurl');
4750
$this->curlClient = new FacebookCurlHttpClient($this->curlMock);
4851
}
@@ -146,15 +149,6 @@ public function testCanCloseConnection()
146149

147150
public function testIsolatesTheHeaderAndBody()
148151
{
149-
$this->curlMock
150-
->shouldReceive('getinfo')
151-
->with(CURLINFO_HEADER_SIZE)
152-
->once()
153-
->andReturn(strlen($this->fakeRawHeader));
154-
$this->curlMock
155-
->shouldReceive('version')
156-
->once()
157-
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
158152
$this->curlMock
159153
->shouldReceive('exec')
160154
->once()
@@ -170,15 +164,6 @@ public function testIsolatesTheHeaderAndBody()
170164
public function testProperlyHandlesProxyHeaders()
171165
{
172166
$rawHeader = $this->fakeRawProxyHeader . $this->fakeRawHeader;
173-
$this->curlMock
174-
->shouldReceive('getinfo')
175-
->with(CURLINFO_HEADER_SIZE)
176-
->once()
177-
->andReturn(mb_strlen($rawHeader));
178-
$this->curlMock
179-
->shouldReceive('version')
180-
->once()
181-
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
182167
$this->curlMock
183168
->shouldReceive('exec')
184169
->once()
@@ -194,15 +179,6 @@ public function testProperlyHandlesProxyHeaders()
194179
public function testProperlyHandlesProxyHeadersWithCurlBug()
195180
{
196181
$rawHeader = $this->fakeRawProxyHeader . $this->fakeRawHeader;
197-
$this->curlMock
198-
->shouldReceive('getinfo')
199-
->with(CURLINFO_HEADER_SIZE)
200-
->once()
201-
->andReturn(mb_strlen($this->fakeRawHeader)); // Mimic bug that doesn't count proxy header
202-
$this->curlMock
203-
->shouldReceive('version')
204-
->once()
205-
->andReturn(['version_number' => self::CURL_VERSION_BUGGY]);
206182
$this->curlMock
207183
->shouldReceive('exec')
208184
->once()
@@ -218,15 +194,6 @@ public function testProperlyHandlesProxyHeadersWithCurlBug()
218194
public function testProperlyHandlesProxyHeadersWithCurlBug2()
219195
{
220196
$rawHeader = $this->fakeRawProxyHeader2 . $this->fakeRawHeader;
221-
$this->curlMock
222-
->shouldReceive('getinfo')
223-
->with(CURLINFO_HEADER_SIZE)
224-
->once()
225-
->andReturn(mb_strlen($this->fakeRawHeader)); // Mimic bug that doesn't count proxy header
226-
$this->curlMock
227-
->shouldReceive('version')
228-
->once()
229-
->andReturn(['version_number' => self::CURL_VERSION_BUGGY]);
230197
$this->curlMock
231198
->shouldReceive('exec')
232199
->once()
@@ -242,15 +209,6 @@ public function testProperlyHandlesProxyHeadersWithCurlBug2()
242209
public function testProperlyHandlesRedirectHeaders()
243210
{
244211
$rawHeader = $this->fakeRawRedirectHeader . $this->fakeRawHeader;
245-
$this->curlMock
246-
->shouldReceive('getinfo')
247-
->with(CURLINFO_HEADER_SIZE)
248-
->once()
249-
->andReturn(mb_strlen($rawHeader));
250-
$this->curlMock
251-
->shouldReceive('version')
252-
->once()
253-
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
254212
$this->curlMock
255213
->shouldReceive('exec')
256214
->once()
@@ -281,15 +239,6 @@ public function testCanSendNormalRequest()
281239
->shouldReceive('errno')
282240
->once()
283241
->andReturn(null);
284-
$this->curlMock
285-
->shouldReceive('getinfo')
286-
->with(CURLINFO_HEADER_SIZE)
287-
->once()
288-
->andReturn(mb_strlen($this->fakeRawHeader));
289-
$this->curlMock
290-
->shouldReceive('version')
291-
->once()
292-
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
293242
$this->curlMock
294243
->shouldReceive('close')
295244
->once()

tests/HttpClients/HttpClientsFactoryTest.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,19 @@ public function testCreateHttpClient($handler, $expected)
5454
*/
5555
public function httpClientsProvider()
5656
{
57-
return [
58-
['curl', self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'],
59-
['guzzle', self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
60-
['stream', self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
61-
[new Client(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
62-
[new FacebookCurlHttpClient(), self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'],
63-
[new FacebookGuzzleHttpClient(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
64-
[new FacebookStreamHttpClient(), self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
65-
[null, self::COMMON_INTERFACE],
57+
$clients = [
58+
['guzzle', self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
59+
['stream', self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
60+
[new Client(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
61+
[new FacebookGuzzleHttpClient(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
62+
[new FacebookStreamHttpClient(), self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
63+
[null, self::COMMON_INTERFACE],
6664
];
65+
if (extension_loaded('curl')) {
66+
$clients[] = ['curl', self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'];
67+
$clients[] = [new FacebookCurlHttpClient(), self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'];
68+
}
69+
70+
return $clients;
6771
}
6872
}

tests/PseudoRandomString/PseudoRandomStringFactoryTest.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,19 @@ public function testCreateHttpClient($handler, $expected)
5353
*/
5454
public function httpClientsProvider()
5555
{
56-
return [
57-
['mcrypt', self::COMMON_NAMESPACE . 'McryptPseudoRandomStringGenerator'],
58-
['openssl', self::COMMON_NAMESPACE . 'OpenSslPseudoRandomStringGenerator'],
59-
['urandom', self::COMMON_NAMESPACE . 'UrandomPseudoRandomStringGenerator'],
60-
[null, self::COMMON_INTERFACE],
56+
$providers = [
57+
[null, self::COMMON_INTERFACE],
6158
];
59+
if (function_exists('mcrypt_create_iv')) {
60+
$providers[] = ['mcrypt', self::COMMON_NAMESPACE . 'McryptPseudoRandomStringGenerator'];
61+
}
62+
if (function_exists('openssl_random_pseudo_bytes')) {
63+
$providers[] = ['openssl', self::COMMON_NAMESPACE . 'OpenSslPseudoRandomStringGenerator'];
64+
}
65+
if (!ini_get('open_basedir') && is_readable('/dev/urandom')) {
66+
$providers[] = ['urandom', self::COMMON_NAMESPACE . 'UrandomPseudoRandomStringGenerator'];
67+
}
68+
69+
return $providers;
6270
}
6371
}

0 commit comments

Comments
 (0)