Inspired by some awesome-as-always code written by my co-worker Mike Adams, here’s a helper function to help create plaintext data tables in PHP. This is particularly useful for PHP-based CLI scripts (we use quite a few at Automattic) or for plaintext e-mails.
But first, here’s an example output with the optional dividers enabled:
ID | First Name | Last Name ------------------------------------- 1 | Alex | Mills 2 | John | Smith 3 | Barack | Obama 4 | Fred | Flinstone 12345 | ReallyLongName | IsReallyLong
This is the code I used to create the above example:
$data = array( 'labels' => array( 'ID' => 'ID', 'firstname' => 'First Name', 'lastname' => 'Last Name', ), 'align' => array( 'ID' => 'right', ), array( 'ID' => 1, 'firstname' => 'Alex', 'lastname' => 'Mills', ), array( 'ID' => 2, 'firstname' => 'John', 'lastname' => 'Smith', ), array( 'ID' => 3, 'firstname' => 'Barack', 'lastname' => 'Obama', ), // Array order doesn't matter as it's associative array( 'ID' => 4, 'lastname' => 'Flinstone', 'firstname' => 'Fred', ), array( 'lastname' => 'IsReallyLong', 'firstname' => 'ReallyLongName', 'ID' => 12345, ), ); echo '<pre>'; table_output( $data ); echo '</pre>';
You can easily loop through your data and generate an array in that format. The arrays are associative so order doesn’t matter.
The labels
array is optional and just allows you assign pretty labels for the columns. If this array is missing, then the data keys will be used.
The align
array is also optional and allows you to pass a value of right
in order to right-align the data in a column. Defaults to left align.
Now, to the functions that generate the table!
// Output a formatted table function table_output( $data, $dividers = true ) { $rows = table_get_rows( $data, $dividers ); echo implode( "\n", $rows ); } // Return an array of table rows function table_get_rows( $data, $dividers = true ) { // Find the column keys to use (use the first data row) $columns = array_keys( $data[0] ); // Create the labels if they're missing if ( empty( $data['labels'] ) ) $data['labels'] = array_combine( $columns, $columns ); // Calculate column widths foreach ( $data as $key => $item ) { if ( 'align' === $key ) continue; foreach ( $item as $column => $value ) { $length = strlen( $value ); if ( empty( $widths[$column] ) || $widths[$column] < $length ) $widths[$column] = $length; } } // Create the row sprintf() format foreach ( $columns as $column ) { $align = ( isset( $data['align'] ) && isset( $data['align'][$column] ) && 'right' == $data['align'][$column] ) ? '' : '-'; $formats[] = '%' . $align . $widths[$column] . 's'; } $divider = ( $dividers ) ? ' | ' : ' '; $format = implode( $divider, $formats ); // Generate the label row $rows['labels'] = vsprintf( $format, _table_get_line_data( $columns, $data['labels'] ) ); // Should there be a divider row? if ( $dividers ) $rows['divider'] = str_repeat( '-', strlen( $rows['labels'] ) ); // Generate the data rows foreach ( $data as $key => $values ) { if ( 'labels' === $key || 'align' === $key ) continue; $rows[$key] = vsprintf( $format, _table_get_line_data( $columns, $values ) ); } return $rows; } // Helper function to get the array of data for a table row in the correct order function _table_get_line_data( $columns, $item ) { foreach ( $columns as $column ) { $data[$column] = ( isset( $item[$column] ) ) ? $item[$column] : ''; } return $data; }
Hope you find it useful!
I like it.
Nice! But Gmail does not format plain text emails properly (i.e. white-space is inconsistent)
Calculating column widths should use mb_strlen not strlen. It will almost inevitably be wrong on real data otherwise. Try Rémi Gonçalves for example.
Yep, you’re totally correct. This is old, kinda crappy code.