Print a MySQL-style table with PHP

I wanted to cleanly display tabular data from a PHP command line script, and I like how MySQL formats its output.  This is quick, somewhat inefficient, hacky code, but it got the job done. You'll find nothing to be proud of in this code; I don't want to spend more time writing this post about it than I did writing it :)

/**
 * Out a MySQL-style table of data
 *
 * @param	array  $data         Associative array of data to output. 
 * @param	array  $header_keys  Optional; Assoc array of display names to use for headers. Keys must match those of $data. Defaults to keys of $data.
 * @param	string $glue         String to join lines with, defaults to newline.
 * @return string
 *
 */
function build_table($data, $header_keys=array(), $glue="\n") {
  $table = '';
  $data_fmt = array();
  $divider_row = array();
  $header_fmt = array();
 
  $keys = array_keys($data[0]);
  $col_lengths = array_flip($keys); // used to determine the max column width
 
  if( empty($header_keys) ) {
    $header_keys = array_combine($keys, $keys);
  }
 
  // set the base max length to the length of our header keys
  foreach( $keys as $key ) {
    $col_lengths[$key] = strlen($header_keys[$key]);
  }
 
  foreach( $data as $row ) {
    foreach( $keys as $key ) {
      $col_lengths[$key] = max($col_lengths[$key], strlen($row[$key]));
    }
  }
 
  foreach( $keys as $key ) {
    $data_fmt[] = '%-' . $col_lengths[$key] . 's';
    $header_fmt[] = '%-' . $col_lengths[$key] . 's';
    $divider_row[] = str_pad('', $col_lengths[$key]+2, '-'); // fill the spacing
  }
  $data_fmt = '| ' . implode(' | ', $data_fmt) . ' |';
  $divider_row = '+' . implode('+', $divider_row) . '+';
  $header_fmt = '| ' . implode(' | ', $header_fmt) . ' |';
 
  // assemble the table
  $table .= $divider_row . $glue;
  $table .= vsprintf($header_fmt . $glue, $header_keys);
  $table .= $divider_row . $glue;
  foreach( $data as $row ) {
    $table .= vsprintf($data_fmt . $glue, $row);
  }
  $table .= $divider_row . $glue;
 
  return $table;
}

The output will be similar to:

+--------------------+--------------------+---------------+
| First              | Second col         | Random Column |
+--------------------+--------------------+---------------+
| 60386980488376     | 597655305189574649 | 51            |
| 959432             | 459191             | 396802        |
| 73874213           | 570702             | 771           |
| 144579584678722975 | 892300317939345    | 59180         |
| 293172             | 314                | 127725766727  |
+--------------------+--------------------+---------------+

It only works with associative arrays, but that's easy enough to fix. You can proudly test it out using this glorious snippet:

$data = array();
 
function get_rand() {
  $max=rand(1,6);
  $str='';
  for( $i = 0; $i < $max; $i++ ) {
    $str .= rand(10, 1000);
  }
  return $str;
}
 
for( $i = 0; $i < 5; $i++ ) {
  $row = array(
    'one'   => get_rand(),
    'two'   => get_rand(),
    'three' => get_rand(),
  );
  $data[] = $row;
}
 
$disp = array(
  'one'   => 'First',
  'two'   => 'Second col',
  'three' => 'Random Column',
);
 
echo build_table($data, $disp);

 

Tags: , ,

Leave a Reply


© 2007-2012, Corey Gilmore | Posts RSS Feed | Comments RSS Feed | Contact

 

The views expressed on these pages are mine alone and not those of any past or present employer. All information presented on this site was obtained lawfully and not through disclosure under the terms of an NDA.