Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F1262442
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/parser/PhutilJSON.php b/src/parser/PhutilJSON.php
index 0bcc4f76..5f43a625 100644
--- a/src/parser/PhutilJSON.php
+++ b/src/parser/PhutilJSON.php
@@ -1,155 +1,161 @@
<?php
/**
* Utilities for wrangling JSON.
*
* @task pretty Formatting JSON Objects
* @task internal Internals
*/
final class PhutilJSON extends Phobject {
/* -( Formatting JSON Objects )-------------------------------------------- */
/**
* Encode an object in JSON and pretty-print it. This generates a valid JSON
* object with human-readable whitespace and indentation.
*
* @param dict An object to encode in JSON.
* @return string Pretty-printed object representation.
*/
- public function encodeFormatted(array $object) {
+ public function encodeFormatted($object) {
return $this->encodeFormattedObject($object, 0)."\n";
}
/**
* Encode a list in JSON and pretty-print it, discarding keys.
*
* @param list<wild> List to encode in JSON.
* @return string Pretty-printed list representation.
*/
public function encodeAsList(array $list) {
return $this->encodeFormattedArray($list, 0)."\n";
}
/* -( Internals )---------------------------------------------------------- */
/**
* Pretty-print a JSON object.
*
* @param dict Object to format.
* @param int Current depth, for indentation.
* @return string Pretty-printed value.
* @task internal
*/
private function encodeFormattedObject($object, $depth) {
+ if ($object instanceof stdClass) {
+ $object = (array)$object;
+ }
+
if (empty($object)) {
return '{}';
}
$pre = $this->getIndent($depth);
$key_pre = $this->getIndent($depth + 1);
$keys = array();
$vals = array();
$max = 0;
foreach ($object as $key => $val) {
$ekey = $this->encodeFormattedValue((string)$key, 0);
$max = max($max, strlen($ekey));
$keys[] = $ekey;
$vals[] = $this->encodeFormattedValue($val, $depth + 1);
}
$key_lines = array();
foreach ($keys as $k => $key) {
$key_lines[] = $key_pre.$key.': '.$vals[$k];
}
$key_lines = implode(",\n", $key_lines);
$out = "{\n";
$out .= $key_lines;
$out .= "\n";
$out .= $pre.'}';
return $out;
}
/**
* Pretty-print a JSON list.
*
* @param list List to format.
* @param int Current depth, for indentation.
* @return string Pretty-printed value.
* @task internal
*/
private function encodeFormattedArray($array, $depth) {
if (empty($array)) {
return '[]';
}
$pre = $this->getIndent($depth);
$val_pre = $this->getIndent($depth + 1);
$vals = array();
foreach ($array as $val) {
$vals[] = $val_pre.$this->encodeFormattedValue($val, $depth + 1);
}
$val_lines = implode(",\n", $vals);
$out = "[\n";
$out .= $val_lines;
$out .= "\n";
$out .= $pre.']';
return $out;
}
/**
* Pretty-print a JSON value.
*
* @param dict Value to format.
* @param int Current depth, for indentation.
* @return string Pretty-printed value.
* @task internal
*/
private function encodeFormattedValue($value, $depth) {
if (is_array($value)) {
if (phutil_is_natural_list($value)) {
return $this->encodeFormattedArray($value, $depth);
} else {
return $this->encodeFormattedObject($value, $depth);
}
+ } else if (is_object($value)) {
+ return $this->encodeFormattedObject($value, $depth);
} else {
if (defined('JSON_UNESCAPED_SLASHES')) {
// If we have a new enough version of PHP, disable escaping of slashes
// when pretty-printing values. Escaping slashes can defuse an attack
// where the attacker embeds "</script>" inside a JSON string, but that
// isn't relevant when rendering JSON for human viewers.
return json_encode($value, JSON_UNESCAPED_SLASHES);
} else {
return json_encode($value);
}
}
}
/**
* Render a string corresponding to the current indent depth.
*
* @param int Current depth.
* @return string Indentation.
* @task internal
*/
private function getIndent($depth) {
if (!$depth) {
return '';
} else {
return str_repeat(' ', $depth);
}
}
}
diff --git a/src/parser/__tests__/PhutilJSONTestCase.php b/src/parser/__tests__/PhutilJSONTestCase.php
index 295d7b55..63630a9d 100644
--- a/src/parser/__tests__/PhutilJSONTestCase.php
+++ b/src/parser/__tests__/PhutilJSONTestCase.php
@@ -1,21 +1,50 @@
<?php
final class PhutilJSONTestCase extends PhutilTestCase {
public function testEmptyArrayEncoding() {
$serializer = new PhutilJSON();
$expect = <<<EOJSON
{
"x": []
}
EOJSON;
$this->assertEqual(
$expect,
$serializer->encodeFormatted(array('x' => array())),
pht('Empty arrays should serialize as `%s`, not `%s`.', '[]', '{}'));
}
+ public function testNestedObjectEncoding() {
+ $expect = <<<EOJSON
+{
+ "empty-object": {},
+ "pair-object": {
+ "duck": "quack"
+ }
+}
+
+EOJSON;
+
+ $empty_object = new stdClass();
+
+ $pair_object = new stdClass();
+ $pair_object->duck = 'quack';
+
+ $input = (object)array(
+ 'empty-object' => $empty_object,
+ 'pair-object' => $pair_object,
+ );
+
+ $serializer = new PhutilJSON();
+
+ $this->assertEqual(
+ $expect,
+ $serializer->encodeFormatted($input),
+ pht('Serialization of PHP-object JSON values.'));
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jan 24, 04:34 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
601540
Default Alt Text
(5 KB)
Attached To
Mode
R118 Arcanist - fork
Attached
Detach File
Event Timeline
Log In to Comment