Human Readable JSON: aka Add spaces and breaks to json dump - php

Is there a "simple" script somewhere that will take a json data and format it to make it more readable?
For example:
// $response is a json encoded string.
var_dump($response);
The above outputs everything on one line. I'd like for it to be indented and spaced to make it easier to read.

Note that var_dump and its terser cousin var_export do print newlines.
Bear in mind that newlines are not shown in HTML document by default. In an HTML context, you want this instead:
echo '<div style="font-family: monospace; white-space:pre;">';
echo htmlspecialchars(var_export($response));
echo '</div>';
In php 5.4+, you can simply use the PRETTY_PRINT flag of json_encode:
echo json_encode($response, JSON_PRETTY_PRINT);
Again, in an HTML context, you'll have to wrap it as described above.

Paste it into JSONLint.com and click validate.

Had a similar problem, in that I was posting a serialised javascript object to a php script and wished to save it to the server in a human-readable format.
Found this post on the webdeveloper.com forum and tweaked the code very slightly to suit my own sensibilities (it takes a json encoded string):
function jsonToReadable($json){
$tc = 0; //tab count
$r = ''; //result
$q = false; //quotes
$t = "\t"; //tab
$nl = "\n"; //new line
for($i=0;$i<strlen($json);$i++){
$c = $json[$i];
if($c=='"' && $json[$i-1]!='\\') $q = !$q;
if($q){
$r .= $c;
continue;
}
switch($c){
case '{':
case '[':
$r .= $c . $nl . str_repeat($t, ++$tc);
break;
case '}':
case ']':
$r .= $nl . str_repeat($t, --$tc) . $c;
break;
case ',':
$r .= $c;
if($json[$i+1]!='{' && $json[$i+1]!='[') $r .= $nl . str_repeat($t, $tc);
break;
case ':':
$r .= $c . ' ';
break;
default:
$r .= $c;
}
}
return $r;
}
passing in
{"object":{"array":["one","two"],"sub-object":{"one":"string","two":2}}}
returns
{
"object": {
"array": [
"one",
"two"
],
"sub-object": {
"one": "string",
"two": 2
}
}
}

json_encode($response, JSON_PRETTY_PRINT);
It's 2017 and I think this should be the answer for anyone on a modern version of PHP.
Note that lots of options exist for how to encode the JSON string to your liking. From php.net:
JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT, JSON_PRESERVE_ZERO_FRACTION, JSON_UNESCAPED_UNICODE, JSON_PARTIAL_OUTPUT_ON_ERROR

echo '<pre>';
print_r(json_decode($response));
echo '</pre>';
Too simple?

Pipe it through python -mjson.tool.

The suggestion of using python worked well for me. Here's some code to use this from PHP:
function jsonEncode( $data, $pretty = false ) {
$str = json_encode($data);
if( $pretty ) {
$descriptorSpec = array(
0 => array('pipe', 'r'), // stdin is a pipe that the child will read from
1 => array('pipe', 'w'), // stdout is a pipe that the child will write to
);
$fp = proc_open('/usr/bin/python -mjson.tool', $descriptorSpec, $pipes);
fputs($pipes[0], $str);
fclose($pipes[0]);
$str = '';
while( !feof($pipes[1]) ) {
$str .= $chunk = fgets($pipes[1], 1024);
}
fclose($pipes[1]);
}
return $str;
}

Related

How to pass a PHP array to a BASH script?

