From 463053faff4b3e4b482714f9848998033d5bd3ef Mon Sep 17 00:00:00 2001 From: Andrew Coulton Date: Thu, 26 Sep 2013 10:51:43 +0100 Subject: [PATCH 01/12] Only copy original request headers when following redirects [fixes #4790] When following a redirect, the client should not add NULL headers from the follow_headers list that were not set on the original request. This prevents problems when requesting URLs that include an authorization signature calculated from the request URL and headers. --- classes/Kohana/Request/Client.php | 7 +++++-- tests/kohana/request/ClientTest.php | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/classes/Kohana/Request/Client.php b/classes/Kohana/Request/Client.php index 26b744240..1190a30fc 100644 --- a/classes/Kohana/Request/Client.php +++ b/classes/Kohana/Request/Client.php @@ -405,10 +405,13 @@ public static function on_header_location(Request $request, Response $response, break; } - // Prepare the additional request + // Prepare the additional request, copying any follow_headers that were present on the original request + $orig_headers = $request->headers()->getArrayCopy(); + $follow_headers = array_intersect_assoc($orig_headers, array_fill_keys($client->follow_headers(), TRUE)); + $follow_request = Request::factory($response->headers('Location')) ->method($follow_method) - ->headers(Arr::extract($request->headers(), $client->follow_headers())); + ->headers($follow_headers); if ($follow_method !== Request::GET) { diff --git a/tests/kohana/request/ClientTest.php b/tests/kohana/request/ClientTest.php index fffc1d5d3..9ad870297 100644 --- a/tests/kohana/request/ClientTest.php +++ b/tests/kohana/request/ClientTest.php @@ -175,6 +175,29 @@ public function test_follows_with_headers() $this->assertFalse(isset($headers['x-not-in-follow']), 'X-Not-In-Follow should not be passed to next request'); } + /** + * Tests that the follow_headers are only added to a redirect request if they were present in the original + * + * @ticket 4790 + */ + public function test_follow_does_not_add_extra_headers() + { + $response = Request::factory( + $this->_dummy_redirect_uri(301), + array( + 'follow' => TRUE, + 'follow_headers' => array('Authorization') + )) + ->headers(array()) + ->execute(); + + $data = json_decode($response->body(),TRUE); + $headers = $data['rq_headers']; + + $this->assertArrayNotHasKey('authorization', $headers, 'Empty headers should not be added when following redirects'); + } + + /** * Provider for test_follows_with_strict_method * From c2227827ab4c994f7b62dc8781df6bf6b9c9687d Mon Sep 17 00:00:00 2001 From: Soon Van Date: Fri, 28 Feb 2014 13:28:53 -0500 Subject: [PATCH 02/12] Update license URLs in PHPDoc - Ref: #4821 Found links pointing to old location of license instead of where they are now at http://kohanaframework.org/license --- classes/Kohana/Config/Group.php | 4 ++-- classes/Kohana/Config/Source.php | 4 ++-- classes/Kohana/Config/Writer.php | 4 ++-- classes/Kohana/Debug.php | 4 ++-- classes/Kohana/HTTP.php | 4 ++-- classes/Kohana/HTTP/Header.php | 4 ++-- classes/Kohana/HTTP/Message.php | 4 ++-- classes/Kohana/HTTP/Request.php | 4 ++-- classes/Kohana/HTTP/Response.php | 4 ++-- classes/Kohana/Log/StdErr.php | 4 ++-- classes/Kohana/Log/StdOut.php | 4 ++-- classes/Kohana/Response.php | 4 ++-- tests/kohana/Config/File/ReaderTest.php | 4 ++-- tests/kohana/Config/GroupTest.php | 4 ++-- tests/kohana/DebugTest.php | 4 ++-- tests/kohana/Http/HeaderTest.php | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/classes/Kohana/Config/Group.php b/classes/Kohana/Config/Group.php index 0460c898d..3e35fdf55 100644 --- a/classes/Kohana/Config/Group.php +++ b/classes/Kohana/Config/Group.php @@ -11,8 +11,8 @@ * @package Kohana * @category Configuration * @author Kohana Team - * @copyright (c) 2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2012-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Config_Group extends ArrayObject { diff --git a/classes/Kohana/Config/Source.php b/classes/Kohana/Config/Source.php index cfce07609..388986085 100644 --- a/classes/Kohana/Config/Source.php +++ b/classes/Kohana/Config/Source.php @@ -7,8 +7,8 @@ * @package Kohana * @category Configuration * @author Kohana Team - * @copyright (c) 2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2012-2014 Kohana Team + * @license http://kohanaframework.org/license */ interface Kohana_Config_Source {} diff --git a/classes/Kohana/Config/Writer.php b/classes/Kohana/Config/Writer.php index 3db22c037..856ebde8d 100644 --- a/classes/Kohana/Config/Writer.php +++ b/classes/Kohana/Config/Writer.php @@ -7,8 +7,8 @@ * * @package Kohana * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ interface Kohana_Config_Writer extends Kohana_Config_Source { diff --git a/classes/Kohana/Debug.php b/classes/Kohana/Debug.php index 9d1efdf52..5a82bb623 100644 --- a/classes/Kohana/Debug.php +++ b/classes/Kohana/Debug.php @@ -5,8 +5,8 @@ * @package Kohana * @category Base * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Debug { diff --git a/classes/Kohana/HTTP.php b/classes/Kohana/HTTP.php index 083b43589..eca52c4e6 100644 --- a/classes/Kohana/HTTP.php +++ b/classes/Kohana/HTTP.php @@ -11,8 +11,8 @@ * @category HTTP * @author Kohana Team * @since 3.1.0 - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ abstract class Kohana_HTTP { diff --git a/classes/Kohana/HTTP/Header.php b/classes/Kohana/HTTP/Header.php index 6a35e9138..0debabf6c 100644 --- a/classes/Kohana/HTTP/Header.php +++ b/classes/Kohana/HTTP/Header.php @@ -9,8 +9,8 @@ * @category HTTP * @author Kohana Team * @since 3.1.0 - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_HTTP_Header extends ArrayObject { diff --git a/classes/Kohana/HTTP/Message.php b/classes/Kohana/HTTP/Message.php index 0861a733a..c24046ec1 100644 --- a/classes/Kohana/HTTP/Message.php +++ b/classes/Kohana/HTTP/Message.php @@ -7,8 +7,8 @@ * @category HTTP * @author Kohana Team * @since 3.1.0 - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ interface Kohana_HTTP_Message { diff --git a/classes/Kohana/HTTP/Request.php b/classes/Kohana/HTTP/Request.php index 8b2169c5f..b8992725f 100644 --- a/classes/Kohana/HTTP/Request.php +++ b/classes/Kohana/HTTP/Request.php @@ -8,8 +8,8 @@ * @category HTTP * @author Kohana Team * @since 3.1.0 - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ interface Kohana_HTTP_Request extends HTTP_Message { diff --git a/classes/Kohana/HTTP/Response.php b/classes/Kohana/HTTP/Response.php index 71058ac49..ddce6b4b9 100644 --- a/classes/Kohana/HTTP/Response.php +++ b/classes/Kohana/HTTP/Response.php @@ -8,8 +8,8 @@ * @category HTTP * @author Kohana Team * @since 3.1.0 - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ interface Kohana_HTTP_Response extends HTTP_Message { diff --git a/classes/Kohana/Log/StdErr.php b/classes/Kohana/Log/StdErr.php index 5097bb75d..53840387a 100644 --- a/classes/Kohana/Log/StdErr.php +++ b/classes/Kohana/Log/StdErr.php @@ -5,8 +5,8 @@ * @package Kohana * @category Logging * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Log_StdErr extends Log_Writer { /** diff --git a/classes/Kohana/Log/StdOut.php b/classes/Kohana/Log/StdOut.php index b0cfeb380..608c65389 100644 --- a/classes/Kohana/Log/StdOut.php +++ b/classes/Kohana/Log/StdOut.php @@ -5,8 +5,8 @@ * @package Kohana * @category Logging * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Log_StdOut extends Log_Writer { diff --git a/classes/Kohana/Response.php b/classes/Kohana/Response.php index 2a12e5e40..686997915 100644 --- a/classes/Kohana/Response.php +++ b/classes/Kohana/Response.php @@ -7,8 +7,8 @@ * @package Kohana * @category Base * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license * @since 3.1.0 */ class Kohana_Response implements HTTP_Response { diff --git a/tests/kohana/Config/File/ReaderTest.php b/tests/kohana/Config/File/ReaderTest.php index ab22d14ae..bfc755eda 100644 --- a/tests/kohana/Config/File/ReaderTest.php +++ b/tests/kohana/Config/File/ReaderTest.php @@ -10,8 +10,8 @@ * @author Kohana Team * @author Jeremy Bush * @author Matt Button - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Config_File_ReaderTest extends Kohana_Unittest_TestCase { diff --git a/tests/kohana/Config/GroupTest.php b/tests/kohana/Config/GroupTest.php index 66fd05856..6222c8df6 100644 --- a/tests/kohana/Config/GroupTest.php +++ b/tests/kohana/Config/GroupTest.php @@ -10,8 +10,8 @@ * @author Kohana Team * @author Jeremy Bush * @author Matt Button - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Config_GroupTest extends Kohana_Unittest_TestCase { diff --git a/tests/kohana/DebugTest.php b/tests/kohana/DebugTest.php index 39176ec17..3f845361e 100644 --- a/tests/kohana/DebugTest.php +++ b/tests/kohana/DebugTest.php @@ -13,8 +13,8 @@ * @category Tests * @author Kohana Team * @author Jeremy Bush - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_DebugTest extends Unittest_TestCase { diff --git a/tests/kohana/Http/HeaderTest.php b/tests/kohana/Http/HeaderTest.php index 0894b468e..8f241d3a5 100644 --- a/tests/kohana/Http/HeaderTest.php +++ b/tests/kohana/Http/HeaderTest.php @@ -11,8 +11,8 @@ * @package Kohana * @category Tests * @author Kohana Team - * @copyright (c) 2008-2012 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2008-2014 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_HTTP_HeaderTest extends Unittest_TestCase { From b109d1ea57acbd7517174acca452773370ecce8d Mon Sep 17 00:00:00 2001 From: Jeff Chan Date: Sat, 12 Apr 2014 04:56:38 +0000 Subject: [PATCH 03/12] Simplify Kohana::globals() test This simplifies the `test_globals_removes_user_def_globals` test to take advantage of PHPUnit's backupGlobals option which is on by default. There's no need to backup globals. In addition, changed to avoid directly assigning to $GLOBALS, since it is not allowed in HHVM. See: https://github.com/facebook/hhvm/blob/master/hphp/doc/inconsistencies#L127 --- tests/kohana/CoreTest.php | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/tests/kohana/CoreTest.php b/tests/kohana/CoreTest.php index a0099d103..0b93ac755 100644 --- a/tests/kohana/CoreTest.php +++ b/tests/kohana/CoreTest.php @@ -107,33 +107,15 @@ public function test_list_files_returns_array_on_success_and_failure() */ public function test_globals_removes_user_def_globals() { - // Store the globals - $temp_globals = array( - 'cookie' => $_COOKIE, - 'get' => $_GET, - 'files' => $_FILES, - 'post' => $_POST, - 'request' => $_REQUEST, - 'server' => $_SERVER, - 'session' => $_SESSION, - 'globals' => $GLOBALS, - ); - - $GLOBALS = array('hackers' => 'foobar','name' => array('','',''), '_POST' => array()); + $GLOBALS['hackers'] = 'foobar'; + $GLOBALS['name'] = array('','',''); + $GLOBALS['_POST'] = array(); Kohana::globals(); - $this->assertEquals(array('_POST' => array()), $GLOBALS); - - // Reset the globals for other tests - $_COOKIE = $temp_globals['cookie']; - $_GET = $temp_globals['get']; - $_FILES = $temp_globals['files']; - $_POST = $temp_globals['post']; - $_REQUEST = $temp_globals['request']; - $_SERVER = $temp_globals['server']; - $_SESSION = $temp_globals['session']; - $GLOBALS = $temp_globals['globals']; + $this->assertFalse(isset($GLOBALS['hackers'])); + $this->assertFalse(isset($GLOBALS['name'])); + $this->assertTrue(isset($GLOBALS['_POST'])); } /** From 611d56989103789944ab9aa91904a5fdc7a40ecb Mon Sep 17 00:00:00 2001 From: Kemo Date: Thu, 17 Apr 2014 01:45:34 +0200 Subject: [PATCH 04/12] Use `preg_replace_callback()` in `_ucwords()` /e modifier is deprecated since PHP 5.4 --- utf8/ucwords.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utf8/ucwords.php b/utf8/ucwords.php index 1411ff1d4..2cc8b35f9 100644 --- a/utf8/ucwords.php +++ b/utf8/ucwords.php @@ -15,9 +15,10 @@ function _ucwords($str) // [\x0c\x09\x0b\x0a\x0d\x20] matches form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns. // This corresponds to the definition of a 'word' defined at http://php.net/ucwords - return preg_replace( - '/(?<=^|[\x0c\x09\x0b\x0a\x0d\x20])[^\x0c\x09\x0b\x0a\x0d\x20]/ue', - 'UTF8::strtoupper(\'$0\')', - $str - ); + return preg_replace_callback( + '/(?<=^|[\x0c\x09\x0b\x0a\x0d\x20])[^\x0c\x09\x0b\x0a\x0d\x20]/u', + function($matches){ + return UTF8::strtoupper($matches[0]); + }, + $str); } From 122899681eb7073fc72c0a62d8df66fea035f56d Mon Sep 17 00:00:00 2001 From: Scott Arciszewski Date: Mon, 12 May 2014 21:15:56 -0400 Subject: [PATCH 05/12] Update Security.php --- classes/Kohana/Security.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/classes/Kohana/Security.php b/classes/Kohana/Security.php index b8f66c635..b07e499e4 100644 --- a/classes/Kohana/Security.php +++ b/classes/Kohana/Security.php @@ -81,8 +81,29 @@ public static function token($new = FALSE) */ public static function check($token) { - return Security::token() === $token; + return Security::slow_equals(Security::token(), $token); } + + + + /** + * Compare two hashes in a time-invariant manner. + * Prevents cryptographic side-channel attacks (timing attacks, specifically) + * + * @param string $a cryptographic hash + * @param string $b cryptographic hash + * @return boolean + */ + public static function slow_equals($a, $b) + { + $diff = strlen($a) ^ strlen($b); + for($i = 0; $i < strlen($a) AND $i < strlen($b); $i++) + { + $diff |= ord($a[$i]) ^ ord($b[$i]); + } + return $diff === 0; + } + /** * Remove image tags from a string. From ee0e121c665100b8f6899149db3cdea4cf0f7f6b Mon Sep 17 00:00:00 2001 From: Scott Arciszewski Date: Mon, 12 May 2014 21:16:19 -0400 Subject: [PATCH 06/12] Update Cookie.php --- classes/Kohana/Cookie.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Kohana/Cookie.php b/classes/Kohana/Cookie.php index dafb7f5a4..fe4cc490d 100644 --- a/classes/Kohana/Cookie.php +++ b/classes/Kohana/Cookie.php @@ -71,7 +71,7 @@ public static function get($key, $default = NULL) // Separate the salt and the value list ($hash, $value) = explode('~', $cookie, 2); - if (Cookie::salt($key, $value) === $hash) + if (Security::slow_equals(Cookie::salt($key, $value), $hash)) { // Cookie signature is valid return $value; From 31d8b4a8ee1032b2b150354e215cda9246e60062 Mon Sep 17 00:00:00 2001 From: Samuel Demirdjian Date: Mon, 9 Jun 2014 09:45:46 +0300 Subject: [PATCH 07/12] Allow query-only links in HTML::anchor Added tests for query-only and fragment-only links --- classes/Kohana/HTML.php | 4 ++-- tests/kohana/HTMLTest.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/classes/Kohana/HTML.php b/classes/Kohana/HTML.php index a78bc7621..ef226c2c8 100644 --- a/classes/Kohana/HTML.php +++ b/classes/Kohana/HTML.php @@ -126,9 +126,9 @@ public static function anchor($uri, $title = NULL, array $attributes = NULL, $pr $attributes['target'] = '_blank'; } } - elseif ($uri[0] !== '#') + elseif ($uri[0] !== '#' AND $uri[0] !== '?') { - // Make the URI absolute for non-id anchors + // Make the URI absolute for non-fragment and non-query anchors $uri = URL::site($uri, $protocol, $index); } } diff --git a/tests/kohana/HTMLTest.php b/tests/kohana/HTMLTest.php index 015a65da4..c4505bc40 100644 --- a/tests/kohana/HTMLTest.php +++ b/tests/kohana/HTMLTest.php @@ -223,6 +223,20 @@ public function test_style($expected, $file, array $attributes = NULL, $protocol public function provider_anchor() { return array( + // a fragment-only anchor + array( + 'Kohana', + array(), + '#go-to-section-kohana', + 'Kohana', + ), + // a query-only anchor + array( + 'Category A', + array(), + '?cat=a', + 'Category A', + ), array( 'Kohana', array(), From e9d912da372900c6904c5131a8ea6fb10365978e Mon Sep 17 00:00:00 2001 From: Kemo Date: Sun, 15 Jun 2014 00:33:24 +0200 Subject: [PATCH 08/12] Fix for issue #496 - bad Request::url() docblock --- classes/Kohana/Request.php | 1 - 1 file changed, 1 deletion(-) diff --git a/classes/Kohana/Request.php b/classes/Kohana/Request.php index ba7738548..bdc059ecf 100644 --- a/classes/Kohana/Request.php +++ b/classes/Kohana/Request.php @@ -740,7 +740,6 @@ public function uri($uri = NULL) * * echo URL::site($this->request->uri(), $protocol); * - * @param array $params URI parameters * @param mixed $protocol protocol string or Request object * @return string * @since 3.0.7 From 60c3105c8ac96c97b56766a7c8459f5b32d45e65 Mon Sep 17 00:00:00 2001 From: Andrew Coulton Date: Sat, 9 Aug 2014 23:40:41 +0100 Subject: [PATCH 09/12] Fix resending headers following redirect Fixes failing test - all header keys are lowercase internally so comparison was not working as expected and the header values were not being properly copied by array_intersect_assoc as that function compares both key and value. --- classes/Kohana/Request/Client.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/classes/Kohana/Request/Client.php b/classes/Kohana/Request/Client.php index 1190a30fc..3c35faf61 100644 --- a/classes/Kohana/Request/Client.php +++ b/classes/Kohana/Request/Client.php @@ -26,7 +26,7 @@ abstract class Kohana_Request_Client { /** * @var array Headers to preserve when following a redirect */ - protected $_follow_headers = array('Authorization'); + protected $_follow_headers = array('authorization'); /** * @var bool Follow 302 redirect with original request method? @@ -205,7 +205,7 @@ public function follow_headers($follow_headers = NULL) if ($follow_headers === NULL) return $this->_follow_headers; - $this->_follow_headers = $follow_headers; + $this->_follow_headers = array_map('strtolower', $follow_headers); return $this; } @@ -407,7 +407,8 @@ public static function on_header_location(Request $request, Response $response, // Prepare the additional request, copying any follow_headers that were present on the original request $orig_headers = $request->headers()->getArrayCopy(); - $follow_headers = array_intersect_assoc($orig_headers, array_fill_keys($client->follow_headers(), TRUE)); + $follow_header_keys = array_intersect(array_keys($orig_headers), $client->follow_headers()); + $follow_headers = \Arr::extract($orig_headers, $follow_header_keys); $follow_request = Request::factory($response->headers('Location')) ->method($follow_method) From 6b519fb074b7f378615e50dee47504e98dc1735d Mon Sep 17 00:00:00 2001 From: slik Date: Tue, 22 Jul 2014 22:05:36 +0300 Subject: [PATCH 10/12] since php 5.5.0 /e modifier is deprecated --- classes/Kohana/Text.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/classes/Kohana/Text.php b/classes/Kohana/Text.php index 7514fd66c..942538d42 100644 --- a/classes/Kohana/Text.php +++ b/classes/Kohana/Text.php @@ -295,8 +295,9 @@ public static function censor($str, $badwords, $replacement = '#', $replace_part if (UTF8::strlen($replacement) == 1) { - $regex .= 'e'; - return preg_replace($regex, 'str_repeat($replacement, UTF8::strlen(\'$1\'))', $str); + return preg_replace_callback($regex, function($matches) use ($replacement) { + return str_repeat($replacement, UTF8::strlen($matches[1])); + }, $str); } return preg_replace($regex, $replacement, $str); From ce8288fd583ebe881c9516adb285a196a0527ec6 Mon Sep 17 00:00:00 2001 From: Andrew Coulton Date: Tue, 12 Aug 2014 11:28:51 +0100 Subject: [PATCH 11/12] Fix Arr::get for ArrayObject on HHVM - fixes HTTP_Header behaviour HHVM 3.2.0 may emit a PHP Notice (Undefined Index) when calling isset on an ArrayObject that maps the keys in some way - for example the HTTP_Header object which converts all keys to lowercase - see https://github.com/facebook/hhvm/issues/3437 Implemented a workaround in Arr::get to resolve breaking tests for Kohana_Request_Client on HHVM. --- classes/Kohana/Arr.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/classes/Kohana/Arr.php b/classes/Kohana/Arr.php index 766369a81..fec1c2fa9 100644 --- a/classes/Kohana/Arr.php +++ b/classes/Kohana/Arr.php @@ -279,7 +279,13 @@ public static function range($step = 10, $max = 100) */ public static function get($array, $key, $default = NULL) { - return isset($array[$key]) ? $array[$key] : $default; + if ($array instanceof ArrayObject) { + // This is a workaround for inconsistent implementation of isset between PHP and HHVM + // See https://github.com/facebook/hhvm/issues/3437 + return $array->offsetExists($key) ? $array->offsetGet($key) : $default; + } else { + return isset($array[$key]) ? $array[$key] : $default; + } } /** From 952d6a888faaed4b214928b3642f15e328a7cb70 Mon Sep 17 00:00:00 2001 From: Andrew Coulton Date: Tue, 12 Aug 2014 13:12:04 +0100 Subject: [PATCH 12/12] Ensure Date::formatted_time always has expected timezone Always re-assign the requested timezone in Date::formatted_time - this will be a no-op if the timezone already matches, otherwise it will convert the time as required. It is not currently safe to make this a conditional call based on comparing the existing timezone name, because of facebook/hhvm#2302. --- classes/Kohana/Date.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/Kohana/Date.php b/classes/Kohana/Date.php index 692d658cb..930edc381 100644 --- a/classes/Kohana/Date.php +++ b/classes/Kohana/Date.php @@ -592,10 +592,10 @@ public static function formatted_time($datetime_str = 'now', $timestamp_format = $tz = new DateTimeZone($timezone ? $timezone : date_default_timezone_get()); $time = new DateTime($datetime_str, $tz); - if ($time->getTimeZone()->getName() !== $tz->getName()) - { - $time->setTimeZone($tz); - } + // Convert the time back to the expected timezone if required (in case the datetime_str provided a timezone, + // offset or unix timestamp. This also ensures that the timezone reported by the object is correct on HHVM + // (see https://github.com/facebook/hhvm/issues/2302). + $time->setTimeZone($tz); return $time->format($timestamp_format); }