Довольно-печать JSON с PHP
Я создаю PHP-скрипт, который передает данные JSON в другой скрипт. Мой скрипт строит данные в большой ассоциативный массив, а затем выводит данные с помощью json_encode. Вот пример скрипта:
$data = array('a' => 'apple', 'b' => 'banana', 'c' => 'catnip');
header('Content-type: text/javascript');
echo json_encode($data);
приведенный выше код дает следующий результат:
{"a":"apple","b":"banana","c":"catnip"}
это здорово, если у вас есть небольшое количество данных, но я бы предпочел что-то вроде этих строк:
{
"a": "apple",
"b": "banana",
"c": "catnip"
}
есть ли способ сделать это в PHP без грязный хак? Кажется, что кто-то в Facebook разобрался.
21 ответов:
PHP 5.4 предлагает
JSON_PRETTY_PRINTопция для использования сjson_encode()звонок.http://php.net/manual/en/function.json-encode.php
<?php ... $json_string = json_encode($data, JSON_PRETTY_PRINT);
эта функция будет принимать строку JSON и отступ его очень читаемый. Он также должен быть конвергентным,
prettyPrint( $json ) === prettyPrint( prettyPrint( $json ) )вход
{"key1":[1,2,3],"key2":"value"}выход
{ "key1": [ 1, 2, 3 ], "key2": "value" }код
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 "\n": case "\r": $char = ""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .= "\n".str_repeat( "\t", $new_line_level ); } $result .= $char.$post; } return $result; }
многие пользователи предложили использовать
echo json_encode($results, JSON_PRETTY_PRINT);что абсолютно верно. Но этого недостаточно, браузер должен понимать тип данных, вы можете указать заголовок непосредственно перед эхом данных обратно пользователю.
header('Content-Type: application/json');это приведет к хорошо отформатированный вывод.
или, если вам нравятся расширения, вы можете использовать JSONView для Chrome.
У меня была та же проблема.
в любом случае я просто использовал код форматирования JSON здесь:
http://recursive-design.com/blog/2008/03/11/format-json-with-php/
хорошо работает для того,что мне было нужно.
и более поддерживаемая версия:https://github.com/GerHobbelt/nicejson-php
Я понимаю, что этот вопрос задает вопрос о том, как кодировать ассоциативный массив в довольно форматированную строку JSON, поэтому это не дает прямого ответа на вопрос, но если у вас есть строка, которая уже находится в формате JSON, вы можете сделать это довольно просто, декодируя и перекодируя ее (требуется PHP >= 5.4):
$json = json_encode(json_decode($json), JSON_PRETTY_PRINT);пример:
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;вот результаты:
{ "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 }
Если вы находитесь на firefox install JSONovich. Не совсем PHP-решение, которое я знаю, но оно делает трюк для целей разработки/отладки.
Я взял код от композитора:https://github.com/composer/composer/blob/master/src/Composer/Json/JsonFile.php и nicejson:https://github.com/GerHobbelt/nicejson-php/blob/master/nicejson.php Код композитора хорош, потому что он свободно обновляется с 5.3 до 5.4, но он только кодирует объект, тогда как nicejson принимает строки json, поэтому я объединил их. Код можно использовать для форматирования строки json и / или кодирования объектов, в настоящее время я использую его в Drupal модуль.
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 = "\n"; $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\r\n", $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) . "\n\n" . $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; }
простой способ для php>5.4: как в Facebook graph
$Data = array('a' => 'apple', 'b' => 'banana', 'c' => 'catnip'); $json= json_encode($Data, JSON_PRETTY_PRINT); header('Content-Type: application/json'); print_r($json);результат в браузере
{ "a": "apple", "b": "banana", "c": "catnip" }
использовать
<pre>в сочетании сjson_encode()и :<pre> <?php echo json_encode($dataArray, JSON_PRETTY_PRINT); ?> </pre>
Если у вас есть существующий JSON (
$ugly_json)echo nl2br(str_replace(' ', ' ', (json_encode(json_decode($ugly_json), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES))));
вы можете немного изменить ответ Кендалла Хопкинса в операторе switch, чтобы получить довольно чистую и красиво отступленную распечатку, передав строку json в следующее:
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.="<br>"; for($index=0;$index<$level-1;$index++){$char.="-----";} break; case '{': case '[': $level++; $char.="<br>"; for($index=0;$index<$level;$index++){$char.="-----";} break; case ',': $ends_line_level = $level; $char.="<br>"; for($index=0;$index<$level;$index++){$char.="-----";} break; case ':': $post = " "; break; case "\t": case "\n": case "\r": $char = ""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .= "\n".str_repeat( "\t", $new_line_level ); } $result .= $char.$post; } echo "RESULTS ARE: <br><br>$result"; return $result;}
теперь просто запустите функцию prettyPrint ($your_json_string ); inline в вашем php и наслаждайтесь распечаткой. Если вы минималист и по какой-то причине не любите скобки, вы можете легко избавиться от них, заменив
$char.="<br>";С$char="<br>";в верхней тройке переключатель кейсы на $char. Вот что вы получаете за вызов Google maps API для города Калгари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" }
имейте выход цвета полный: малюсенькое разрешение
код:
$s = '{"access": {"token": {"issued_at": "2008-08-16T14:10:31.309353", "expires": "2008-08-17T14:10:31Z", "id": "MIICQgYJKoZIhvcIegeyJpc3N1ZWRfYXQiOiAi"}, "serviceCatalog": [], "user": {"username": "ajay", "roles_links": [], "id": "16452ca89", "roles": [], "name": "ajay"}}}'; $crl = 0; $ss = false; echo "<pre>"; for($c=0; $c<strlen($s); $c++) { if ( $s[$c] == '}' || $s[$c] == ']' ) { $crl--; echo "\n"; echo str_repeat(' ', ($crl*2)); } if ( $s[$c] == '"' && ($s[$c-1] == ',' || $s[$c-2] == ',') ) { echo "\n"; echo str_repeat(' ', ($crl*2)); } if ( $s[$c] == '"' && !$ss ) { if ( $s[$c-1] == ':' || $s[$c-2] == ':' ) echo '<span style="color:#0000ff;">'; else echo '<span style="color:#ff0000;">'; } echo $s[$c]; if ( $s[$c] == '"' && $ss ) echo '</span>'; if ( $s[$c] == '"' ) $ss = !$ss; if ( $s[$c] == '{' || $s[$c] == '[' ) { $crl++; echo "\n"; echo str_repeat(' ', ($crl*2)); } } echo $s[$c];
вы могли бы сделать это, как показано ниже.
$array = array( "a" => "apple", "b" => "banana", "c" => "catnip" ); foreach ($array as $a_key => $a_val) { $json .= "\"{$a_key}\" : \"{$a_val}\",\n"; } header('Content-Type: application/json'); echo "{\n" .rtrim($json, ",\n") . "\n}";выше будет выводить вроде как Facebook.
{ "a" : "apple", "b" : "banana", "c" : "catnip" }
Если вы использовали только
$json_string = json_encode($data, JSON_PRETTY_PRINT);, вы получите в браузере что-то вроде этого (используя Facebook link из вопроса :) ):но если вы использовали расширение Chrome, как JSONView (даже без опции PHP выше), то вы получите больше довольно читаемое отладочное решение где вы можете даже сложить / свернуть каждый отдельный объект JSON легко, как это:
классический случай для рекурсивного решения. Вот мой:
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."\n"; $result .= self::prettyPrint($j, $indentor, $indentor.$indent); $result .= $indent.array_shift($j); } else if($c == '}' || $c == ']') { array_unshift($j, $c); $result .= "\n"; return $result; } else { $result .= $c."\n".$indent; } } else { $result .= $c; $c == '"' && !$escaped && $inString = !$inString; $escaped = $c == '\' ? !$escaped : false; } } $j = $bak; return $result; } }использование:
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\"" } }Ура
print_r pretty print для PHP
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;"><strong><font color=white>ARRAY</font></strong></td></tr>'; }else{ echo '<tr><td colspan=2 style="background-color:#333333;"><strong>'; echo '<font color=white>OBJECT Type: '.get_class($elem).'</font></strong></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 '<strong>'.$k."</strong></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("\n","<strong><font color=red>*</font></strong><br>\n",$elem); } }
1 -
json_encode($rows,JSON_PRETTY_PRINT);возвращает уточненные данные с символами новой строки. Это полезно для ввода командной строки, но как вы обнаружили не так хороша в браузере. Браузер будет принимать новые строки в качестве источника (и, таким образом, просмотр источника страницы действительно покажет довольно JSON), но они не используются для форматирования вывода в браузерах. Браузеры, использующие HTML.2-Используйте эту функцию github
<?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 = "\n"; } 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; }
Это решение делает "очень красивый" JSON. Не совсем то, что просил OP, но это позволяет вам лучше визуализировать JSON.
/** * 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); }}
вот что сработало для меня:
содержание теста.php:
<html> <body> Testing JSON array output <pre> <?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)); ?> </pre> </body> </html>выход:
Testing JSON array output Json as single line {"a":"apple","b":"banana","c":"catnip"} Json as multiline array Array ( [a] => apple [b] => banana [c] => catnip )также обратите внимание на использование тега "pre" в html.
надеюсь, что это поможет кому-то
Если вы работаете с MVC
попробуйте сделать это в ваш контроллер
public function getLatestUsers() { header('Content-Type: application/json'); echo $this->model->getLatestUsers(); // this returns json_encode($somedata, JSON_PRETTY_PRINT) }тогда если вы вызовете /getLatestUsers вы получите довольно JSON выход ;)
у меня нет достаточной репутации, чтобы ответить Кендаллу Хопкинсу, но я нашел ошибку в его красивом (он тоже подошел неловко)
эта строка должна быть изменена:
if( $char === '"' && $prev_char != '\' ) {до
if( $char === '"' && ($prev_char != '\' && $prev_prev_char != '\' ) {prettifier ломается и создает недопустимый json, когда строка заканчивается обратной косой чертой, например:
"kittens\"


Comments