I have a php script and a bash script. They're in the same directory. I'm running the php script from the command line which will pass an array to the bash script. I'm trying to do the following:
pass a PHP array to the BASH script
get user input from STDIN
pass the user input back to the PHP script for further processing
Here's my php script:
<?php
$a=array("red","green","blue","yellow");
$string = '(' . implode(' ', $a) . ')'; // (red green blue yellow)
$user_response = shell_exec('./response.sh $string');
// do something with $user_response
?>
The BASH script is supposed to read the array from STDIN and prompt the user to select an option:
#!/bin/bash
options=$($1); # (red green blue yellow) but this isn't working
i=0;
echo "select an option";
for each in "${options[#]}"
do
echo "[$i] $each"
i=$((i+1))
done
echo;
read input;
echo "You picked option ${options[$input]}";
# here's where I want to pass or export the input back to the
# php script for further processing
When I run the php script it doesn't display the array options.
I'd say the easiest would be not to try and emulate an internal bash array, but use 'normal' logic / post-processing. For example; if you simply pass implode(' ', $a) to the bash script (you should also pass it through escapeshellarg()):
$a=array("red","green","blue","yellow");
$args = implode(' ', array_map('escapeshellarg', $a));
$user_response = shell_exec('./response.sh '. $args);
Then you can traverse the arguments in bash using
for each in $*; do
echo $each
done
The issue with your solution is that the output of the Shell Script is actually IN the PHP $response variable:
SHELL script:
#!/bin/bash
echo "Before prompt"
read -p 'Enter a value: ' input
echo "You entered $input"
PHP script:
<?php
$shell = shell_exec("./t.sh");
echo "SHELL RESPONSE\n$shell\n";
Result of php t.php:
$ php t.php
Enter a value: foo
SHELL RESPONSE
Before prompt
You entered foo
You captured the entire STDOUT of the Shell Script.
If you are looking to simply pass values to a shell script, the option of $option_string = implode(' ', $array_of_values); will work to place options individually for the script. If you would like something a little more advanced (setting flags, assigning things, etc) try this (https://ideone.com/oetqaY):
function build_shell_args(Array $options = array(), $equals="=") {
static $ok_chars = '/^[-0-9a-z_:\/\.]+$/i';
$args = array();
foreach ($options as $key => $val) if (!is_null($val) && $val !== FALSE) {
$arg = '';
$key_len = 0;
if(is_string($key) && ($key_len = strlen($key)) > 0) {
if(!preg_match($ok_chars, $key))
$key = escapeshellarg($key);
$arg .= '-'.(($key_len > 1) ? '-' : '').$key;
}
if($val !== TRUE) {
if((string) $val !== (string) (int) $val) {
$val = print_r($val, TRUE);
if(!preg_match($ok_chars, $val))
$val = escapeshellarg($val);
}
if($key_len != 0)
$arg .= $equals;
$arg .= $val;
}
if(!empty($arg))
$args[] = $arg;
}
return implode(' ', $args);
}
That will be about your most comprehensive solution for passing to the command line.
If you are instead looking for a way to prompt the user (in general), I would consider staying inside PHP. The most basic way is:
print_r("$question : ");
$fp = fopen('php://stdin', 'r');
$response = fgets($fp, 1024);
Or, to support validating the question, multi-line, and only calling on CLI:
function prompt($message = NULL, $validator = NULL, $terminator = NULL, $include_terminating_line = FALSE) {
if(PHP_SAPI != 'cli') {
throw new \Exception('Can not Prompt. Not Interactive.');
}
$return = '';
// Defaults to 0 or more of any character.
$validator = !is_null($validator) ? $validator : '/^.*$/';
// Defaults to a lonely new-line character.
$terminator = !is_null($terminator) ? $terminator : "/^\\n$/";
if(#preg_match($validator, NULL) === FALSE) {
throw new Exception("Prompt Validator Regex INVALID. - '$validator'");
}
if(#preg_match($terminator, NULL) === FALSE) {
throw new Exception("Prompt Terminator Regex INVALID. - '$terminator'");
}
$fp = fopen('php://stdin', 'r');
$message = print_r($message,true);
while (TRUE) {
print_r("$message : ");
while (TRUE) {
$line = fgets($fp, 1024); // read the special file to get the user input from keyboard
$terminate = preg_match($terminator, $line);
$valid = preg_match($validator, $line);
if (!empty($valid) && (empty($terminate) || $include_terminating_line)) {
$return .= $line;
}
if (!empty($terminate)) {
break 2;
}
if(empty($valid)) {
print_r("\nInput Invalid!\n");
break;
}
}
}
return $return;
}
You can have your shell script as this:
#!/bin/bash
options=("$#")
i=0
echo "select an option"
for str in "${options[#]}"; do
echo "[$i] $str"
((i++))
done
echo
read -p 'Enter an option: ' input
echo "You picked option ${options[$input]}"
Then have your PHP code as this:
<?php
$a=array("red","green","blue","yellow");
$string = implode(' ', $a);
$user_response = shell_exec("./response.sh $string");
echo "$user_response\n";
?>
However keep in mind output will be like this when running from PHP:
php -f test.php
Enter an option: 2
select an option
[0] red
[1] green
[2] blue
[3] yellow
You picked option blue
i.e. user input will come before the output from script is shown.
Since parentheses run what's in them in a sub-shell, which isn't what I think you want...
I would change this...
$string = '(' . implode(' ', $a) . ')';
To this...
$string = '"' . implode (' ', $a) . '"';
Also, use double quotes here...
$user_response = shell_exec ("./response.sh $string");
Or break out...
$user_response = shell_exec ('./response.sh ' . $string);
I would therefore also change the BASH to simply accept a single argument, a string, and split that argument into an array to get our options.
Like so...
#!/bin/bash
IFS=' ';
read -ra options <<< "$1";
i=0;
echo "select an option";
for each in "${options[#]}"; do
echo "[$i] $each";
i=$((i+1));
done;
unset i;
echo;
read input;
echo "You picked option " ${options[$input]};

View a PHP Closure's Source

Is it possible to reflect into or otherwise view the source of a PHP closure object? That is, if I do something like this
$closure = function()
{
return 'Hi There';
};
and then something like this
var_dump($closure);
PHP outputs
object(Closure)[14]
That is, I know the object's a closure, but I have no idea what it does.
I'm looking for a reflection method, function, or debugging extension that will allow me to dump the actual body of anonymous function.
What you can get from PHP is limited, using reflection you can just obtain the parameter signature of the function and the start and ending line of the source code file. I've once wrote a blog article about that: http://www.metashock.de/2013/05/dump-source-code-of-closure-in-php/ ...
It lead me to the following code, using reflection:
function closure_dump(Closure $c) {
$str = 'function (';
$r = new ReflectionFunction($c);
$params = array();
foreach($r->getParameters() as $p) {
$s = '';
if($p->isArray()) {
$s .= 'array ';
} else if($p->getClass()) {
$s .= $p->getClass()->name . ' ';
}
if($p->isPassedByReference()){
$s .= '&';
}
$s .= '$' . $p->name;
if($p->isOptional()) {
$s .= ' = ' . var_export($p->getDefaultValue(), TRUE);
}
$params []= $s;
}
$str .= implode(', ', $params);
$str .= '){' . PHP_EOL;
$lines = file($r->getFileName());
for($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) {
$str .= $lines[$l];
}
return $str;
}
If you have the following closure:
$f = function (Closure $a, &$b = -1, array $c = array())
use ($foo)
{
echo $this->name;
echo 'test';
};
closure_dump() will give the following results:
function (Closure $a, &$b = -1, array $c = array (
)){
use ($foo)
{
echo $this->name;
echo 'test';
};
You see it is imperfect (the array param). Also it will not handle some edge cases properly, especially if closures are nested or multiple inline closures will getting passed to a function in one line. The latter looks most problematic to me. Since, you get only the starting and ending line from reflection, both functions will be on that line in this case and you have no useful information to decide which one of them should get dumped. So far, I didn't found a solution for that, also I'm unsure if there is a solution.
However, in most cases, it should at least being helpful for debugging, as long as you don't rely on it. Feel free to enhance it!

CSV to JSON with PHP?

I need to convert a CSV file to JSON on the server using PHP. I am using this script which works:
function csvToJSON($csv) {
$rows = explode("\n", $csv);
$i = 0;
$len = count($rows);
$json = "{\n" . ' "data" : [';
foreach ($rows as $row) {
$cols = explode(',', $row);
$json .= "\n {\n";
$json .= ' "var0" : "' . $cols[0] . "\",\n";
$json .= ' "var1" : "' . $cols[1] . "\",\n";
$json .= ' "var2" : "' . $cols[2] . "\",\n";
$json .= ' "var3" : "' . $cols[3] . "\",\n";
$json .= ' "var4" : "' . $cols[4] . "\",\n";
$json .= ' "var5" : "' . $cols[5] . "\",\n";
$json .= ' "var6" : "' . $cols[6] . "\",\n";
$json .= ' "var7" : "' . $cols[7] . "\",\n";
$json .= ' "var8" : "' . $cols[8] . "\",\n";
$json .= ' "var9" : "' . $cols[9] . "\",\n";
$json .= ' "var10" : "' . $cols[10] . '"';
$json .= "\n }";
if ($i !== $len - 1) {
$json .= ',';
}
$i++;
}
$json .= "\n ]\n}";
return $json;
}
$json = csvToJSON($csv);
$json = preg_replace('/[ \n]/', '', $json);
header('Content-Type: text/plain');
header('Cache-Control: no-cache');
echo $json;
The $csv variable is a string resulting from a cURL request which returns the CSV content.
I am sure this is not the most efficient PHP code to do it because I am a beginner developer and my knowledge of PHP is low. Is there a better, more efficient way to convert CSV to JSON using PHP?
Thanks in advance.
Note. I am aware that I am adding whitespace and then removing it, I do this so I can have the option to return "readable" JSON by removing the line $json = preg_replace('/[ \n]/', '', $json); for testing purposes.
Edit. Thanks for your replies, based on them the new code is like this:
function csvToJson($csv) {
$rows = explode("\n", trim($csv));
$csvarr = array_map(function ($row) {
$keys = array('var0','var1','var2','var3','var4','var5','var6','var7','var8','var9','var10');
return array_combine($keys, str_getcsv($row));
}, $rows);
$json = json_encode($csvarr);
return $json;
}
$json = csvToJson($csv);
header('Content-Type: application/json');
header('Cache-Control: no-cache');
echo $json;
Well there is the json_encode() function, which you should use rather than building up the JSON output yourself. And there is also a function str_getcsv() for parsing CSV:
$array = array_map("str_getcsv", explode("\n", $csv));
print json_encode($array);
You must however adapt the $array if you want the JSON output to hold named fields.
I modified the answer in the question to use the first line of the CSV for the array keys. This has the advantage of not having to hard-code the keys in the function allowing it to work for any CSV with column headers and any number of columns.
Here is my modified version:
function csvToJson($csv) {
$rows = explode("\n", trim($csv));
$data = array_slice($rows, 1);
$keys = array_fill(0, count($data), $rows[0]);
$json = array_map(function ($row, $key) {
return array_combine(str_getcsv($key), str_getcsv($row));
}, $data, $keys);
return json_encode($json);
}
None of these answers work with multiline cells, because they all assume a row ends with '\n'. The builtin fgetcsv function understands that multiline cells are enclosed in " so it doesn't run into the same problem. The code below instead of relying on '\n' to find each row of a csv lets fgetcsv go row by row and prep our output.
function csv_to_json($file){
$columns = fgetcsv($file); // first lets get the keys.
$output = array(); // we will build out an array of arrays here.
while(!feof($file)){ // until we get to the end of file, we'll pull in a new line
$line = fgetcsv($file); // gets the next line
$lineObject = array(); // we build out each line with our $columns keys
foreach($columns as $key => $value){
$lineObject[$value] = $line[$key];
}
array_push($output, $lineObject);
}
return json_encode($output); // encode it as json before sending it back
}
Some tips...
If you have URL opening enabled for fopen() and wrappers, you can use fgetscsv().
You can build an array of the CSV, and then convert it with PHP's native json_encode().
The correct mime type for JSON is application/json.
You could probably reduce the overhead by removing all the spaces and \n's. But that's in your note.
You could increase the performance by skipping the preg_replace and passing a boolean that would turn it on and off.
Other than that, the variable unrolling of your var[1-10] actually is good, as long as there are always ten varaibles.
The explode and the foreach approach are just fine.
I recommend using Coseva (a csv parsing library) and using the built in toJSON() method.
<?php
// load
require('../src/CSV.php');
// read
$csv = new Coseva\CSV('path/to/my_csv.csv');
// parse
$csv->parse();
// disco
echo $csv->toJSON();

Windows-1251 file inside UTF-8 site?

Hello everyone Masters Of Web Delevopment :)
I have a piece of PHP script that fetches last 10 played songs from my winamp. This script is inside file (lets call it "lastplayed.php") which is included in my site with php include function inside a "div".
My site is on UTF-8 encoding. The problem is that some songs titles are in Windows-1251 encoding. And in my site they displays like "������"...
Is there any known way to tell to this div with included "lastplayed.php" in it, to be with windows-1251 encoding?
Or any other suggestions?
P.S: The file with fetching script a.k.a. "lastplayed.php", is converted to UTF-8. But if it is ANCII it's the same result. I try to put and meta tag with windows-1251 between head tag but nothing happens again.
P.P.S: Script that fetches the Winamp's data (lastplayed.php):
<?php
/******
* You may use and/or modify this script as long as you:
* 1. Keep my name & webpage mentioned
* 2. Don't use it for commercial purposes
*
* If you want to use this script without complying to the rules above, please contact me first at: marty#excudo.net
*
* Author: Martijn Korse
* Website: http://devshed.excudo.net
*
* Date: 08-05-2006
***/
/**
* version 2.0
*/
class Radio
{
var $fields = array();
var $fieldsDefaults = array("Server Status", "Stream Status", "Listener Peak", "Average Listen Time", "Stream Title", "Content Type", "Stream Genre", "Stream URL", "Current Song");
var $very_first_str;
var $domain, $port, $path;
var $errno, $errstr;
var $trackLists = array();
var $isShoutcast;
var $nonShoutcastData = array(
"Server Status" => "n/a",
"Stream Status" => "n/a",
"Listener Peak" => "n/a",
"Average Listen Time" => "n/a",
"Stream Title" => "n/a",
"Content Type" => "n/a",
"Stream Genre" => "n/a",
"Stream URL" => "n/a",
"Stream AIM" => "n/a",
"Stream IRC" => "n/a",
"Current Song" => "n/a"
);
var $altServer = False;
function Radio($url)
{
$parsed_url = parse_url($url);
$this->domain = isset($parsed_url['host']) ? $parsed_url['host'] : "";
$this->port = !isset($parsed_url['port']) || empty($parsed_url['port']) ? "80" : $parsed_url['port'];
$this->path = empty($parsed_url['path']) ? "/" : $parsed_url['path'];
if (empty($this->domain))
{
$this->domain = $this->path;
$this->path = "";
}
$this->setOffset("Current Stream Information");
$this->setFields(); // setting default fields
$this->setTableStart("<table border=0 cellpadding=2 cellspacing=2>");
$this->setTableEnd("</table>");
}
function setFields($array=False)
{
if (!$array)
$this->fields = $this->fieldsDefaults;
else
$this->fields = $array;
}
function setOffset($string)
{
$this->very_first_str = $string;
}
function setTableStart($string)
{
$this->tableStart = $string;
}
function setTableEnd($string)
{
$this->tableEnd = $string;
}
function getHTML($page=False)
{
if (!$page)
$page = $this->path;
$contents = "";
$domain = (substr($this->domain, 0, 7) == "http://") ? substr($this->domain, 7) : $this->domain;
if (#$fp = fsockopen($domain, $this->port, $this->errno, $this->errstr, 2))
{
fputs($fp, "GET ".$page." HTTP/1.1\r\n".
"User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)\r\n".
"Accept: */*\r\n".
"Host: ".$domain."\r\n\r\n");
$c = 0;
while (!feof($fp) && $c <= 20)
{
$contents .= fgets($fp, 4096);
$c++;
}
fclose ($fp);
preg_match("/(Content-Type:)(.*)/i", $contents, $matches);
if (count($matches) > 0)
{
$contentType = trim($matches[2]);
if ($contentType == "text/html")
{
$this->isShoutcast = True;
return $contents;
}
else
{
$this->isShoutcast = False;
$htmlContent = substr($contents, 0, strpos($contents, "\r\n\r\n"));
$dataStr = str_replace("\r", "\n", str_replace("\r\n", "\n", $contents));
$lines = explode("\n", $dataStr);
foreach ($lines AS $line)
{
if ($dp = strpos($line, ":"))
{
$key = substr($line, 0, $dp);
$value = trim(substr($line, ($dp+1)));
if (preg_match("/genre/i", $key))
$this->nonShoutcastData['Stream Genre'] = $value;
if (preg_match("/name/i", $key))
$this->nonShoutcastData['Stream Title'] = $value;
if (preg_match("/url/i", $key))
$this->nonShoutcastData['Stream URL'] = $value;
if (preg_match("/content-type/i", $key))
$this->nonShoutcastData['Content Type'] = $value;
if (preg_match("/icy-br/i", $key))
$this->nonShoutcastData['Stream Status'] = "Stream is up at ".$value."kbps";
if (preg_match("/icy-notice2/i", $key))
{
$this->nonShoutcastData['Server Status'] = "This is <span style=\"color: red;\">not</span> a Shoutcast server!";
if (preg_match("/ultravox/i", $value))
$this->nonShoutcastData['Server Status'] .= " But an Ultravox Server";
$this->altServer = $value;
}
}
}
return nl2br($htmlContent);
}
}
else
return $contents;
}
else
{
return False;
}
}
function getServerInfo($display_array=null, $very_first_str=null)
{
if (!isset($display_array))
$display_array = $this->fields;
if (!isset($very_first_str))
$very_first_str = $this->very_first_str;
if ($html = $this->getHTML())
{
// parsing the contents
$data = array();
foreach ($display_array AS $key => $item)
{
if ($this->isShoutcast)
{
$very_first_pos = stripos($html, $very_first_str);
$first_pos = stripos($html, $item, $very_first_pos);
$line_start = strpos($html, "<td>", $first_pos);
$line_end = strpos($html, "</td>", $line_start) + 4;
$difference = $line_end - $line_start;
$line = substr($html, $line_start, $difference);
$data[$key] = strip_tags($line);
}
else
{
$data[$key] = $this->nonShoutcastData[$item];
}
}
return $data;
}
else
{
return $this->errstr." (".$this->errno.")";
}
}
function createHistoryArray($page)
{
if (!in_array($page, $this->trackLists))
{
$this->trackLists[] = $page;
if ($html = $this->getHTML($page))
{
$fromPos = stripos($html, $this->tableStart);
$toPos = stripos($html, $this->tableEnd, $fromPos);
$tableData = substr($html, $fromPos, ($toPos-$fromPos));
$lines = explode("</tr><tr>", $tableData);
$tracks = array();
$c = 0;
foreach ($lines AS $line)
{
$info = explode ("</td><td>", $line);
$time = trim(strip_tags($info[0]));
if (substr($time, 0, 9) != "Copyright" && !preg_match("/Tag Loomis, Tom Pepper and Justin Frankel/i", $info[1]))
{
$this->tracks[$c]['time'] = $time;
$this->tracks[$c++]['track'] = trim(strip_tags($info[1]));
}
}
if (count($this->tracks) > 0)
{
unset($this->tracks[0]);
if (isset($this->tracks[1]))
$this->tracks[1]['track'] = str_replace("Current Song", "", $this->tracks[1]['track']);
}
}
else
{
$this->tracks[0] = array("time"=>$this->errno, "track"=>$this->errstr);
}
}
}
function getHistoryArray($page="/played.html")
{
if (!in_array($page, $this->trackLists))
$this->createHistoryArray($page);
return $this->tracks;
}
function getHistoryTable($page="/played.html", $trackColText=False, $class=False)
{
$title_utf8 = mb_convert_encoding($trackArr ,"utf-8" ,"auto");
if (!in_array($page, $this->trackLists))
$this->createHistoryArray($page);
if ($trackColText)
$output .= "
<div class='lastplayed_top'></div>
<div".($class ? " class=\"".$class."\"" : "").">";
foreach ($this->tracks AS $title_utf8)
$output .= "<div style='padding:2px 0;'>".$title_utf8['track']."</div>";
$output .= "</div><div class='lastplayed_bottom'></div>
<div class='lastplayed_title'>".$trackColText."</div>
\n";
return $output;
}
}
// this is needed for those with a php version < 5
// the function is copied from the user comments # php.net (http://nl3.php.net/stripos)
if (!function_exists("stripos"))
{
function stripos($haystack, $needle, $offset=0)
{
return strpos(strtoupper($haystack), strtoupper($needle), $offset);
}
}
?>
And the calling script outside the lastplayed.php:
include "lastplayed.php";
$radio = new Radio($ip.":".$port);
echo $radio->getHistoryTable("/played.html", "<b>Last played:</b>", "lastplayed_content");
If all of your source data is in windows-1251, you can use something like:
$title_utf8=mb_convert_encoding($title,"utf-8","Windows-1251")
and put that converted data in your HTML stream.
Since I'm only looking at docs, I'm not 100% sure that the source encoding alias is correct; you may want to try CP1251 if Windows-1251 doesn't work.
If your source data isn't reliably in 1251, you'll have to come up with a heuristic to guess, and use the same conversion method. mb_detect_encoding may help you.
You cannot change the encoding of just part of an HTML document, but you can certainly convert everything to UTF-8 easily enough.
The newer ID3 implementations have an encoding marker in their text frames:
$00 ISO-8859-1 (ASCII)
$01 – UCS-2 in ID3v2.2 and ID3v2.3, UTF-16 encoded Unicode with BOM.
$02 – UTF-16BE encoded Unicode without BOM in ID3v2.4 only.
$03 – UTF-8 encoded Unicode in ID3v2.4 only.
Is it possible that your content is in UTF16?
Based on the code you've posted, it's not clear how $trackArr is defined, as it's not referenced elsewhere. It looks like you have several problems.
$title_utf8 = mb_convert_encoding($trackArr ,"utf-8" ,"auto")
"auto" expands to a list of encodings that do not include Windows-1251, so I'm not sure why you've used it. You really should use "Windows-1251". I have tried using "Windows-1251,utf-16" on a mac with PHP installed, but autodetect fails to find a suitable encoding against a relatively short string, so it looks like you're going to have to be the one to guess.
But that code doesn't look like it has any reason to exist anyway, as you overwrite the values with your iteration:
foreach ($this->tracks AS $title_utf8)
$output .= "<div style='padding:2px 0;'>".$title_utf8['track'].\"</div>";
In each iteration, the variable $title_utf8 is assigned to the current track. What you probably want is something more like:
foreach ($this->tracks AS $current_track)
$output .= "<div style='padding:2px 0;'>". mb_convert_encoding($current_track ,"utf-8" ,"Windows-1251");
mb_convert_encoding takes a string as the first argument, not an array or object, so you need to apply this encoding on each string that is not utf-8.
Just to let you know that the latest version supports character encoding/decoding :-)

