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

Remove mb-string dependency #552

Merged
merged 8 commits into from
May 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
}
],
"require": {
"php": ">=5.4.0",
"ext-mbstring": "*"
"php": ">=5.4.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until PHP 7 is under the "allowed failures" section on Travis, could you use "php": "^5.4" please? (also the >= is unrecommended by Composer itself).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Let's fix this issue in a separate PR. :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #554 :)

},
"require-dev": {
"phpunit/phpunit": "~4.0",
Expand All @@ -26,7 +25,8 @@
"autoload": {
"psr-4": {
"Facebook\\": "src/Facebook/"
}
},
"files": ["src/Facebook/polyfills.php"]
},
"autoload-dev": {
"psr-4": {
Expand Down
24 changes: 8 additions & 16 deletions src/Facebook/Helpers/FacebookRedirectLoginHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,27 +235,19 @@ public function getAccessToken($redirectUrl = null)
protected function validateCsrf()
{
$state = $this->getState();
$savedState = $this->persistentDataHandler->get('state');

if (!$state || !$savedState) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
if (!$state) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required GET param "state" missing.');
}

$savedLen = strlen($savedState);
$givenLen = strlen($state);

if ($savedLen !== $givenLen) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
$savedState = $this->persistentDataHandler->get('state');
if (!$savedState) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing from persistent data.');
}

$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($state[$i]) ^ ord($savedState[$i]);
if (\hash_equals($savedState, $state)) {
return;
}

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

/**
Expand Down
53 changes: 3 additions & 50 deletions src/Facebook/HttpClients/FacebookCurlHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,6 @@ class FacebookCurlHttpClient implements FacebookHttpClientInterface
*/
protected $facebookCurl;

/**
* @const Curl Version which is unaffected by the proxy header length error.
*/
const CURL_PROXY_QUIRK_VER = 0x071E00;

/**
* @const "Connection Established" header text
*/
const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";

/**
* @param FacebookCurl|null Procedural curl as object
*/
Expand Down Expand Up @@ -164,47 +154,10 @@ public function compileRequestHeaders(array $headers)
*/
public function extractResponseHeadersAndBody()
{
$headerSize = $this->getHeaderSize();

$rawHeaders = mb_substr($this->rawResponse, 0, $headerSize);
$rawBody = mb_substr($this->rawResponse, $headerSize);
$parts = explode("\r\n\r\n", $this->rawResponse);
$rawBody = array_pop($parts);
$rawHeaders = implode("\r\n\r\n", $parts);

return [trim($rawHeaders), trim($rawBody)];
}

/**
* Return proper header size
*
* @return integer
*/
private function getHeaderSize()
{
$headerSize = $this->facebookCurl->getinfo(CURLINFO_HEADER_SIZE);
// This corrects a Curl bug where header size does not account
// for additional Proxy headers.
if ($this->needsCurlProxyFix()) {
// Additional way to calculate the request body size.
if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) {
$headerSize = mb_strlen($this->rawResponse) - $m[1];
} elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) {
$headerSize += mb_strlen(self::CONNECTION_ESTABLISHED);
}
}

return $headerSize;
}

