diff --git a/lib/Cake/Test/Case/View/JsonViewTest.php b/lib/Cake/Test/Case/View/JsonViewTest.php index 5a661c78b..4e4eb2574 100644 --- a/lib/Cake/Test/Case/View/JsonViewTest.php +++ b/lib/Cake/Test/Case/View/JsonViewTest.php @@ -28,6 +28,11 @@ App::uses('JsonView', 'View'); */ class JsonViewTest extends CakeTestCase { +/** + * setUp method + * + * @return void + **/ public function setUp() { parent::setUp(); Configure::write('debug', 0); @@ -156,6 +161,20 @@ class JsonViewTest extends CakeTestCase { ); } +/** + * Custom error handler for use while testing methods that use json_encode + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + * @return void + * @throws CakeException + **/ + public function jsonEncodeErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) { + throw new CakeException($errstr, 0, $errno, $errfile, $errline); + } + /** * Test render with a valid string in _serialize. * @@ -306,4 +325,56 @@ class JsonViewTest extends CakeTestCase { $this->assertSame($expected, $output); $this->assertSame('application/javascript', $Response->type()); } + +/** + * JsonViewTest::testRenderInvalidJSON() + * + * @return void + */ + public function testRenderInvalidJSON() { + $Request = new CakeRequest(); + $Response = new CakeResponse(); + $Controller = new Controller($Request, $Response); + + // non utf-8 stuff + $data = array('data' => array('foo' => 'bar' . chr('0x97'))); + + $Controller->set($data); + $Controller->set('_serialize', 'data'); + $View = new JsonView($Controller); + + // Use a custom error handler + set_error_handler(array($this, 'jsonEncodeErrorHandler')); + + try { + $View->render(); + restore_error_handler(); + $this->fail('Failed asserting that exception of type "CakeException" is thrown.'); + } catch (CakeException $e) { + restore_error_handler(); + $this->assertRegExp('/UTF-8/', $e->getMessage()); + return; + } + } + +/** + * JsonViewTest::testRenderJSONBoolFalse() + * + * @return void + */ + public function testRenderJSONBoolFalse() { + $Request = new CakeRequest(); + $Response = new CakeResponse(); + $Controller = new Controller($Request, $Response); + + // encoding a false, ensure this doesn't trigger exception + $data = false; + + $Controller->set($data); + $Controller->set('_serialize', 'data'); + $View = new JsonView($Controller); + $output = $View->render(); + $this->assertSame('null', $output); + } + } diff --git a/lib/Cake/View/JsonView.php b/lib/Cake/View/JsonView.php index 2f184139d..7953803de 100644 --- a/lib/Cake/View/JsonView.php +++ b/lib/Cake/View/JsonView.php @@ -126,6 +126,7 @@ class JsonView extends View { * Serialize view vars * * @param array $serialize The viewVars that need to be serialized + * @throws CakeException * @return string The serialized data */ protected function _serialize($serialize) { @@ -145,10 +146,17 @@ class JsonView extends View { } if (version_compare(PHP_VERSION, '5.4.0', '>=') && Configure::read('debug')) { - return json_encode($data, JSON_PRETTY_PRINT); + $json = json_encode($data, JSON_PRETTY_PRINT); + } else { + $json = json_encode($data); } - return json_encode($data); + if (function_exists('json_last_error') && json_last_error() !== JSON_ERROR_NONE) { + throw new CakeException(json_last_error_msg()); + } elseif ($json === false) { + throw new CakeException('Failed to parse JSON'); + } + return $json; } } diff --git a/lib/Cake/basics.php b/lib/Cake/basics.php index 8dc20a015..9ca5a93db 100644 --- a/lib/Cake/basics.php +++ b/lib/Cake/basics.php @@ -1061,3 +1061,25 @@ if (!function_exists('convertSlash')) { } } + +if (!function_exists('json_last_error_msg')) { + +/** + * Provides the fallback implementation of json_last_error_msg() available in PHP 5.5 and above. + * + * @return string Error message. + */ + function json_last_error_msg() { + static $errors = array( + JSON_ERROR_NONE => '', + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', + JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', + JSON_ERROR_SYNTAX => 'Syntax error', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' + ); + $error = json_last_error(); + return array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})"; + } + +}