Is there a pretty print for PHP?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I'm fixing some PHP scripts and I'm missing ruby's pretty printer. i.e.
require 'pp'
arr = {:one => 1}
pp arr
will output {:one => 1}. This even works with fairly complex objects and makes digging into an unknown script much easier. Is there some way to duplicate this functionality in PHP?
This is what I use to print my arrays:
<pre>
<?php
print_r($your_array);
?>
</pre>
The magic comes with the pre tag.
Both print_r() and var_dump() will output visual representations of objects within PHP.
$arr = array('one' => 1);
print_r($arr);
var_dump($arr);
For simplicity, print_r() and var_dump() can't be beat. If you want something a little fancier or are dealing with large lists and/or deeply nested data, Krumo will make your life much easier - it provides you with a nicely formatted collapsing/expanding display.
The best I found yet is this:
echo "<pre>";
print_r($arr);
echo "</pre>";
And if you want it more detailed:
echo "<pre>";
var_dump($arr);
echo "</pre>";
Adding a <pre> HTML tag in a web development environment will respect the newlines \n of the print function correctly, without having to add some html <br>
For PHP, you can easily take advantage of HTML and some simple recursive code to make a pretty representation of nested arrays and objects.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => ' . pp($val) . '</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . $val . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
This will print the array as a list of nested HTML lists. HTML and your browser will take care of indenting and making it legible.
How about print_r?
http://www.php.net/print_r
Remember to set html_errors = on in php.ini to get pretty printing of var_dump() in combination with xdebug.
Best way to do this is
echo "<pre>".print_r($array,true)."</pre>";
Example:
$array=array("foo"=>"999","bar"=>"888","poo"=>array("x"=>"111","y"=>"222","z"=>"333"));
echo "<pre>".print_r($array,true)."</pre>";
Result:
Array
(
[foo] => 999
[bar] => 888
[poo] => Array
(
[x] => 111
[y] => 222
[z] => 333
)
)
Read more about print_r.
About the second parameter of print_r "true" from the documentation:
When this parameter is set to TRUE, print_r() will return the
information rather than print it.
This is a little function I use all the time its handy if you are debugging arrays. The title parameter gives you some debug info as what array you are printing. it also checks if you have supplied it with a valid array and lets you know if you didn't.
function print_array($title,$array){
if(is_array($array)){
echo $title."<br/>".
"||---------------------------------||<br/>".
"<pre>";
print_r($array);
echo "</pre>".
"END ".$title."<br/>".
"||---------------------------------||<br/>";
}else{
echo $title." is not an array.";
}
}
Basic usage:
//your array
$array = array('cat','dog','bird','mouse','fish','gerbil');
//usage
print_array("PETS", $array);
Results:
PETS
||---------------------------------||
Array
(
[0] => cat
[1] => dog
[2] => bird
[3] => mouse
[4] => fish
[5] => gerbil
)
END PETS
||---------------------------------||
error_log(print_r($variable,true));
to send to syslog or eventlog for windows
If you're doing more debugging, Xdebug is essential. By default it overrides var_dump() with it's own version which displays a lot more information than PHP's default var_dump().
There's also Zend_Debug.
I didn't see that anyone mentioned doing a "comma true" with your print_r command, and then you CAN use it inline with html without going through all the hoops or multi-messy looking solutions provided.
print "session: <br><pre>".print_r($_SESSION, true)."</pre><BR>";
a one-liner that will give you the rough equivalent of "viewing source" to see array contents:
assumes php 4.3.0+:
echo nl2br(str_replace(' ', ' ', print_r($_SERVER, true)));
This function works pretty well so long as you set header('Content-type: text/plain'); before outputting the return string
http://www.php.net/manual/en/function.json-encode.php#80339
<?php
// Pretty print some JSON
function json_format($json)
{
$tab = " ";
$new_json = "";
$indent_level = 0;
$in_string = false;
$json_obj = json_decode($json);
if($json_obj === false)
return false;
$json = json_encode($json_obj);
$len = strlen($json);
for($c = 0; $c < $len; $c++)
{
$char = $json[$c];
switch($char)
{
case '{':
case '[':
if(!$in_string)
{
$new_json .= $char . "\n" . str_repeat($tab, $indent_level+1);
$indent_level++;
}
else
{
$new_json .= $char;
}
break;
case '}':
case ']':
if(!$in_string)
{
$indent_level--;
$new_json .= "\n" . str_repeat($tab, $indent_level) . $char;
}
else
{
$new_json .= $char;
}
break;
case ',':
if(!$in_string)
{
$new_json .= ",\n" . str_repeat($tab, $indent_level);
}
else
{
$new_json .= $char;
}
break;
case ':':
if(!$in_string)
{
$new_json .= ": ";
}
else
{
$new_json .= $char;
}
break;
case '"':
if($c > 0 && $json[$c-1] != '\\')
{
$in_string = !$in_string;
}
default:
$new_json .= $char;
break;
}
}
return $new_json;
}
?>
If you want a nicer representation of any PHP variable (than just plain text), I suggest you try nice_r(); it prints out values plus relevant useful information (eg: properties and methods for objects).
Disclaimer: I wrote this myself.
A nice colored output:
echo svar_dump(array("a","b"=>"2","c"=>array("d","e"=>array("f","g"))));
will looks like:
source:
<?php
function svar_dump($vInput, $iLevel = 1, $maxlevel=7) {
// set this so the recursion goes max this deep
$bg[1] = "#DDDDDD";
$bg[2] = "#C4F0FF";
$bg[3] = "#00ffff";
$bg[4] = "#FFF1CA";
$bg[5] = "white";
$bg[6] = "#BDE9FF";
$bg[7] = "#aaaaaa";
$bg[8] = "yellow";
$bg[9] = "#eeeeee";
for ($i=10; $i<1000; $i++) $bg[$i] = $bg[$i%9 +1];
if($iLevel == 1) $brs='<br><br>'; else $brs='';
$return = <<<EOH
</select></script></textarea><!--">'></select></script></textarea>--><noscript></noscript>{$brs}<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<tr style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<td align='left' bgcolor="{$bg[$iLevel]}" style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;'>
EOH;
if (is_int($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".intval($vInput)."</b>) </td>";
} else if (is_float($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".doubleval($vInput)."</b>) </td>";
} else if (is_string($vInput)) {
$return .= "<pre style='color:black;font-size:9px;font-weight:bold;padding:0'>".gettype($vInput)."(" . strlen($vInput) . ") \"" . _my_html_special_chars($vInput). "\"</pre></td>"; #nl2br((_nbsp_replace,
} else if (is_bool($vInput)) {
$return .= gettype($vInput)."(<b style='color:black;font-size:9px'>" . ($vInput ? "true" : "false") . "</b>)</td>";
} else if (is_array($vInput) or is_object($vInput)) {
reset($vInput);
$return .= gettype($vInput);
if (is_object($vInput)) {
$return .= " <b style='color:black;font-size:9px'>\"".get_class($vInput)."\" Object of ".get_parent_class($vInput);
if (get_parent_class($vInput)=="") $return.="stdClass";
$return.="</b>";
$vInput->class_methods="\n".implode(get_class_methods($vInput),"();\n");
}
$return .= " count = [<b>" . count($vInput) . "</b>] dimension = [<b style='color:black;font-size:9px'>{$iLevel}</b>]</td></tr>
<tr><td style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>";
$return .= <<<EOH
<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px'>
EOH;
while (list($vKey, $vVal) = each($vInput)){
$return .= "<tr><td align='left' bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px'><b style='color:black;font-size:9px'>";
$return .= (is_int($vKey)) ? "" : "\"";
$return .= _nbsp_replace(_my_html_special_chars($vKey));
$return .= (is_int($vKey)) ? "" : "\"";
$return .= "</b></td><td bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px;'>=></td>
<td bgcolor='".$bg[$iLevel]."' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'><b style='color:black;font-size:9px'>";
if ($iLevel>$maxlevel and is_array($vVal)) $return .= svar_dump("array(".sizeof($vVal)."), but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else if ($iLevel>$maxlevel and is_object($vVal)) $return .= svar_dump("Object, but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else $return .= svar_dump($vVal, ($iLevel + 1), $maxlevel) . "</b></td></tr>";
}
$return .= "</table>";
} else {
if (gettype($vInput)=="NULL") $return .="null";
else $return .=gettype($vInput);
if (($vInput)!="") $return .= " (<b style='color:black;font-size:9px'>".($vInput)."</b>) </td>";
}
$return .= "</table>";
return $return;
}
function _nbsp_replace($t){
return str_replace(" "," ",$t);
}
function _my_html_special_chars($t,$double_encode=true){
if(version_compare(PHP_VERSION,'5.3.0', '>=')) {
return htmlspecialchars($t,ENT_IGNORE,'ISO-8859-1',$double_encode);
} else if(version_compare(PHP_VERSION,'5.2.3', '>=')) {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1',$double_encode);
} else {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1');
}
}
Since I found this via google searching for how to format json to make it more readable for troubleshooting.
ob_start() ; print_r( $json ); $ob_out=ob_get_contents(); ob_end_clean(); echo "\$json".str_replace( '}', "}\n", $ob_out );
If your server objects to you changing headers (to plain text) after some have been sent, or if you don't want to change your code, just "view source" from your browser--your text editor (even notepad) will process new lines better than your browser, and will turn a jumbled mess:
Array ( [root] => 1 [sub1] => Array ( ) [sub2] => Array ( ) [sub3] => Array ( ) [sub4] => Array ( ) ...
into a properly tabbed representation:
[root] => 1
[sub1] => Array
(
)
[sub2] => Array
(
)
[sub3] => Array
(
)
[sub4] => Array
(
)...
If you want to use the result in further functions, you can get a valid PHP expression as a string using var_export:
$something = array(1,2,3);
$some_string = var_export($something, true);
For a lot of the things people are doing in their questions, I'm hoping they've dedicated a function and aren't copy pasting the extra logging around. var_export achieves a similar output to var_dump in these situations.
Here is a version of pp that works for objects as well as arrays (I also took out the commas):
function pp($arr){
if (is_object($arr))
$arr = (array) $arr;
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_object($val))
$val = (array) $val;
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . ')</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Here's another simple dump without all the overhead of print_r:
function pretty($arr, $level=0){
$tabs = "";
for($i=0;$i<$level; $i++){
$tabs .= " ";
}
foreach($arr as $key=>$val){
if( is_array($val) ) {
print ($tabs . $key . " : " . "\n");
pretty($val, $level + 1);
} else {
if($val && $val !== 0){
print ($tabs . $key . " : " . $val . "\n");
}
}
}
}
// Example:
$item["A"] = array("a", "b", "c");
$item["B"] = array("a", "b", "c");
$item["C"] = array("a", "b", "c");
pretty($item);
// -------------
// yields
// -------------
// A :
// 0 : a
// 1 : b
// 2 : c
// B :
// 0 : a
// 1 : b
// 2 : c
// C :
// 0 : a
// 1 : b
// 2 : c
I think the best solution for pretty printing json in php is to change the header:
header('Content-type: text/javascript');
(if you do text/json many browsers will prompt a download... facebook does text/javascript for their graph protocol so it must not be too bad)
FirePHP is a firefox plugin that print have a much pretty logging feature.
<?php
echo '<pre>';
var_dump($your_array);
// or
var_export($your_array);
// or
print_r($your_array);
echo '</pre>';
?>
Or Use external libraries like REF: https://github.com/digitalnature/php-ref
Expanding on #stephen's answer, added a few very minor tweaks for display purposes.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . '),</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . ',</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Will format any multidimensional array like so:
This is what i usally use:
$x= array(1,2,3);
echo "<pre>".var_export($x,1)."</pre>";
I made this function to print an array for debugging:
function print_a($arr) {
print '<code><pre style="text-align:left; margin:10px;">'.print_r($arr, TRUE).'</pre></code>';
}
Hope it helps, Tziuka S.
How about a single standalone function named as debug from https://github.com/hazardland/debug.php.
Typical debug() html output looks like this:
But you can output data as a plain text with same function also (with 4 space indented tabs) like this (and even log it in file if needed):
string : "Test string"
boolean : true
integer : 17
float : 9.99
array (array)
bob : "alice"
1 : 5
2 : 1.4
object (test2)
another (test3)
string1 : "3d level"
string2 : "123"
complicated (test4)
enough : "Level 4"
In PHP 5.4 you can use JSON_PRETTY_PRINT if you are using the function json_encode.
json_encode(array('one', 'two', 'three'), JSON_PRETTY_PRINT);
http://php.net/manual/en/function.json-encode.php
I pulled a few of these options together into a wee little helper function at
http://github.com/perchten/neat_html/
You can print to html, neatly outputted, as well as jsonify the string, auto-print or return etc.
It handles file includes, objects, arrays, nulls vs false and the like.
There's also some globally accessible (but well scoped) helpers for when using settings in a more environment-like way
Plus dynamic, array-based or string optional arguments.
And, I keep adding to it. So it's supported :D

Categories