Formatting JSON With PHP

The built-in json_encode() function in PHP puts everything on one line. For development and debugging, it can often be more useful to have properly indented, human-readable JSON that makes it easier to manually inspect the encoded data and check it for problems.

Here’s a function that lets you format/pretty-print any JSON string to be more readable:

/**
 * Indents a flat JSON string to make it more human-readable.
 *
 * @param string $json The original JSON string to process.
 * @param string $indentStr The string used for indenting nested structures. Defaults to 4 spaces.
 * @return string Indented version of the original JSON string.
 */
function pretty_json($json, $indentStr = '    ') {

	$result      = '';
	$level       = 0;
	$strLen      = strlen($json);
	$newLine     = "\n";
	$prevChar    = '';
	$outOfQuotes = true;
	$openingBracket = false;

	for ($i = 0; $i <= $strLen; $i++) {

		// Grab the next character in the string.
		$char = substr($json, $i, 1);

		// Add spaces before and after :
		if (($char == ':' && $prevChar != ' ') || ($prevChar == ':' && $char != ' ')) {
			if ($outOfQuotes) {
				$result .= ' ';
			}
		}

		// Are we inside a quoted string?
		if ($char == '"' && $prevChar != '\\') {
			$outOfQuotes = !$outOfQuotes;

			// If this character is the end of a non-empty element,
			// output a new line and indent the next line.
		} else if(($char == '}' || $char == ']') && $outOfQuotes) {
			$level --;
			if (!$openingBracket) {
				$result .= $newLine . str_repeat($indentStr, $level);
			}
		}

		// Add the character to the result string.
		$result .= $char;

		// If the last character was the beginning of a non-empty element,
		// output a new line and indent the next line.
		$openingBracket = ($char == '{' || $char == '[');
		if (($char == ',' || $openingBracket) && $outOfQuotes) {
			if ($openingBracket) {
				$level ++;
			}

			$nextChar = substr($json, $i + 1, 1);
			if ( ! ($openingBracket && ($nextChar == '}' || $nextChar == ']')) ) {
				$result .= $newLine . str_repeat($indentStr, $level);
			}
		}

		$prevChar = $char;
	}

	return $result;
}

Usage example:

$sampleData = array(
	'nested' => array(
		'a' => array(
			'b' => 1,
			'c' => null,
			'd' => array(1, 2, 3, 4)
		),
		'x' => array(1, 2, null, 'foo'),
		'y' => 3.14,
	),
	'special_chars' => ":,\'\"/\()[]&\r\n\t!",
	'escapes' => "\xc3\xa9",
	'empty_object' => new stdClass(),
	'empty_array' => array(),
);

$json = json_encode($sampleData);
echo "json_encode() output:\n", $json, "\n\n";

$pretty = pretty_json($json);
echo "Formatted JSON:\n", $pretty;

Output:

json_encode() output:
{"nested":{"a":{"b":1,"c":null,"d":[1,2,3,4]},"x":[1,2,null,"foo"],"y":3.14},"special_chars":":,\\'\"\/\\()[]&\r\n\t!","escapes":"\u00e9","empty_object":{},"empty_array":[]}

Formatted JSON:
{
    "nested" : {
        "a" : {
            "b" : 1,
            "c" : null,
            "d" : [
                1,
                2,
                3,
                4
            ]
        },
        "x" : [
            1,
            2,
            null,
            "foo"
        ],
        "y" : 3.14
    },
    "special_chars" : ":,\\'\"\/\\()[]&\r\n\t!",
    "escapes" : "\u00e9",
    "empty_object" : {},
    "empty_array" : []
}

Credit for the original JSON indentation function goes to Recursive Design. I have also made a few changes of my own:

  • Add spaces around colons (based on this gist).
  • Print empty arrays and objects on a single line.
  • Configurable indentation (defaults to 4 spaces).
Related posts :

2 Responses to “Formatting JSON With PHP”

  1. steve says:

    Great function, one thing I would like to see or if you could point me how to do this part would be , instead of a new line on things like “test”: [ /n “35” /n ] if it would be possible to do something like this

    “count”: [12000, 20000],
    or
    “description”: {“text”: “…”, “sensitive”: false}

    ?

  2. Jānis Elsts says:

    Well, that depends on what you want to do with nested dictionaries like {“a” : {“text” : “…”, “object” : {…}, “b” : “c”}}.

    If you just want everything to be on one line, then it’s very easy. Just remove the code that adds newlines.

    On the other hand, if you want to do something more complex, like putting “simple” arrays on one line but adding newlines to hierarchical structures, that’s going to be a whole lot harder (maybe even impossible without writing your own JSON serializer).

Leave a Reply