123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975 |
- <?php
- /**
- * Utility for printing tables from commandline scripts.
- *
- * PHP versions 5 and 7
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * @category Console
- * @package Console_Table
- * @author Richard Heyes <richard@phpguru.org>
- * @author Jan Schneider <jan@horde.org>
- * @copyright 2002-2005 Richard Heyes
- * @copyright 2006-2008 Jan Schneider
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @version CVS: $Id$
- * @link http://pear.php.net/package/Console_Table
- */
- define('CONSOLE_TABLE_HORIZONTAL_RULE', 1);
- define('CONSOLE_TABLE_ALIGN_LEFT', -1);
- define('CONSOLE_TABLE_ALIGN_CENTER', 0);
- define('CONSOLE_TABLE_ALIGN_RIGHT', 1);
- define('CONSOLE_TABLE_BORDER_ASCII', -1);
- /**
- * The main class.
- *
- * @category Console
- * @package Console_Table
- * @author Jan Schneider <jan@horde.org>
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @link http://pear.php.net/package/Console_Table
- */
- class Console_Table
- {
- /**
- * The table headers.
- *
- * @var array
- */
- var $_headers = array();
- /**
- * The data of the table.
- *
- * @var array
- */
- var $_data = array();
- /**
- * The maximum number of columns in a row.
- *
- * @var integer
- */
- var $_max_cols = 0;
- /**
- * The maximum number of rows in the table.
- *
- * @var integer
- */
- var $_max_rows = 0;
- /**
- * Lengths of the columns, calculated when rows are added to the table.
- *
- * @var array
- */
- var $_cell_lengths = array();
- /**
- * Heights of the rows.
- *
- * @var array
- */
- var $_row_heights = array();
- /**
- * How many spaces to use to pad the table.
- *
- * @var integer
- */
- var $_padding = 1;
- /**
- * Column filters.
- *
- * @var array
- */
- var $_filters = array();
- /**
- * Columns to calculate totals for.
- *
- * @var array
- */
- var $_calculateTotals;
- /**
- * Alignment of the columns.
- *
- * @var array
- */
- var $_col_align = array();
- /**
- * Default alignment of columns.
- *
- * @var integer
- */
- var $_defaultAlign;
- /**
- * Character set of the data.
- *
- * @var string
- */
- var $_charset = 'utf-8';
- /**
- * Border characters.
- * Allowed keys:
- * - intersection - intersection ("+")
- * - horizontal - horizontal rule character ("-")
- * - vertical - vertical rule character ("|")
- *
- * @var array
- */
- var $_border = array(
- 'intersection' => '+',
- 'horizontal' => '-',
- 'vertical' => '|',
- );
- /**
- * If borders are shown or not
- * Allowed keys: top, right, bottom, left, inner: true and false
- *
- * @var array
- */
- var $_borderVisibility = array(
- 'top' => true,
- 'right' => true,
- 'bottom' => true,
- 'left' => true,
- 'inner' => true
- );
- /**
- * Whether the data has ANSI colors.
- *
- * @var Console_Color2
- */
- var $_ansiColor = false;
- /**
- * Constructor.
- *
- * @param integer $align Default alignment. One of
- * CONSOLE_TABLE_ALIGN_LEFT,
- * CONSOLE_TABLE_ALIGN_CENTER or
- * CONSOLE_TABLE_ALIGN_RIGHT.
- * @param string $border The character used for table borders or
- * CONSOLE_TABLE_BORDER_ASCII.
- * @param integer $padding How many spaces to use to pad the table.
- * @param string $charset A charset supported by the mbstring PHP
- * extension.
- * @param boolean $color Whether the data contains ansi color codes.
- */
- function __construct($align = CONSOLE_TABLE_ALIGN_LEFT,
- $border = CONSOLE_TABLE_BORDER_ASCII, $padding = 1,
- $charset = null, $color = false)
- {
- $this->_defaultAlign = $align;
- $this->setBorder($border);
- $this->_padding = $padding;
- if ($color) {
- if (!class_exists('Console_Color2')) {
- include_once 'Console/Color2.php';
- }
- $this->_ansiColor = new Console_Color2();
- }
- if (!empty($charset)) {
- $this->setCharset($charset);
- }
- }
- /**
- * Converts an array to a table.
- *
- * @param array $headers Headers for the table.
- * @param array $data A two dimensional array with the table
- * data.
- * @param boolean $returnObject Whether to return the Console_Table object
- * instead of the rendered table.
- *
- * @static
- *
- * @return Console_Table|string A Console_Table object or the generated
- * table.
- */
- function fromArray($headers, $data, $returnObject = false)
- {
- if (!is_array($headers) || !is_array($data)) {
- return false;
- }
- $table = new Console_Table();
- $table->setHeaders($headers);
- foreach ($data as $row) {
- $table->addRow($row);
- }
- return $returnObject ? $table : $table->getTable();
- }
- /**
- * Adds a filter to a column.
- *
- * Filters are standard PHP callbacks which are run on the data before
- * table generation is performed. Filters are applied in the order they
- * are added. The callback function must accept a single argument, which
- * is a single table cell.
- *
- * @param integer $col Column to apply filter to.
- * @param mixed &$callback PHP callback to apply.
- *
- * @return void
- */
- function addFilter($col, &$callback)
- {
- $this->_filters[] = array($col, &$callback);
- }
- /**
- * Sets the charset of the provided table data.
- *
- * @param string $charset A charset supported by the mbstring PHP
- * extension.
- *
- * @return void
- */
- function setCharset($charset)
- {
- $locale = setlocale(LC_CTYPE, 0);
- setlocale(LC_CTYPE, 'en_US');
- $this->_charset = strtolower($charset);
- setlocale(LC_CTYPE, $locale);
- }
- /**
- * Set the table border settings
- *
- * Border definition modes:
- * - CONSOLE_TABLE_BORDER_ASCII: Default border with +, - and |
- * - array with keys "intersection", "horizontal" and "vertical"
- * - single character string that sets all three of the array keys
- *
- * @param mixed $border Border definition
- *
- * @return void
- * @see $_border
- */
- function setBorder($border)
- {
- if ($border === CONSOLE_TABLE_BORDER_ASCII) {
- $intersection = '+';
- $horizontal = '-';
- $vertical = '|';
- } else if (is_string($border)) {
- $intersection = $horizontal = $vertical = $border;
- } else if ($border == '') {
- $intersection = $horizontal = $vertical = '';
- } else {
- extract($border);
- }
- $this->_border = array(
- 'intersection' => $intersection,
- 'horizontal' => $horizontal,
- 'vertical' => $vertical,
- );
- }
- /**
- * Set which borders shall be shown.
- *
- * @param array $visibility Visibility settings.
- * Allowed keys: left, right, top, bottom, inner
- *
- * @return void
- * @see $_borderVisibility
- */
- function setBorderVisibility($visibility)
- {
- $this->_borderVisibility = array_merge(
- $this->_borderVisibility,
- array_intersect_key(
- $visibility,
- $this->_borderVisibility
- )
- );
- }
- /**
- * Sets the alignment for the columns.
- *
- * @param integer $col_id The column number.
- * @param integer $align Alignment to set for this column. One of
- * CONSOLE_TABLE_ALIGN_LEFT
- * CONSOLE_TABLE_ALIGN_CENTER
- * CONSOLE_TABLE_ALIGN_RIGHT.
- *
- * @return void
- */
- function setAlign($col_id, $align = CONSOLE_TABLE_ALIGN_LEFT)
- {
- switch ($align) {
- case CONSOLE_TABLE_ALIGN_CENTER:
- $pad = STR_PAD_BOTH;
- break;
- case CONSOLE_TABLE_ALIGN_RIGHT:
- $pad = STR_PAD_LEFT;
- break;
- default:
- $pad = STR_PAD_RIGHT;
- break;
- }
- $this->_col_align[$col_id] = $pad;
- }
- /**
- * Specifies which columns are to have totals calculated for them and
- * added as a new row at the bottom.
- *
- * @param array $cols Array of column numbers (starting with 0).
- *
- * @return void
- */
- function calculateTotalsFor($cols)
- {
- $this->_calculateTotals = $cols;
- }
- /**
- * Sets the headers for the columns.
- *
- * @param array $headers The column headers.
- *
- * @return void
- */
- function setHeaders($headers)
- {
- $this->_headers = array(array_values($headers));
- $this->_updateRowsCols($headers);
- }
- /**
- * Adds a row to the table.
- *
- * @param array $row The row data to add.
- * @param boolean $append Whether to append or prepend the row.
- *
- * @return void
- */
- function addRow($row, $append = true)
- {
- if ($append) {
- $this->_data[] = array_values($row);
- } else {
- array_unshift($this->_data, array_values($row));
- }
- $this->_updateRowsCols($row);
- }
- /**
- * Inserts a row after a given row number in the table.
- *
- * If $row_id is not given it will prepend the row.
- *
- * @param array $row The data to insert.
- * @param integer $row_id Row number to insert before.
- *
- * @return void
- */
- function insertRow($row, $row_id = 0)
- {
- array_splice($this->_data, $row_id, 0, array($row));
- $this->_updateRowsCols($row);
- }
- /**
- * Adds a column to the table.
- *
- * @param array $col_data The data of the column.
- * @param integer $col_id The column index to populate.
- * @param integer $row_id If starting row is not zero, specify it here.
- *
- * @return void
- */
- function addCol($col_data, $col_id = 0, $row_id = 0)
- {
- foreach ($col_data as $col_cell) {
- $this->_data[$row_id++][$col_id] = $col_cell;
- }
- $this->_updateRowsCols();
- $this->_max_cols = max($this->_max_cols, $col_id + 1);
- }
- /**
- * Adds data to the table.
- *
- * @param array $data A two dimensional array with the table data.
- * @param integer $col_id Starting column number.
- * @param integer $row_id Starting row number.
- *
- * @return void
- */
- function addData($data, $col_id = 0, $row_id = 0)
- {
- foreach ($data as $row) {
- if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
- $this->_data[$row_id] = CONSOLE_TABLE_HORIZONTAL_RULE;
- $row_id++;
- continue;
- }
- $starting_col = $col_id;
- foreach ($row as $cell) {
- $this->_data[$row_id][$starting_col++] = $cell;
- }
- $this->_updateRowsCols();
- $this->_max_cols = max($this->_max_cols, $starting_col);
- $row_id++;
- }
- }
- /**
- * Adds a horizontal seperator to the table.
- *
- * @return void
- */
- function addSeparator()
- {
- $this->_data[] = CONSOLE_TABLE_HORIZONTAL_RULE;
- }
- /**
- * Returns the generated table.
- *
- * @return string The generated table.
- */
- function getTable()
- {
- $this->_applyFilters();
- $this->_calculateTotals();
- $this->_validateTable();
- return $this->_buildTable();
- }
- /**
- * Calculates totals for columns.
- *
- * @return void
- */
- function _calculateTotals()
- {
- if (empty($this->_calculateTotals)) {
- return;
- }
- $this->addSeparator();
- $totals = array();
- foreach ($this->_data as $row) {
- if (is_array($row)) {
- foreach ($this->_calculateTotals as $columnID) {
- $totals[$columnID] += $row[$columnID];
- }
- }
- }
- $this->_data[] = $totals;
- $this->_updateRowsCols();
- }
- /**
- * Applies any column filters to the data.
- *
- * @return void
- */
- function _applyFilters()
- {
- if (empty($this->_filters)) {
- return;
- }
- foreach ($this->_filters as $filter) {
- $column = $filter[0];
- $callback = $filter[1];
- foreach ($this->_data as $row_id => $row_data) {
- if ($row_data !== CONSOLE_TABLE_HORIZONTAL_RULE) {
- $this->_data[$row_id][$column] =
- call_user_func($callback, $row_data[$column]);
- }
- }
- }
- }
- /**
- * Ensures that column and row counts are correct.
- *
- * @return void
- */
- function _validateTable()
- {
- if (!empty($this->_headers)) {
- $this->_calculateRowHeight(-1, $this->_headers[0]);
- }
- for ($i = 0; $i < $this->_max_rows; $i++) {
- for ($j = 0; $j < $this->_max_cols; $j++) {
- if (!isset($this->_data[$i][$j]) &&
- (!isset($this->_data[$i]) ||
- $this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE)) {
- $this->_data[$i][$j] = '';
- }
- }
- $this->_calculateRowHeight($i, $this->_data[$i]);
- if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
- ksort($this->_data[$i]);
- }
- }
- $this->_splitMultilineRows();
- // Update cell lengths.
- for ($i = 0; $i < count($this->_headers); $i++) {
- $this->_calculateCellLengths($this->_headers[$i]);
- }
- for ($i = 0; $i < $this->_max_rows; $i++) {
- $this->_calculateCellLengths($this->_data[$i]);
- }
- ksort($this->_data);
- }
- /**
- * Splits multiline rows into many smaller one-line rows.
- *
- * @return void
- */
- function _splitMultilineRows()
- {
- ksort($this->_data);
- $sections = array(&$this->_headers, &$this->_data);
- $max_rows = array(count($this->_headers), $this->_max_rows);
- $row_height_offset = array(-1, 0);
- for ($s = 0; $s <= 1; $s++) {
- $inserted = 0;
- $new_data = $sections[$s];
- for ($i = 0; $i < $max_rows[$s]; $i++) {
- // Process only rows that have many lines.
- $height = $this->_row_heights[$i + $row_height_offset[$s]];
- if ($height > 1) {
- // Split column data into one-liners.
- $split = array();
- for ($j = 0; $j < $this->_max_cols; $j++) {
- $split[$j] = preg_split('/\r?\n|\r/',
- $sections[$s][$i][$j]);
- }
- $new_rows = array();
- // Construct new 'virtual' rows - insert empty strings for
- // columns that have less lines that the highest one.
- for ($i2 = 0; $i2 < $height; $i2++) {
- for ($j = 0; $j < $this->_max_cols; $j++) {
- $new_rows[$i2][$j] = !isset($split[$j][$i2])
- ? ''
- : $split[$j][$i2];
- }
- }
- // Replace current row with smaller rows. $inserted is
- // used to take account of bigger array because of already
- // inserted rows.
- array_splice($new_data, $i + $inserted, 1, $new_rows);
- $inserted += count($new_rows) - 1;
- }
- }
- // Has the data been modified?
- if ($inserted > 0) {
- $sections[$s] = $new_data;
- $this->_updateRowsCols();
- }
- }
- }
- /**
- * Builds the table.
- *
- * @return string The generated table string.
- */
- function _buildTable()
- {
- if (!count($this->_data)) {
- return '';
- }
- $vertical = $this->_border['vertical'];
- $separator = $this->_getSeparator();
- $return = array();
- for ($i = 0; $i < count($this->_data); $i++) {
- for ($j = 0; $j < count($this->_data[$i]); $j++) {
- if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE &&
- $this->_strlen($this->_data[$i][$j]) <
- $this->_cell_lengths[$j]) {
- $this->_data[$i][$j] = $this->_strpad($this->_data[$i][$j],
- $this->_cell_lengths[$j],
- ' ',
- $this->_col_align[$j]);
- }
- }
- if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
- $row_begin = $this->_borderVisibility['left']
- ? $vertical . str_repeat(' ', $this->_padding)
- : '';
- $row_end = $this->_borderVisibility['right']
- ? str_repeat(' ', $this->_padding) . $vertical
- : '';
- $implode_char = str_repeat(' ', $this->_padding) . $vertical
- . str_repeat(' ', $this->_padding);
- $return[] = $row_begin
- . implode($implode_char, $this->_data[$i]) . $row_end;
- } elseif (!empty($separator)) {
- $return[] = $separator;
- }
- }
- $return = implode(PHP_EOL, $return);
- if (!empty($separator)) {
- if ($this->_borderVisibility['inner']) {
- $return = $separator . PHP_EOL . $return;
- }
- if ($this->_borderVisibility['bottom']) {
- $return .= PHP_EOL . $separator;
- }
- }
- $return .= PHP_EOL;
- if (!empty($this->_headers)) {
- $return = $this->_getHeaderLine() . PHP_EOL . $return;
- }
- return $return;
- }
- /**
- * Creates a horizontal separator for header separation and table
- * start/end etc.
- *
- * @return string The horizontal separator.
- */
- function _getSeparator()
- {
- if (!$this->_border) {
- return;
- }
- $horizontal = $this->_border['horizontal'];
- $intersection = $this->_border['intersection'];
- $return = array();
- foreach ($this->_cell_lengths as $cl) {
- $return[] = str_repeat($horizontal, $cl);
- }
- $row_begin = $this->_borderVisibility['left']
- ? $intersection . str_repeat($horizontal, $this->_padding)
- : '';
- $row_end = $this->_borderVisibility['right']
- ? str_repeat($horizontal, $this->_padding) . $intersection
- : '';
- $implode_char = str_repeat($horizontal, $this->_padding) . $intersection
- . str_repeat($horizontal, $this->_padding);
- return $row_begin . implode($implode_char, $return) . $row_end;
- }
- /**
- * Returns the header line for the table.
- *
- * @return string The header line of the table.
- */
- function _getHeaderLine()
- {
- // Make sure column count is correct
- for ($j = 0; $j < count($this->_headers); $j++) {
- for ($i = 0; $i < $this->_max_cols; $i++) {
- if (!isset($this->_headers[$j][$i])) {
- $this->_headers[$j][$i] = '';
- }
- }
- }
- for ($j = 0; $j < count($this->_headers); $j++) {
- for ($i = 0; $i < count($this->_headers[$j]); $i++) {
- if ($this->_strlen($this->_headers[$j][$i]) <
- $this->_cell_lengths[$i]) {
- $this->_headers[$j][$i] =
- $this->_strpad($this->_headers[$j][$i],
- $this->_cell_lengths[$i],
- ' ',
- $this->_col_align[$i]);
- }
- }
- }
- $vertical = $this->_border['vertical'];
- $row_begin = $this->_borderVisibility['left']
- ? $vertical . str_repeat(' ', $this->_padding)
- : '';
- $row_end = $this->_borderVisibility['right']
- ? str_repeat(' ', $this->_padding) . $vertical
- : '';
- $implode_char = str_repeat(' ', $this->_padding) . $vertical
- . str_repeat(' ', $this->_padding);
- $separator = $this->_getSeparator();
- if (!empty($separator) && $this->_borderVisibility['top']) {
- $return[] = $separator;
- }
- for ($j = 0; $j < count($this->_headers); $j++) {
- $return[] = $row_begin
- . implode($implode_char, $this->_headers[$j]) . $row_end;
- }
- return implode(PHP_EOL, $return);
- }
- /**
- * Updates values for maximum columns and rows.
- *
- * @param array $rowdata Data array of a single row.
- *
- * @return void
- */
- function _updateRowsCols($rowdata = null)
- {
- // Update maximum columns.
- $this->_max_cols = max($this->_max_cols, count($rowdata));
- // Update maximum rows.
- ksort($this->_data);
- $keys = array_keys($this->_data);
- $this->_max_rows = end($keys) + 1;
- switch ($this->_defaultAlign) {
- case CONSOLE_TABLE_ALIGN_CENTER:
- $pad = STR_PAD_BOTH;
- break;
- case CONSOLE_TABLE_ALIGN_RIGHT:
- $pad = STR_PAD_LEFT;
- break;
- default:
- $pad = STR_PAD_RIGHT;
- break;
- }
- // Set default column alignments
- for ($i = 0; $i < $this->_max_cols; $i++) {
- if (!isset($this->_col_align[$i])) {
- $this->_col_align[$i] = $pad;
- }
- }
- }
- /**
- * Calculates the maximum length for each column of a row.
- *
- * @param array $row The row data.
- *
- * @return void
- */
- function _calculateCellLengths($row)
- {
- for ($i = 0; $i < count($row); $i++) {
- if (!isset($this->_cell_lengths[$i])) {
- $this->_cell_lengths[$i] = 0;
- }
- $this->_cell_lengths[$i] = max($this->_cell_lengths[$i],
- $this->_strlen($row[$i]));
- }
- }
- /**
- * Calculates the maximum height for all columns of a row.
- *
- * @param integer $row_number The row number.
- * @param array $row The row data.
- *
- * @return void
- */
- function _calculateRowHeight($row_number, $row)
- {
- if (!isset($this->_row_heights[$row_number])) {
- $this->_row_heights[$row_number] = 1;
- }
- // Do not process horizontal rule rows.
- if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
- return;
- }
- for ($i = 0, $c = count($row); $i < $c; ++$i) {
- $lines = preg_split('/\r?\n|\r/', $row[$i]);
- $this->_row_heights[$row_number] = max($this->_row_heights[$row_number],
- count($lines));
- }
- }
- /**
- * Returns the character length of a string.
- *
- * @param string $str A multibyte or singlebyte string.
- *
- * @return integer The string length.
- */
- function _strlen($str)
- {
- static $mbstring;
- // Strip ANSI color codes if requested.
- if ($this->_ansiColor) {
- $str = $this->_ansiColor->strip($str);
- }
- // Cache expensive function_exists() calls.
- if (!isset($mbstring)) {
- $mbstring = function_exists('mb_strwidth');
- }
- if ($mbstring) {
- return mb_strwidth($str, $this->_charset);
- }
- return strlen($str);
- }
- /**
- * Returns part of a string.
- *
- * @param string $string The string to be converted.
- * @param integer $start The part's start position, zero based.
- * @param integer $length The part's length.
- *
- * @return string The string's part.
- */
- function _substr($string, $start, $length = null)
- {
- static $mbstring;
- // Cache expensive function_exists() calls.
- if (!isset($mbstring)) {
- $mbstring = function_exists('mb_substr');
- }
- if (is_null($length)) {
- $length = $this->_strlen($string);
- }
- if ($mbstring) {
- $ret = @mb_substr($string, $start, $length, $this->_charset);
- if (!empty($ret)) {
- return $ret;
- }
- }
- return substr($string, $start, $length);
- }
- /**
- * Returns a string padded to a certain length with another string.
- *
- * This method behaves exactly like str_pad but is multibyte safe.
- *
- * @param string $input The string to be padded.
- * @param integer $length The length of the resulting string.
- * @param string $pad The string to pad the input string with. Must
- * be in the same charset like the input string.
- * @param const $type The padding type. One of STR_PAD_LEFT,
- * STR_PAD_RIGHT, or STR_PAD_BOTH.
- *
- * @return string The padded string.
- */
- function _strpad($input, $length, $pad = ' ', $type = STR_PAD_RIGHT)
- {
- $mb_length = $this->_strlen($input);
- $sb_length = strlen($input);
- $pad_length = $this->_strlen($pad);
- /* Return if we already have the length. */
- if ($mb_length >= $length) {
- return $input;
- }
- /* Shortcut for single byte strings. */
- if ($mb_length == $sb_length && $pad_length == strlen($pad)) {
- return str_pad($input, $length, $pad, $type);
- }
- switch ($type) {
- case STR_PAD_LEFT:
- $left = $length - $mb_length;
- $output = $this->_substr(str_repeat($pad, ceil($left / $pad_length)),
- 0, $left, $this->_charset) . $input;
- break;
- case STR_PAD_BOTH:
- $left = floor(($length - $mb_length) / 2);
- $right = ceil(($length - $mb_length) / 2);
- $output = $this->_substr(str_repeat($pad, ceil($left / $pad_length)),
- 0, $left, $this->_charset) .
- $input .
- $this->_substr(str_repeat($pad, ceil($right / $pad_length)),
- 0, $right, $this->_charset);
- break;
- case STR_PAD_RIGHT:
- $right = $length - $mb_length;
- $output = $input .
- $this->_substr(str_repeat($pad, ceil($right / $pad_length)),
- 0, $right, $this->_charset);
- break;
- }
- return $output;
- }
- }
|