/**
* Detect versions of Curl which report incorrect header lengths when
* using Proxies.
*
* @return boolean
*/
private function needsCurlProxyFix()
{
$ver = $this->facebookCurl->version();
$version = $ver['version_number'];

return $version < self::CURL_PROXY_QUIRK_VER;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ public function validateLength($length)
*/
public function binToHex($binaryData, $length)
{
if (true !== extension_loaded('mbstring')) {
throw new \RuntimeException('Multibyte support required');
}
return \mb_substr(\bin2hex($binaryData), 0, $length);
return \substr(\bin2hex($binaryData), 0, $length);
}
}
10 changes: 2 additions & 8 deletions src/Facebook/SignedRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,8 @@ protected function hashSignature($encodedData)
*/
protected function validateSignature($hashedSig, $sig)
{
if (mb_strlen($hashedSig) === mb_strlen($sig)) {
$validate = 0;
for ($i = 0; $i < mb_strlen($sig); $i++) {
$validate |= ord($hashedSig[$i]) ^ ord($sig[$i]);
}
if ($validate === 0) {
return;
}
if (\hash_equals($hashedSig, $sig)) {
return;
}

throw new FacebookSDKException('Signed request has an invalid signature.', 602);
Expand Down
49 changes: 49 additions & 0 deletions src/Facebook/polyfills.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Copyright 2016 Facebook, Inc.
*
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
* use, copy, modify, and distribute this software in source code or binary
* form for use in connection with the web services and APIs provided by
* Facebook.
*
* As with any software that integrates with the Facebook platform, your use
* of this software is subject to the Facebook Developer Principles and
* Policies [http://developers.facebook.com/policy/]. This copyright notice
* shall be included in all copies or substantial portions of the software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/

/**
* @see https://github.com/sarciszewski/php-future/blob/master/src/Security.php#L37-L51
*/
if (!function_exists('hash_equals')) {
function hash_equals($knownString, $userString)
{
if (function_exists('mb_strlen')) {
$kLen = mb_strlen($knownString, '8bit');
$uLen = mb_strlen($userString, '8bit');
} else {
$kLen = strlen($knownString);
$uLen = strlen($userString);
}
if ($kLen !== $uLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $kLen; $i++) {
$result |= (ord($knownString[$i]) ^ ord($userString[$i]));
}

// They are only identical strings if $result is exactly 0...
return 0 === $result;
}
}
3 changes: 3 additions & 0 deletions tests/FacebookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ public function testSettingAnInvalidHttpClientHandlerThrows()

public function testCurlHttpClientHandlerCanBeForced()
{
if (!extension_loaded('curl')) {
$this->markTestSkipped('cURL must be installed to test cURL client handler.');
}
$config = array_merge($this->config, [
'http_client_handler' => 'curl'
]);
Expand Down
57 changes: 3 additions & 54 deletions tests/HttpClients/FacebookCurlHttpClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class FacebookCurlHttpClientTest extends AbstractTestHttpClient

public function setUp()
{
if (!extension_loaded('curl')) {
$this->markTestSkipped('cURL must be installed to test cURL client handler.');
}
$this->curlMock = m::mock('Facebook\HttpClients\FacebookCurl');
$this->curlClient = new FacebookCurlHttpClient($this->curlMock);
}
Expand Down Expand Up @@ -146,15 +149,6 @@ public function testCanCloseConnection()

public function testIsolatesTheHeaderAndBody()
{
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(strlen($this->fakeRawHeader));
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
$this->curlMock
->shouldReceive('exec')
->once()
Expand All @@ -170,15 +164,6 @@ public function testIsolatesTheHeaderAndBody()
public function testProperlyHandlesProxyHeaders()
{
$rawHeader = $this->fakeRawProxyHeader . $this->fakeRawHeader;
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(mb_strlen($rawHeader));
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
$this->curlMock
->shouldReceive('exec')
->once()
Expand All @@ -194,15 +179,6 @@ public function testProperlyHandlesProxyHeaders()
public function testProperlyHandlesProxyHeadersWithCurlBug()
{
$rawHeader = $this->fakeRawProxyHeader . $this->fakeRawHeader;
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(mb_strlen($this->fakeRawHeader)); // Mimic bug that doesn't count proxy header
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_BUGGY]);
$this->curlMock
->shouldReceive('exec')
->once()
Expand All @@ -218,15 +194,6 @@ public function testProperlyHandlesProxyHeadersWithCurlBug()
public function testProperlyHandlesProxyHeadersWithCurlBug2()
{
$rawHeader = $this->fakeRawProxyHeader2 . $this->fakeRawHeader;
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(mb_strlen($this->fakeRawHeader)); // Mimic bug that doesn't count proxy header
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_BUGGY]);
$this->curlMock
->shouldReceive('exec')
->once()
Expand All @@ -242,15 +209,6 @@ public function testProperlyHandlesProxyHeadersWithCurlBug2()
public function testProperlyHandlesRedirectHeaders()
{
$rawHeader = $this->fakeRawRedirectHeader . $this->fakeRawHeader;
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(mb_strlen($rawHeader));
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
$this->curlMock
->shouldReceive('exec')
->once()
Expand Down Expand Up @@ -281,15 +239,6 @@ public function testCanSendNormalRequest()
->shouldReceive('errno')
->once()
->andReturn(null);
$this->curlMock
->shouldReceive('getinfo')
->with(CURLINFO_HEADER_SIZE)
->once()
->andReturn(mb_strlen($this->fakeRawHeader));
$this->curlMock
->shouldReceive('version')
->once()
->andReturn(['version_number' => self::CURL_VERSION_STABLE]);
$this->curlMock
->shouldReceive('close')
->once()
Expand Down
22 changes: 13 additions & 9 deletions tests/HttpClients/HttpClientsFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,19 @@ public function testCreateHttpClient($handler, $expected)
*/
public function httpClientsProvider()
{
return [
['curl', self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'],
['guzzle', self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
['stream', self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
[new Client(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
[new FacebookCurlHttpClient(), self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'],
[new FacebookGuzzleHttpClient(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
[new FacebookStreamHttpClient(), self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
[null, self::COMMON_INTERFACE],
$clients = [
['guzzle', self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
['stream', self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
[new Client(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
[new FacebookGuzzleHttpClient(), self::COMMON_NAMESPACE . 'FacebookGuzzleHttpClient'],
[new FacebookStreamHttpClient(), self::COMMON_NAMESPACE . 'FacebookStreamHttpClient'],
[null, self::COMMON_INTERFACE],
];
if (extension_loaded('curl')) {
$clients[] = ['curl', self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'];
$clients[] = [new FacebookCurlHttpClient(), self::COMMON_NAMESPACE . 'FacebookCurlHttpClient'];
}

return $clients;
}
}
18 changes: 13 additions & 5 deletions tests/PseudoRandomString/PseudoRandomStringFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,19 @@ public function testCreateHttpClient($handler, $expected)
*/
public function httpClientsProvider()
{
return [
['mcrypt', self::COMMON_NAMESPACE . 'McryptPseudoRandomStringGenerator'],
['openssl', self::COMMON_NAMESPACE . 'OpenSslPseudoRandomStringGenerator'],
['urandom', self::COMMON_NAMESPACE . 'UrandomPseudoRandomStringGenerator'],
[null, self::COMMON_INTERFACE],
$providers = [
[null, self::COMMON_INTERFACE],
];
if (function_exists('mcrypt_create_iv')) {
$providers[] = ['mcrypt', self::COMMON_NAMESPACE . 'McryptPseudoRandomStringGenerator'];
}
if (function_exists('openssl_random_pseudo_bytes')) {
$providers[] = ['openssl', self::COMMON_NAMESPACE . 'OpenSslPseudoRandomStringGenerator'];
}
if (!ini_get('open_basedir') && is_readable('/dev/urandom')) {
$providers[] = ['urandom', self::COMMON_NAMESPACE . 'UrandomPseudoRandomStringGenerator'];
}

return $providers;
}
}