Merge pull request #6064 from robmcvey/jsonView

2.6 jsonView should throw exception if json_encode fails
This commit is contained in:
José Lorenzo Rodríguez 2015-03-18 10:01:40 +01:00
commit 277f641108
3 changed files with 103 additions and 2 deletions

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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})";
}
}