Pretty-Printing JSON with PHP
我正在构建一个将JSON数据提供给另一个脚本的PHP脚本。我的脚本将数据构建成一个大型的关联数组,然后使用
1 2 3 | $data = array('a' => 'apple', 'b' => 'banana', 'c' => 'catnip'); header('Content-type: text/javascript'); echo json_encode($data); |
上述代码生成以下输出:
1 | {"a":"apple","b":"banana","c":"catnip"} |
如果您有少量的数据,这是很好的,但是我更喜欢这些数据:
1 2 3 4 5 | { "a":"apple", "b":"banana", "c":"catnip" } |
有没有一种方法可以在PHP中做到这一点而不需要一个丑陋的黑客?好像是Facebook的人发现的。
php 5.4提供了用于
http://php.net/manual/en/function.json-encode.php
1 2 3 |
输入
1 | {"key1":[1,2,3],"key2":"value"} |
产量
1 2 3 4 5 6 7 8 | { "key1": [ 1, 2, 3 ], "key2":"value" } |
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | function prettyPrint( $json ) { $result = ''; $level = 0; $in_quotes = false; $in_escape = false; $ends_line_level = NULL; $json_length = strlen( $json ); for( $i = 0; $i < $json_length; $i++ ) { $char = $json[$i]; $new_line_level = NULL; $post =""; if( $ends_line_level !== NULL ) { $new_line_level = $ends_line_level; $ends_line_level = NULL; } if ( $in_escape ) { $in_escape = false; } else if( $char === '"' ) { $in_quotes = !$in_quotes; } else if( ! $in_quotes ) { switch( $char ) { case '}': case ']': $level--; $ends_line_level = NULL; $new_line_level = $level; break; case '{': case '[': $level++; case ',': $ends_line_level = $level; break; case ':': $post =""; break; case"": case"\t": case" ": case" ": $char =""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .=" ".str_repeat("\t", $new_line_level ); } $result .= $char.$post; } return $result; } |
许多用户建议您使用
1 |
这是绝对正确的。但这还不够,浏览器需要了解数据类型,您可以在将数据回送给用户之前指定头。
1 |
这将导致格式良好的输出。
或者,如果您喜欢扩展,可以使用jsonview for chrome。
- 只设置头部,火狐会使用自己的内部JSON调试解析器完美地显示它,根本不需要触摸JSON的内容!谢谢您!!
我也有同样的问题。
不管怎样,我只是在这里使用了JSON格式代码:
http://recursive-design.com/blog/2008/03/11/format-json-with-php/
对我需要的东西很有效。
更为维护的版本:https://github.com/gerhobbelt/nicejson-php
我意识到这个问题是关于如何将关联数组编码为一个格式很好的JSON字符串,所以这并不能直接回答这个问题,但是如果您有一个已经是JSON格式的字符串,您可以通过对其进行解码和重新编码(需要php>=5.4)使其变得非常简单:
1 |
例子:
1 2 3 4 | header('Content-Type: application/json'); $json_ugly = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; $json_pretty = json_encode(json_decode($json_ugly), JSON_PRETTY_PRINT); echo $json_pretty; |
此输出:
1 2 3 4 5 6 7 | { "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 } |
I took the code from Composer : https://github.com/composer/composer/blob/master/src/Composer/Json/JsonFile.php and nicejson : https://github.com/GerHobbelt/nicejson-php/blob/master/nicejson.php
Composer code is good because it updates fluently from 5.3 to 5.4 but it only encodes object whereas nicejson takes json strings, so i merged them. The code can be used to format json string and/or encode objects, i'm currently using it in a Drupal module.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | if (!defined('JSON_UNESCAPED_SLASHES')) define('JSON_UNESCAPED_SLASHES', 64); if (!defined('JSON_PRETTY_PRINT')) define('JSON_PRETTY_PRINT', 128); if (!defined('JSON_UNESCAPED_UNICODE')) define('JSON_UNESCAPED_UNICODE', 256); function _json_encode($data, $options = 448) { if (version_compare(PHP_VERSION, '5.4', '>=')) { return json_encode($data, $options); } return _json_format(json_encode($data), $options); } function _pretty_print_json($json) { return _json_format($json, JSON_PRETTY_PRINT); } function _json_format($json, $options = 448) { $prettyPrint = (bool) ($options & JSON_PRETTY_PRINT); $unescapeUnicode = (bool) ($options & JSON_UNESCAPED_UNICODE); $unescapeSlashes = (bool) ($options & JSON_UNESCAPED_SLASHES); if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) { return $json; } $result = ''; $pos = 0; $strLen = strlen($json); $indentStr = ' '; $newLine =" "; $outOfQuotes = true; $buffer = ''; $noescape = true; for ($i = 0; $i < $strLen; $i++) { // Grab the next character in the string $char = substr($json, $i, 1); // Are we inside a quoted string? if ('"' === $char && $noescape) { $outOfQuotes = !$outOfQuotes; } if (!$outOfQuotes) { $buffer .= $char; $noescape = '\' === $char ? !$noescape : true; continue; } elseif ('' !== $buffer) { if ($unescapeSlashes) { $buffer = str_replace('\\/', '/', $buffer); } if ($unescapeUnicode && function_exists('mb_convert_encoding')) { // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($match) { return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); }, $buffer); } $result .= $buffer . $char; $buffer = ''; continue; } elseif(false !== strpos(" \t ", $char)) { continue; } if (':' === $char) { // Add a space after the : character $char .= ' '; } elseif (('}' === $char || ']' === $char)) { $pos--; $prevChar = substr($json, $i - 1, 1); if ('{' !== $prevChar && '[' !== $prevChar) { // If this character is the end of an element, // output a new line and indent the next line $result .= $newLine; for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } else { // Collapse empty {} and [] $result = rtrim($result) ." " . $indentStr; } } $result .= $char; // If the last character was the beginning of an element, // output a new line and indent the next line if (',' === $char || '{' === $char || '[' === $char) { $result .= $newLine; if ('{' === $char || '[' === $char) { $pos++; } for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } } // If buffer not empty after formating we have an unclosed quote if (strlen($buffer) > 0) { //json is incorrectly formatted $result = false; } return $result; } |
如果你在火狐上,安装jsonovich。我知道这不是一个真正的PHP解决方案,但它为开发/调试提供了技巧。
将几个答案粘在一起符合我对现有JSON的需求:
1 2 3 4 | Code: echo"[cc lang="php"]"; echo json_encode(json_decode($json_response), JSON_PRETTY_PRINT); echo" |
;输出:{"数据":{"token_type":"持票人","到期日期":3628799,"scopes":"完全访问","创建时间":1540504324}"错误":[,]"分页":,"token_type":"持票人","到期日期":3628799,"scopes":"完全访问","创建时间":1540504324}< /代码>
如果您有现有的JSON(
1 | echo nl2br(str_replace(' ', ' ', (json_encode(json_decode($ugly_json), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)))); |
结合
1 2 3 4 |
< /代码>
您可以在switch语句中稍微修改kendall-hopkins的答案,通过将JSON字符串传递到以下内容中,得到一个外观非常干净、缩进度很好的打印输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | function prettyPrint( $json ){ $result = ''; $level = 0; $in_quotes = false; $in_escape = false; $ends_line_level = NULL; $json_length = strlen( $json ); for( $i = 0; $i < $json_length; $i++ ) { $char = $json[$i]; $new_line_level = NULL; $post =""; if( $ends_line_level !== NULL ) { $new_line_level = $ends_line_level; $ends_line_level = NULL; } if ( $in_escape ) { $in_escape = false; } else if( $char === '"' ) { $in_quotes = !$in_quotes; } else if( ! $in_quotes ) { switch( $char ) { case '}': case ']': $level--; $ends_line_level = NULL; $new_line_level = $level; $char.=""; for($index=0;$index<$level-1;$index++){$char.="-----";} break; case '{': case '[': $level++; $char.=""; for($index=0;$index<$level;$index++){$char.="-----";} break; case ',': $ends_line_level = $level; $char.=""; for($index=0;$index<$level;$index++){$char.="-----";} break; case ':': $post =""; break; case"\t": case" ": case" ": $char =""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .=" ".str_repeat("\t", $new_line_level ); } $result .= $char.$post; } echo"RESULTS ARE: $result"; return $result; |
}
现在只需在PHP中运行prettyprint($yourjsonu string);并享受打印输出。如果你是一个极简主义者,并且出于某种原因不喜欢括号,你可以通过在$char的前三个开关盒中用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | RESULTS ARE: { - - -"results" : [ - - -- - - { - - -- - -- - -"address_components" : [ - - -- - -- - -- - - { - - -- - -- - -- - -- - -"long_name" :"Calgary" - - -- - -- - -- - -- - -"short_name" :"Calgary" - - -- - -- - -- - -- - -"types" : [ - - -- - -- - -- - -- - -- - -"locality" - - -- - -- - -- - -- - -- - -"political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - -"long_name" :"Division No. 6" - - -- - -- - -- - -- - -"short_name" :"Division No. 6" - - -- - -- - -- - -- - -"types" : [ - - -- - -- - -- - -- - -- - -"administrative_area_level_2" - - -- - -- - -- - -- - -- - -"political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - -"long_name" :"Alberta" - - -- - -- - -- - -- - -"short_name" :"AB" - - -- - -- - -- - -- - -"types" : [ - - -- - -- - -- - -- - -- - -"administrative_area_level_1" - - -- - -- - -- - -- - -- - -"political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - -"long_name" :"Canada" - - -- - -- - -- - -- - -"short_name" :"CA" - - -- - -- - -- - -- - -"types" : [ - - -- - -- - -- - -- - -- - -"country" - - -- - -- - -- - -- - -- - -"political" ] - - -- - -- - -- - - } - - -- - -- - - ] - - -- - - - - -- - -- - -"formatted_address" :"Calgary, AB, Canada" - - -- - -- - -"geometry" : { - - -- - -- - -- - -"bounds" : { - - -- - -- - -- - -- - -"northeast" : { - - -- - -- - -- - -- - -- - -"lat" : 51.18383 - - -- - -- - -- - -- - -- - -"lng" : -113.8769511 } - - -- - -- - -- - - - - -- - -- - -- - -- - -"southwest" : { - - -- - -- - -- - -- - -- - -"lat" : 50.84240399999999 - - -- - -- - -- - -- - -- - -"lng" : -114.27136 } - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - -"location" : { - - -- - -- - -- - -- - -"lat" : 51.0486151 - - -- - -- - -- - -- - -"lng" : -114.0708459 } - - -- - -- - - - - -- - -- - -- - -"location_type" :"APPROXIMATE" - - -- - -- - -- - -"viewport" : { - - -- - -- - -- - -- - -"northeast" : { - - -- - -- - -- - -- - -- - -"lat" : 51.18383 - - -- - -- - -- - -- - -- - -"lng" : -113.8769511 } - - -- - -- - -- - - - - -- - -- - -- - -- - -"southwest" : { - - -- - -- - -- - -- - -- - -"lat" : 50.84240399999999 - - -- - -- - -- - -- - -- - -"lng" : -114.27136 } - - -- - -- - -- - - } - - -- - -- - - } - - -- - - - - -- - -- - -"place_id" :"ChIJ1T-EnwNwcVMROrZStrE7bSY" - - -- - -- - -"types" : [ - - -- - -- - -- - -"locality" - - -- - -- - -- - -"political" ] - - -- - - } - - - ] - - -"status" :"OK" } |
全彩输出:微溶液
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | $s = '{"access": {"token": {"issued_at":"2008-08-16T14:10:31.309353","expires":"2008-08-17T14:10:31Z","id":"MIICQgYJKoZIhvcIegeyJpc3N1ZWRfYXQiOiAi <div class="suo-content">[collapse title=""]<ul><li>这很有帮助,尽管其中有一些错误。我把它们修好了,现在它像一个魔咒一样工作,而且功能一点也没有那么大!谢谢阿杰伊</li><li>如果有人想用这个的话,我只想评论一下修复的方法…在第二个和第三个if条件中添加一个验证检查$c>1,最后一个echo将其包装到一个is_数组($s)if中。这应该覆盖它,并且不应该得到任何未初始化的字符串偏移量错误。</li></ul>[/collapse]</div><hr><P>递归解决方案的经典案例。这是我的:</P>[cc lang="php"]class JsonFormatter { public static function prettyPrint(&$j, $indentor ="\t", $indent ="") { $inString = $escaped = false; $result = $indent; if(is_string($j)) { $bak = $j; $j = str_split(trim($j, '"')); } while(count($j)) { $c = array_shift($j); if(false !== strpos("{[,]}", $c)) { if($inString) { $result .= $c; } else if($c == '{' || $c == '[') { $result .= $c." "; $result .= self::prettyPrint($j, $indentor, $indentor.$indent); $result .= $indent.array_shift($j); } else if($c == '}' || $c == ']') { array_unshift($j, $c); $result .=" "; return $result; } else { $result .= $c." ".$indent; } } else { $result .= $c; $c == '"' && !$escaped && $inString = !$inString; $escaped = $c == '\' ? !$escaped : false; } } $j = $bak; return $result; } } |
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | php > require 'JsonFormatter.php'; php > $a = array('foo' => 1, 'bar' => 'This"is" bar', 'baz' => array('a' => 1, 'b' => 2, 'c' => '"3"')); php > print_r($a); Array ( [foo] => 1 [bar] => This"is" bar [baz] => Array ( [a] => 1 [b] => 2 [c] =>"3" ) ) php > echo JsonFormatter::prettyPrint(json_encode($a)); { "foo":1, "bar":"This "is" bar", "baz":{ "a":1, "b":2, "c":""3"" } } |
干杯
你可以像下面这样做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
上面的输出有点像Facebook。
1 2 3 4 5 | { "a" :"apple", "b" :"banana", "c" :"catnip" } |
这个解决方案使json"非常漂亮"。不完全符合OP的要求,但它可以让您更好地可视化JSON。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /** * takes an object parameter and returns the pretty json format. * this is a space saving version that uses 2 spaces instead of the regular 4 * * @param $in * * @return string */ function pretty_json ($in): string { return preg_replace_callback('/^ +/m', function (array $matches): string { return str_repeat(' ', strlen($matches[0]) / 2); }, json_encode($in, JSON_PRETTY_PRINT | JSON_HEX_APOS) ); } /** * takes a JSON string an adds colours to the keys/values * if the string is not JSON then it is returned unaltered. * * @param string $in * * @return string */ function markup_json (string $in): string { $string = 'green'; $number = 'darkorange'; $null = 'magenta'; $key = 'red'; $pattern = '/("(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/'; return preg_replace_callback($pattern, function (array $matches) use ($string, $number, $null, $key): string { $match = $matches[0]; $colour = $number; if (preg_match('/^"/', $match)) { $colour = preg_match('/:$/', $match) ? $key : $string; } elseif ($match === 'null') { $colour = $null; } return"<span style='color:{$colour}'>{$match}</span>"; }, str_replace(['<', '>', '&'], ['<', '>', '&'], $in) ) ?? $in; } public function test_pretty_json_object () { $ob = new \stdClass(); $ob->test = 'unit-tester'; $json = pretty_json($ob); $expected = <<<JSON { "test":"unit-tester" } JSON; $this->assertEquals($expected, $json); } public function test_pretty_json_str () { $ob = 'unit-tester'; $json = pretty_json($ob); $this->assertEquals(""$ob"", $json); } public function test_markup_json () { $json = <<<JSON [{"name":"abc","id":123,"warnings":[],"errors":null},{"name":"abc"}] JSON; $expected = <<<STR [ { <span style='color:red'>"name":</span> <span style='color:green'>"abc"</span>, <span style='color:red'>"id":</span> <span style='color:darkorange'>123</span>, <span style='color:red'>"warnings":</span> [], <span style='color:red'>"errors":</span> <span style='color:magenta'>null</span> }, { <span style='color:red'>"name":</span> <span style='color:green'>"abc"</span> } ] STR; $output = markup_json(pretty_json(json_decode($json))); $this->assertEquals($expected,$output); } |
}
如果您只使用
但是,如果您使用了类似jsonview的chrome扩展(即使没有上面的php选项),那么您将得到一个更可读的可调试解决方案,您甚至可以像这样轻松地折叠/折叠每个单独的json对象:
为PHP打印漂亮的打印
PHP示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | function print_nice($elem,$max_level=10,$print_nice_stack=array()){ if(is_array($elem) || is_object($elem)){ if(in_array($elem,$print_nice_stack,true)){ echo"<font color=red>RECURSION</font>"; return; } $print_nice_stack[]=&$elem; if($max_level<1){ echo"<font color=red>nivel maximo alcanzado</font>"; return; } $max_level--; echo"<table border=1 cellspacing=0 cellpadding=3 width=100%>"; if(is_array($elem)){ echo '<tr><td colspan=2 style="background-color:#333333;"><font color=white>ARRAY</font></td></tr>'; }else{ echo '<tr><td colspan=2 style="background-color:#333333;">'; echo '<font color=white>OBJECT Type: '.get_class($elem).'</font></td></tr>'; } $color=0; foreach($elem as $k => $v){ if($max_level%2){ $rgb=($color++%2)?"#888888":"#BBBBBB"; }else{ $rgb=($color++%2)?"#8888BB":"#BBBBFF"; } echo '<tr><td valign="top" style="width:40px;background-color:'.$rgb.';">'; echo ''.$k."</td><td>"; print_nice($v,$max_level,$print_nice_stack); echo"</td></tr>"; } echo"</table>"; return; } if($elem === null){ echo"<font color=green>NULL</font>"; }elseif($elem === 0){ echo"0"; }elseif($elem === true){ echo"<font color=green>TRUE</font>"; }elseif($elem === false){ echo"<font color=green>FALSE</font>"; }elseif($elem ===""){ echo"<font color=green>EMPTY STRING</font>"; }else{ echo str_replace(" ","<font color=red>*</font> ",$elem); } } |
1-
2-使用此功能Github
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php /** * Formats a JSON string for pretty printing * * @param string $json The JSON to make pretty * @param bool $html Insert nonbreaking spaces and <br />s for tabs and linebreaks * @return string The prettified output * @author Jay Roberts */ function _format_json($json, $html = false) { $tabcount = 0; $result = ''; $inquote = false; $ignorenext = false; if ($html) { $tab =" "; $newline ="<br/>"; } else { $tab ="\t"; $newline =" "; } for($i = 0; $i < strlen($json); $i++) { $char = $json[$i]; if ($ignorenext) { $result .= $char; $ignorenext = false; } else { switch($char) { case '[': case '{': $tabcount++; $result .= $char . $newline . str_repeat($tab, $tabcount); break; case ']': case '}': $tabcount--; $result = trim($result) . $newline . str_repeat($tab, $tabcount) . $char; break; case ',': $result .= $char . $newline . str_repeat($tab, $tabcount); break; case '"': $inquote = !$inquote; $result .= $char; break; case '\': if ($inquote) $ignorenext = true; $result .= $char; break; default: $result .= $char; } } } return $result; } |
以下是对我有用的:
test.php的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <html> <body> Testing JSON array output [cc lang="php"] <?php $data = array('a'=>'apple', 'b'=>'banana', 'c'=>'catnip'); // encode in json format $data = json_encode($data); // json as single line echo"</br>Json as single line </br>"; echo $data; // json as an array, formatted nicely echo"</br>Json as multiline array </br>"; print_r(json_decode($data, true)); ?> |
<正文>