Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Utility for printing tables from commandline scripts.
|
Chris@0
|
4 *
|
Chris@0
|
5 * PHP versions 5 and 7
|
Chris@0
|
6 *
|
Chris@0
|
7 * All rights reserved.
|
Chris@0
|
8 *
|
Chris@0
|
9 * Redistribution and use in source and binary forms, with or without
|
Chris@0
|
10 * modification, are permitted provided that the following conditions are met:
|
Chris@0
|
11 *
|
Chris@0
|
12 * o Redistributions of source code must retain the above copyright notice,
|
Chris@0
|
13 * this list of conditions and the following disclaimer.
|
Chris@0
|
14 * o Redistributions in binary form must reproduce the above copyright notice,
|
Chris@0
|
15 * this list of conditions and the following disclaimer in the documentation
|
Chris@0
|
16 * and/or other materials provided with the distribution.
|
Chris@0
|
17 * o The names of the authors may not be used to endorse or promote products
|
Chris@0
|
18 * derived from this software without specific prior written permission.
|
Chris@0
|
19 *
|
Chris@0
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
Chris@0
|
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
Chris@0
|
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
Chris@0
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
Chris@0
|
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
Chris@0
|
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
Chris@0
|
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
Chris@0
|
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
Chris@0
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
Chris@0
|
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
Chris@0
|
30 * POSSIBILITY OF SUCH DAMAGE.
|
Chris@0
|
31 *
|
Chris@0
|
32 * @category Console
|
Chris@0
|
33 * @package Console_Table
|
Chris@0
|
34 * @author Richard Heyes <richard@phpguru.org>
|
Chris@0
|
35 * @author Jan Schneider <jan@horde.org>
|
Chris@0
|
36 * @copyright 2002-2005 Richard Heyes
|
Chris@0
|
37 * @copyright 2006-2008 Jan Schneider
|
Chris@0
|
38 * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
|
Chris@0
|
39 * @version CVS: $Id$
|
Chris@0
|
40 * @link http://pear.php.net/package/Console_Table
|
Chris@0
|
41 */
|
Chris@0
|
42
|
Chris@0
|
43 define('CONSOLE_TABLE_HORIZONTAL_RULE', 1);
|
Chris@0
|
44 define('CONSOLE_TABLE_ALIGN_LEFT', -1);
|
Chris@0
|
45 define('CONSOLE_TABLE_ALIGN_CENTER', 0);
|
Chris@0
|
46 define('CONSOLE_TABLE_ALIGN_RIGHT', 1);
|
Chris@0
|
47 define('CONSOLE_TABLE_BORDER_ASCII', -1);
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * The main class.
|
Chris@0
|
51 *
|
Chris@0
|
52 * @category Console
|
Chris@0
|
53 * @package Console_Table
|
Chris@0
|
54 * @author Jan Schneider <jan@horde.org>
|
Chris@0
|
55 * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
|
Chris@0
|
56 * @link http://pear.php.net/package/Console_Table
|
Chris@0
|
57 */
|
Chris@0
|
58 class Console_Table
|
Chris@0
|
59 {
|
Chris@0
|
60 /**
|
Chris@0
|
61 * The table headers.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @var array
|
Chris@0
|
64 */
|
Chris@0
|
65 var $_headers = array();
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@0
|
68 * The data of the table.
|
Chris@0
|
69 *
|
Chris@0
|
70 * @var array
|
Chris@0
|
71 */
|
Chris@0
|
72 var $_data = array();
|
Chris@0
|
73
|
Chris@0
|
74 /**
|
Chris@0
|
75 * The maximum number of columns in a row.
|
Chris@0
|
76 *
|
Chris@0
|
77 * @var integer
|
Chris@0
|
78 */
|
Chris@0
|
79 var $_max_cols = 0;
|
Chris@0
|
80
|
Chris@0
|
81 /**
|
Chris@0
|
82 * The maximum number of rows in the table.
|
Chris@0
|
83 *
|
Chris@0
|
84 * @var integer
|
Chris@0
|
85 */
|
Chris@0
|
86 var $_max_rows = 0;
|
Chris@0
|
87
|
Chris@0
|
88 /**
|
Chris@0
|
89 * Lengths of the columns, calculated when rows are added to the table.
|
Chris@0
|
90 *
|
Chris@0
|
91 * @var array
|
Chris@0
|
92 */
|
Chris@0
|
93 var $_cell_lengths = array();
|
Chris@0
|
94
|
Chris@0
|
95 /**
|
Chris@0
|
96 * Heights of the rows.
|
Chris@0
|
97 *
|
Chris@0
|
98 * @var array
|
Chris@0
|
99 */
|
Chris@0
|
100 var $_row_heights = array();
|
Chris@0
|
101
|
Chris@0
|
102 /**
|
Chris@0
|
103 * How many spaces to use to pad the table.
|
Chris@0
|
104 *
|
Chris@0
|
105 * @var integer
|
Chris@0
|
106 */
|
Chris@0
|
107 var $_padding = 1;
|
Chris@0
|
108
|
Chris@0
|
109 /**
|
Chris@0
|
110 * Column filters.
|
Chris@0
|
111 *
|
Chris@0
|
112 * @var array
|
Chris@0
|
113 */
|
Chris@0
|
114 var $_filters = array();
|
Chris@0
|
115
|
Chris@0
|
116 /**
|
Chris@0
|
117 * Columns to calculate totals for.
|
Chris@0
|
118 *
|
Chris@0
|
119 * @var array
|
Chris@0
|
120 */
|
Chris@0
|
121 var $_calculateTotals;
|
Chris@0
|
122
|
Chris@0
|
123 /**
|
Chris@0
|
124 * Alignment of the columns.
|
Chris@0
|
125 *
|
Chris@0
|
126 * @var array
|
Chris@0
|
127 */
|
Chris@0
|
128 var $_col_align = array();
|
Chris@0
|
129
|
Chris@0
|
130 /**
|
Chris@0
|
131 * Default alignment of columns.
|
Chris@0
|
132 *
|
Chris@0
|
133 * @var integer
|
Chris@0
|
134 */
|
Chris@0
|
135 var $_defaultAlign;
|
Chris@0
|
136
|
Chris@0
|
137 /**
|
Chris@0
|
138 * Character set of the data.
|
Chris@0
|
139 *
|
Chris@0
|
140 * @var string
|
Chris@0
|
141 */
|
Chris@0
|
142 var $_charset = 'utf-8';
|
Chris@0
|
143
|
Chris@0
|
144 /**
|
Chris@0
|
145 * Border characters.
|
Chris@0
|
146 * Allowed keys:
|
Chris@0
|
147 * - intersection - intersection ("+")
|
Chris@0
|
148 * - horizontal - horizontal rule character ("-")
|
Chris@0
|
149 * - vertical - vertical rule character ("|")
|
Chris@0
|
150 *
|
Chris@0
|
151 * @var array
|
Chris@0
|
152 */
|
Chris@0
|
153 var $_border = array(
|
Chris@0
|
154 'intersection' => '+',
|
Chris@0
|
155 'horizontal' => '-',
|
Chris@0
|
156 'vertical' => '|',
|
Chris@0
|
157 );
|
Chris@0
|
158
|
Chris@0
|
159 /**
|
Chris@0
|
160 * If borders are shown or not
|
Chris@0
|
161 * Allowed keys: top, right, bottom, left, inner: true and false
|
Chris@0
|
162 *
|
Chris@0
|
163 * @var array
|
Chris@0
|
164 */
|
Chris@0
|
165 var $_borderVisibility = array(
|
Chris@0
|
166 'top' => true,
|
Chris@0
|
167 'right' => true,
|
Chris@0
|
168 'bottom' => true,
|
Chris@0
|
169 'left' => true,
|
Chris@0
|
170 'inner' => true
|
Chris@0
|
171 );
|
Chris@0
|
172
|
Chris@0
|
173 /**
|
Chris@0
|
174 * Whether the data has ANSI colors.
|
Chris@0
|
175 *
|
Chris@0
|
176 * @var Console_Color2
|
Chris@0
|
177 */
|
Chris@0
|
178 var $_ansiColor = false;
|
Chris@0
|
179
|
Chris@0
|
180 /**
|
Chris@0
|
181 * Constructor.
|
Chris@0
|
182 *
|
Chris@0
|
183 * @param integer $align Default alignment. One of
|
Chris@0
|
184 * CONSOLE_TABLE_ALIGN_LEFT,
|
Chris@0
|
185 * CONSOLE_TABLE_ALIGN_CENTER or
|
Chris@0
|
186 * CONSOLE_TABLE_ALIGN_RIGHT.
|
Chris@0
|
187 * @param string $border The character used for table borders or
|
Chris@0
|
188 * CONSOLE_TABLE_BORDER_ASCII.
|
Chris@0
|
189 * @param integer $padding How many spaces to use to pad the table.
|
Chris@0
|
190 * @param string $charset A charset supported by the mbstring PHP
|
Chris@0
|
191 * extension.
|
Chris@0
|
192 * @param boolean $color Whether the data contains ansi color codes.
|
Chris@0
|
193 */
|
Chris@0
|
194 function __construct($align = CONSOLE_TABLE_ALIGN_LEFT,
|
Chris@0
|
195 $border = CONSOLE_TABLE_BORDER_ASCII, $padding = 1,
|
Chris@0
|
196 $charset = null, $color = false)
|
Chris@0
|
197 {
|
Chris@0
|
198 $this->_defaultAlign = $align;
|
Chris@0
|
199 $this->setBorder($border);
|
Chris@0
|
200 $this->_padding = $padding;
|
Chris@0
|
201 if ($color) {
|
Chris@0
|
202 if (!class_exists('Console_Color2')) {
|
Chris@0
|
203 include_once 'Console/Color2.php';
|
Chris@0
|
204 }
|
Chris@0
|
205 $this->_ansiColor = new Console_Color2();
|
Chris@0
|
206 }
|
Chris@0
|
207 if (!empty($charset)) {
|
Chris@0
|
208 $this->setCharset($charset);
|
Chris@0
|
209 }
|
Chris@0
|
210 }
|
Chris@0
|
211
|
Chris@0
|
212 /**
|
Chris@0
|
213 * Converts an array to a table.
|
Chris@0
|
214 *
|
Chris@0
|
215 * @param array $headers Headers for the table.
|
Chris@0
|
216 * @param array $data A two dimensional array with the table
|
Chris@0
|
217 * data.
|
Chris@0
|
218 * @param boolean $returnObject Whether to return the Console_Table object
|
Chris@0
|
219 * instead of the rendered table.
|
Chris@0
|
220 *
|
Chris@0
|
221 * @static
|
Chris@0
|
222 *
|
Chris@0
|
223 * @return Console_Table|string A Console_Table object or the generated
|
Chris@0
|
224 * table.
|
Chris@0
|
225 */
|
Chris@0
|
226 function fromArray($headers, $data, $returnObject = false)
|
Chris@0
|
227 {
|
Chris@0
|
228 if (!is_array($headers) || !is_array($data)) {
|
Chris@0
|
229 return false;
|
Chris@0
|
230 }
|
Chris@0
|
231
|
Chris@0
|
232 $table = new Console_Table();
|
Chris@0
|
233 $table->setHeaders($headers);
|
Chris@0
|
234
|
Chris@0
|
235 foreach ($data as $row) {
|
Chris@0
|
236 $table->addRow($row);
|
Chris@0
|
237 }
|
Chris@0
|
238
|
Chris@0
|
239 return $returnObject ? $table : $table->getTable();
|
Chris@0
|
240 }
|
Chris@0
|
241
|
Chris@0
|
242 /**
|
Chris@0
|
243 * Adds a filter to a column.
|
Chris@0
|
244 *
|
Chris@0
|
245 * Filters are standard PHP callbacks which are run on the data before
|
Chris@0
|
246 * table generation is performed. Filters are applied in the order they
|
Chris@0
|
247 * are added. The callback function must accept a single argument, which
|
Chris@0
|
248 * is a single table cell.
|
Chris@0
|
249 *
|
Chris@0
|
250 * @param integer $col Column to apply filter to.
|
Chris@0
|
251 * @param mixed &$callback PHP callback to apply.
|
Chris@0
|
252 *
|
Chris@0
|
253 * @return void
|
Chris@0
|
254 */
|
Chris@0
|
255 function addFilter($col, &$callback)
|
Chris@0
|
256 {
|
Chris@0
|
257 $this->_filters[] = array($col, &$callback);
|
Chris@0
|
258 }
|
Chris@0
|
259
|
Chris@0
|
260 /**
|
Chris@0
|
261 * Sets the charset of the provided table data.
|
Chris@0
|
262 *
|
Chris@0
|
263 * @param string $charset A charset supported by the mbstring PHP
|
Chris@0
|
264 * extension.
|
Chris@0
|
265 *
|
Chris@0
|
266 * @return void
|
Chris@0
|
267 */
|
Chris@0
|
268 function setCharset($charset)
|
Chris@0
|
269 {
|
Chris@0
|
270 $locale = setlocale(LC_CTYPE, 0);
|
Chris@0
|
271 setlocale(LC_CTYPE, 'en_US');
|
Chris@0
|
272 $this->_charset = strtolower($charset);
|
Chris@0
|
273 setlocale(LC_CTYPE, $locale);
|
Chris@0
|
274 }
|
Chris@0
|
275
|
Chris@0
|
276 /**
|
Chris@0
|
277 * Set the table border settings
|
Chris@0
|
278 *
|
Chris@0
|
279 * Border definition modes:
|
Chris@0
|
280 * - CONSOLE_TABLE_BORDER_ASCII: Default border with +, - and |
|
Chris@0
|
281 * - array with keys "intersection", "horizontal" and "vertical"
|
Chris@0
|
282 * - single character string that sets all three of the array keys
|
Chris@0
|
283 *
|
Chris@0
|
284 * @param mixed $border Border definition
|
Chris@0
|
285 *
|
Chris@0
|
286 * @return void
|
Chris@0
|
287 * @see $_border
|
Chris@0
|
288 */
|
Chris@0
|
289 function setBorder($border)
|
Chris@0
|
290 {
|
Chris@0
|
291 if ($border === CONSOLE_TABLE_BORDER_ASCII) {
|
Chris@0
|
292 $intersection = '+';
|
Chris@0
|
293 $horizontal = '-';
|
Chris@0
|
294 $vertical = '|';
|
Chris@0
|
295 } else if (is_string($border)) {
|
Chris@0
|
296 $intersection = $horizontal = $vertical = $border;
|
Chris@0
|
297 } else if ($border == '') {
|
Chris@0
|
298 $intersection = $horizontal = $vertical = '';
|
Chris@0
|
299 } else {
|
Chris@0
|
300 extract($border);
|
Chris@0
|
301 }
|
Chris@0
|
302
|
Chris@0
|
303 $this->_border = array(
|
Chris@0
|
304 'intersection' => $intersection,
|
Chris@0
|
305 'horizontal' => $horizontal,
|
Chris@0
|
306 'vertical' => $vertical,
|
Chris@0
|
307 );
|
Chris@0
|
308 }
|
Chris@0
|
309
|
Chris@0
|
310 /**
|
Chris@0
|
311 * Set which borders shall be shown.
|
Chris@0
|
312 *
|
Chris@0
|
313 * @param array $visibility Visibility settings.
|
Chris@0
|
314 * Allowed keys: left, right, top, bottom, inner
|
Chris@0
|
315 *
|
Chris@0
|
316 * @return void
|
Chris@0
|
317 * @see $_borderVisibility
|
Chris@0
|
318 */
|
Chris@0
|
319 function setBorderVisibility($visibility)
|
Chris@0
|
320 {
|
Chris@0
|
321 $this->_borderVisibility = array_merge(
|
Chris@0
|
322 $this->_borderVisibility,
|
Chris@0
|
323 array_intersect_key(
|
Chris@0
|
324 $visibility,
|
Chris@0
|
325 $this->_borderVisibility
|
Chris@0
|
326 )
|
Chris@0
|
327 );
|
Chris@0
|
328 }
|
Chris@0
|
329
|
Chris@0
|
330 /**
|
Chris@0
|
331 * Sets the alignment for the columns.
|
Chris@0
|
332 *
|
Chris@0
|
333 * @param integer $col_id The column number.
|
Chris@0
|
334 * @param integer $align Alignment to set for this column. One of
|
Chris@0
|
335 * CONSOLE_TABLE_ALIGN_LEFT
|
Chris@0
|
336 * CONSOLE_TABLE_ALIGN_CENTER
|
Chris@0
|
337 * CONSOLE_TABLE_ALIGN_RIGHT.
|
Chris@0
|
338 *
|
Chris@0
|
339 * @return void
|
Chris@0
|
340 */
|
Chris@0
|
341 function setAlign($col_id, $align = CONSOLE_TABLE_ALIGN_LEFT)
|
Chris@0
|
342 {
|
Chris@0
|
343 switch ($align) {
|
Chris@0
|
344 case CONSOLE_TABLE_ALIGN_CENTER:
|
Chris@0
|
345 $pad = STR_PAD_BOTH;
|
Chris@0
|
346 break;
|
Chris@0
|
347 case CONSOLE_TABLE_ALIGN_RIGHT:
|
Chris@0
|
348 $pad = STR_PAD_LEFT;
|
Chris@0
|
349 break;
|
Chris@0
|
350 default:
|
Chris@0
|
351 $pad = STR_PAD_RIGHT;
|
Chris@0
|
352 break;
|
Chris@0
|
353 }
|
Chris@0
|
354 $this->_col_align[$col_id] = $pad;
|
Chris@0
|
355 }
|
Chris@0
|
356
|
Chris@0
|
357 /**
|
Chris@0
|
358 * Specifies which columns are to have totals calculated for them and
|
Chris@0
|
359 * added as a new row at the bottom.
|
Chris@0
|
360 *
|
Chris@0
|
361 * @param array $cols Array of column numbers (starting with 0).
|
Chris@0
|
362 *
|
Chris@0
|
363 * @return void
|
Chris@0
|
364 */
|
Chris@0
|
365 function calculateTotalsFor($cols)
|
Chris@0
|
366 {
|
Chris@0
|
367 $this->_calculateTotals = $cols;
|
Chris@0
|
368 }
|
Chris@0
|
369
|
Chris@0
|
370 /**
|
Chris@0
|
371 * Sets the headers for the columns.
|
Chris@0
|
372 *
|
Chris@0
|
373 * @param array $headers The column headers.
|
Chris@0
|
374 *
|
Chris@0
|
375 * @return void
|
Chris@0
|
376 */
|
Chris@0
|
377 function setHeaders($headers)
|
Chris@0
|
378 {
|
Chris@0
|
379 $this->_headers = array(array_values($headers));
|
Chris@0
|
380 $this->_updateRowsCols($headers);
|
Chris@0
|
381 }
|
Chris@0
|
382
|
Chris@0
|
383 /**
|
Chris@0
|
384 * Adds a row to the table.
|
Chris@0
|
385 *
|
Chris@0
|
386 * @param array $row The row data to add.
|
Chris@0
|
387 * @param boolean $append Whether to append or prepend the row.
|
Chris@0
|
388 *
|
Chris@0
|
389 * @return void
|
Chris@0
|
390 */
|
Chris@0
|
391 function addRow($row, $append = true)
|
Chris@0
|
392 {
|
Chris@0
|
393 if ($append) {
|
Chris@0
|
394 $this->_data[] = array_values($row);
|
Chris@0
|
395 } else {
|
Chris@0
|
396 array_unshift($this->_data, array_values($row));
|
Chris@0
|
397 }
|
Chris@0
|
398
|
Chris@0
|
399 $this->_updateRowsCols($row);
|
Chris@0
|
400 }
|
Chris@0
|
401
|
Chris@0
|
402 /**
|
Chris@0
|
403 * Inserts a row after a given row number in the table.
|
Chris@0
|
404 *
|
Chris@0
|
405 * If $row_id is not given it will prepend the row.
|
Chris@0
|
406 *
|
Chris@0
|
407 * @param array $row The data to insert.
|
Chris@0
|
408 * @param integer $row_id Row number to insert before.
|
Chris@0
|
409 *
|
Chris@0
|
410 * @return void
|
Chris@0
|
411 */
|
Chris@0
|
412 function insertRow($row, $row_id = 0)
|
Chris@0
|
413 {
|
Chris@0
|
414 array_splice($this->_data, $row_id, 0, array($row));
|
Chris@0
|
415
|
Chris@0
|
416 $this->_updateRowsCols($row);
|
Chris@0
|
417 }
|
Chris@0
|
418
|
Chris@0
|
419 /**
|
Chris@0
|
420 * Adds a column to the table.
|
Chris@0
|
421 *
|
Chris@0
|
422 * @param array $col_data The data of the column.
|
Chris@0
|
423 * @param integer $col_id The column index to populate.
|
Chris@0
|
424 * @param integer $row_id If starting row is not zero, specify it here.
|
Chris@0
|
425 *
|
Chris@0
|
426 * @return void
|
Chris@0
|
427 */
|
Chris@0
|
428 function addCol($col_data, $col_id = 0, $row_id = 0)
|
Chris@0
|
429 {
|
Chris@0
|
430 foreach ($col_data as $col_cell) {
|
Chris@0
|
431 $this->_data[$row_id++][$col_id] = $col_cell;
|
Chris@0
|
432 }
|
Chris@0
|
433
|
Chris@0
|
434 $this->_updateRowsCols();
|
Chris@0
|
435 $this->_max_cols = max($this->_max_cols, $col_id + 1);
|
Chris@0
|
436 }
|
Chris@0
|
437
|
Chris@0
|
438 /**
|
Chris@0
|
439 * Adds data to the table.
|
Chris@0
|
440 *
|
Chris@0
|
441 * @param array $data A two dimensional array with the table data.
|
Chris@0
|
442 * @param integer $col_id Starting column number.
|
Chris@0
|
443 * @param integer $row_id Starting row number.
|
Chris@0
|
444 *
|
Chris@0
|
445 * @return void
|
Chris@0
|
446 */
|
Chris@0
|
447 function addData($data, $col_id = 0, $row_id = 0)
|
Chris@0
|
448 {
|
Chris@0
|
449 foreach ($data as $row) {
|
Chris@0
|
450 if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
|
Chris@0
|
451 $this->_data[$row_id] = CONSOLE_TABLE_HORIZONTAL_RULE;
|
Chris@0
|
452 $row_id++;
|
Chris@0
|
453 continue;
|
Chris@0
|
454 }
|
Chris@0
|
455 $starting_col = $col_id;
|
Chris@0
|
456 foreach ($row as $cell) {
|
Chris@0
|
457 $this->_data[$row_id][$starting_col++] = $cell;
|
Chris@0
|
458 }
|
Chris@0
|
459 $this->_updateRowsCols();
|
Chris@0
|
460 $this->_max_cols = max($this->_max_cols, $starting_col);
|
Chris@0
|
461 $row_id++;
|
Chris@0
|
462 }
|
Chris@0
|
463 }
|
Chris@0
|
464
|
Chris@0
|
465 /**
|
Chris@0
|
466 * Adds a horizontal seperator to the table.
|
Chris@0
|
467 *
|
Chris@0
|
468 * @return void
|
Chris@0
|
469 */
|
Chris@0
|
470 function addSeparator()
|
Chris@0
|
471 {
|
Chris@0
|
472 $this->_data[] = CONSOLE_TABLE_HORIZONTAL_RULE;
|
Chris@0
|
473 }
|
Chris@0
|
474
|
Chris@0
|
475 /**
|
Chris@0
|
476 * Returns the generated table.
|
Chris@0
|
477 *
|
Chris@0
|
478 * @return string The generated table.
|
Chris@0
|
479 */
|
Chris@0
|
480 function getTable()
|
Chris@0
|
481 {
|
Chris@0
|
482 $this->_applyFilters();
|
Chris@0
|
483 $this->_calculateTotals();
|
Chris@0
|
484 $this->_validateTable();
|
Chris@0
|
485
|
Chris@0
|
486 return $this->_buildTable();
|
Chris@0
|
487 }
|
Chris@0
|
488
|
Chris@0
|
489 /**
|
Chris@0
|
490 * Calculates totals for columns.
|
Chris@0
|
491 *
|
Chris@0
|
492 * @return void
|
Chris@0
|
493 */
|
Chris@0
|
494 function _calculateTotals()
|
Chris@0
|
495 {
|
Chris@0
|
496 if (empty($this->_calculateTotals)) {
|
Chris@0
|
497 return;
|
Chris@0
|
498 }
|
Chris@0
|
499
|
Chris@0
|
500 $this->addSeparator();
|
Chris@0
|
501
|
Chris@0
|
502 $totals = array();
|
Chris@0
|
503 foreach ($this->_data as $row) {
|
Chris@0
|
504 if (is_array($row)) {
|
Chris@0
|
505 foreach ($this->_calculateTotals as $columnID) {
|
Chris@0
|
506 $totals[$columnID] += $row[$columnID];
|
Chris@0
|
507 }
|
Chris@0
|
508 }
|
Chris@0
|
509 }
|
Chris@0
|
510
|
Chris@0
|
511 $this->_data[] = $totals;
|
Chris@0
|
512 $this->_updateRowsCols();
|
Chris@0
|
513 }
|
Chris@0
|
514
|
Chris@0
|
515 /**
|
Chris@0
|
516 * Applies any column filters to the data.
|
Chris@0
|
517 *
|
Chris@0
|
518 * @return void
|
Chris@0
|
519 */
|
Chris@0
|
520 function _applyFilters()
|
Chris@0
|
521 {
|
Chris@0
|
522 if (empty($this->_filters)) {
|
Chris@0
|
523 return;
|
Chris@0
|
524 }
|
Chris@0
|
525
|
Chris@0
|
526 foreach ($this->_filters as $filter) {
|
Chris@0
|
527 $column = $filter[0];
|
Chris@0
|
528 $callback = $filter[1];
|
Chris@0
|
529
|
Chris@0
|
530 foreach ($this->_data as $row_id => $row_data) {
|
Chris@0
|
531 if ($row_data !== CONSOLE_TABLE_HORIZONTAL_RULE) {
|
Chris@0
|
532 $this->_data[$row_id][$column] =
|
Chris@0
|
533 call_user_func($callback, $row_data[$column]);
|
Chris@0
|
534 }
|
Chris@0
|
535 }
|
Chris@0
|
536 }
|
Chris@0
|
537 }
|
Chris@0
|
538
|
Chris@0
|
539 /**
|
Chris@0
|
540 * Ensures that column and row counts are correct.
|
Chris@0
|
541 *
|
Chris@0
|
542 * @return void
|
Chris@0
|
543 */
|
Chris@0
|
544 function _validateTable()
|
Chris@0
|
545 {
|
Chris@0
|
546 if (!empty($this->_headers)) {
|
Chris@0
|
547 $this->_calculateRowHeight(-1, $this->_headers[0]);
|
Chris@0
|
548 }
|
Chris@0
|
549
|
Chris@0
|
550 for ($i = 0; $i < $this->_max_rows; $i++) {
|
Chris@0
|
551 for ($j = 0; $j < $this->_max_cols; $j++) {
|
Chris@0
|
552 if (!isset($this->_data[$i][$j]) &&
|
Chris@0
|
553 (!isset($this->_data[$i]) ||
|
Chris@0
|
554 $this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE)) {
|
Chris@0
|
555 $this->_data[$i][$j] = '';
|
Chris@0
|
556 }
|
Chris@0
|
557
|
Chris@0
|
558 }
|
Chris@0
|
559 $this->_calculateRowHeight($i, $this->_data[$i]);
|
Chris@0
|
560
|
Chris@0
|
561 if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
|
Chris@0
|
562 ksort($this->_data[$i]);
|
Chris@0
|
563 }
|
Chris@0
|
564
|
Chris@0
|
565 }
|
Chris@0
|
566
|
Chris@0
|
567 $this->_splitMultilineRows();
|
Chris@0
|
568
|
Chris@0
|
569 // Update cell lengths.
|
Chris@0
|
570 for ($i = 0; $i < count($this->_headers); $i++) {
|
Chris@0
|
571 $this->_calculateCellLengths($this->_headers[$i]);
|
Chris@0
|
572 }
|
Chris@0
|
573 for ($i = 0; $i < $this->_max_rows; $i++) {
|
Chris@0
|
574 $this->_calculateCellLengths($this->_data[$i]);
|
Chris@0
|
575 }
|
Chris@0
|
576
|
Chris@0
|
577 ksort($this->_data);
|
Chris@0
|
578 }
|
Chris@0
|
579
|
Chris@0
|
580 /**
|
Chris@0
|
581 * Splits multiline rows into many smaller one-line rows.
|
Chris@0
|
582 *
|
Chris@0
|
583 * @return void
|
Chris@0
|
584 */
|
Chris@0
|
585 function _splitMultilineRows()
|
Chris@0
|
586 {
|
Chris@0
|
587 ksort($this->_data);
|
Chris@0
|
588 $sections = array(&$this->_headers, &$this->_data);
|
Chris@0
|
589 $max_rows = array(count($this->_headers), $this->_max_rows);
|
Chris@0
|
590 $row_height_offset = array(-1, 0);
|
Chris@0
|
591
|
Chris@0
|
592 for ($s = 0; $s <= 1; $s++) {
|
Chris@0
|
593 $inserted = 0;
|
Chris@0
|
594 $new_data = $sections[$s];
|
Chris@0
|
595
|
Chris@0
|
596 for ($i = 0; $i < $max_rows[$s]; $i++) {
|
Chris@0
|
597 // Process only rows that have many lines.
|
Chris@0
|
598 $height = $this->_row_heights[$i + $row_height_offset[$s]];
|
Chris@0
|
599 if ($height > 1) {
|
Chris@0
|
600 // Split column data into one-liners.
|
Chris@0
|
601 $split = array();
|
Chris@0
|
602 for ($j = 0; $j < $this->_max_cols; $j++) {
|
Chris@0
|
603 $split[$j] = preg_split('/\r?\n|\r/',
|
Chris@0
|
604 $sections[$s][$i][$j]);
|
Chris@0
|
605 }
|
Chris@0
|
606
|
Chris@0
|
607 $new_rows = array();
|
Chris@0
|
608 // Construct new 'virtual' rows - insert empty strings for
|
Chris@0
|
609 // columns that have less lines that the highest one.
|
Chris@0
|
610 for ($i2 = 0; $i2 < $height; $i2++) {
|
Chris@0
|
611 for ($j = 0; $j < $this->_max_cols; $j++) {
|
Chris@0
|
612 $new_rows[$i2][$j] = !isset($split[$j][$i2])
|
Chris@0
|
613 ? ''
|
Chris@0
|
614 : $split[$j][$i2];
|
Chris@0
|
615 }
|
Chris@0
|
616 }
|
Chris@0
|
617
|
Chris@0
|
618 // Replace current row with smaller rows. $inserted is
|
Chris@0
|
619 // used to take account of bigger array because of already
|
Chris@0
|
620 // inserted rows.
|
Chris@0
|
621 array_splice($new_data, $i + $inserted, 1, $new_rows);
|
Chris@0
|
622 $inserted += count($new_rows) - 1;
|
Chris@0
|
623 }
|
Chris@0
|
624 }
|
Chris@0
|
625
|
Chris@0
|
626 // Has the data been modified?
|
Chris@0
|
627 if ($inserted > 0) {
|
Chris@0
|
628 $sections[$s] = $new_data;
|
Chris@0
|
629 $this->_updateRowsCols();
|
Chris@0
|
630 }
|
Chris@0
|
631 }
|
Chris@0
|
632 }
|
Chris@0
|
633
|
Chris@0
|
634 /**
|
Chris@0
|
635 * Builds the table.
|
Chris@0
|
636 *
|
Chris@0
|
637 * @return string The generated table string.
|
Chris@0
|
638 */
|
Chris@0
|
639 function _buildTable()
|
Chris@0
|
640 {
|
Chris@0
|
641 if (!count($this->_data)) {
|
Chris@0
|
642 return '';
|
Chris@0
|
643 }
|
Chris@0
|
644
|
Chris@0
|
645 $vertical = $this->_border['vertical'];
|
Chris@0
|
646 $separator = $this->_getSeparator();
|
Chris@0
|
647
|
Chris@0
|
648 $return = array();
|
Chris@0
|
649 for ($i = 0; $i < count($this->_data); $i++) {
|
Chris@12
|
650 if (is_array($this->_data[$i])) {
|
Chris@12
|
651 for ($j = 0; $j < count($this->_data[$i]); $j++) {
|
Chris@12
|
652 if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE &&
|
Chris@12
|
653 $this->_strlen($this->_data[$i][$j]) <
|
Chris@12
|
654 $this->_cell_lengths[$j]) {
|
Chris@12
|
655 $this->_data[$i][$j] = $this->_strpad($this->_data[$i][$j],
|
Chris@12
|
656 $this->_cell_lengths[$j],
|
Chris@12
|
657 ' ',
|
Chris@12
|
658 $this->_col_align[$j]);
|
Chris@12
|
659 }
|
Chris@0
|
660 }
|
Chris@0
|
661 }
|
Chris@0
|
662
|
Chris@0
|
663 if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
|
Chris@0
|
664 $row_begin = $this->_borderVisibility['left']
|
Chris@0
|
665 ? $vertical . str_repeat(' ', $this->_padding)
|
Chris@0
|
666 : '';
|
Chris@0
|
667 $row_end = $this->_borderVisibility['right']
|
Chris@0
|
668 ? str_repeat(' ', $this->_padding) . $vertical
|
Chris@0
|
669 : '';
|
Chris@0
|
670 $implode_char = str_repeat(' ', $this->_padding) . $vertical
|
Chris@0
|
671 . str_repeat(' ', $this->_padding);
|
Chris@0
|
672 $return[] = $row_begin
|
Chris@0
|
673 . implode($implode_char, $this->_data[$i]) . $row_end;
|
Chris@0
|
674 } elseif (!empty($separator)) {
|
Chris@0
|
675 $return[] = $separator;
|
Chris@0
|
676 }
|
Chris@0
|
677
|
Chris@0
|
678 }
|
Chris@0
|
679
|
Chris@0
|
680 $return = implode(PHP_EOL, $return);
|
Chris@0
|
681 if (!empty($separator)) {
|
Chris@0
|
682 if ($this->_borderVisibility['inner']) {
|
Chris@0
|
683 $return = $separator . PHP_EOL . $return;
|
Chris@0
|
684 }
|
Chris@0
|
685 if ($this->_borderVisibility['bottom']) {
|
Chris@0
|
686 $return .= PHP_EOL . $separator;
|
Chris@0
|
687 }
|
Chris@0
|
688 }
|
Chris@0
|
689 $return .= PHP_EOL;
|
Chris@0
|
690
|
Chris@0
|
691 if (!empty($this->_headers)) {
|
Chris@0
|
692 $return = $this->_getHeaderLine() . PHP_EOL . $return;
|
Chris@0
|
693 }
|
Chris@0
|
694
|
Chris@0
|
695 return $return;
|
Chris@0
|
696 }
|
Chris@0
|
697
|
Chris@0
|
698 /**
|
Chris@0
|
699 * Creates a horizontal separator for header separation and table
|
Chris@0
|
700 * start/end etc.
|
Chris@0
|
701 *
|
Chris@0
|
702 * @return string The horizontal separator.
|
Chris@0
|
703 */
|
Chris@0
|
704 function _getSeparator()
|
Chris@0
|
705 {
|
Chris@0
|
706 if (!$this->_border) {
|
Chris@0
|
707 return;
|
Chris@0
|
708 }
|
Chris@0
|
709
|
Chris@0
|
710 $horizontal = $this->_border['horizontal'];
|
Chris@0
|
711 $intersection = $this->_border['intersection'];
|
Chris@0
|
712
|
Chris@0
|
713 $return = array();
|
Chris@0
|
714 foreach ($this->_cell_lengths as $cl) {
|
Chris@0
|
715 $return[] = str_repeat($horizontal, $cl);
|
Chris@0
|
716 }
|
Chris@0
|
717
|
Chris@0
|
718 $row_begin = $this->_borderVisibility['left']
|
Chris@0
|
719 ? $intersection . str_repeat($horizontal, $this->_padding)
|
Chris@0
|
720 : '';
|
Chris@0
|
721 $row_end = $this->_borderVisibility['right']
|
Chris@0
|
722 ? str_repeat($horizontal, $this->_padding) . $intersection
|
Chris@0
|
723 : '';
|
Chris@0
|
724 $implode_char = str_repeat($horizontal, $this->_padding) . $intersection
|
Chris@0
|
725 . str_repeat($horizontal, $this->_padding);
|
Chris@0
|
726
|
Chris@0
|
727 return $row_begin . implode($implode_char, $return) . $row_end;
|
Chris@0
|
728 }
|
Chris@0
|
729
|
Chris@0
|
730 /**
|
Chris@0
|
731 * Returns the header line for the table.
|
Chris@0
|
732 *
|
Chris@0
|
733 * @return string The header line of the table.
|
Chris@0
|
734 */
|
Chris@0
|
735 function _getHeaderLine()
|
Chris@0
|
736 {
|
Chris@0
|
737 // Make sure column count is correct
|
Chris@0
|
738 for ($j = 0; $j < count($this->_headers); $j++) {
|
Chris@0
|
739 for ($i = 0; $i < $this->_max_cols; $i++) {
|
Chris@0
|
740 if (!isset($this->_headers[$j][$i])) {
|
Chris@0
|
741 $this->_headers[$j][$i] = '';
|
Chris@0
|
742 }
|
Chris@0
|
743 }
|
Chris@0
|
744 }
|
Chris@0
|
745
|
Chris@0
|
746 for ($j = 0; $j < count($this->_headers); $j++) {
|
Chris@0
|
747 for ($i = 0; $i < count($this->_headers[$j]); $i++) {
|
Chris@0
|
748 if ($this->_strlen($this->_headers[$j][$i]) <
|
Chris@0
|
749 $this->_cell_lengths[$i]) {
|
Chris@0
|
750 $this->_headers[$j][$i] =
|
Chris@0
|
751 $this->_strpad($this->_headers[$j][$i],
|
Chris@0
|
752 $this->_cell_lengths[$i],
|
Chris@0
|
753 ' ',
|
Chris@0
|
754 $this->_col_align[$i]);
|
Chris@0
|
755 }
|
Chris@0
|
756 }
|
Chris@0
|
757 }
|
Chris@0
|
758
|
Chris@0
|
759 $vertical = $this->_border['vertical'];
|
Chris@0
|
760 $row_begin = $this->_borderVisibility['left']
|
Chris@0
|
761 ? $vertical . str_repeat(' ', $this->_padding)
|
Chris@0
|
762 : '';
|
Chris@0
|
763 $row_end = $this->_borderVisibility['right']
|
Chris@0
|
764 ? str_repeat(' ', $this->_padding) . $vertical
|
Chris@0
|
765 : '';
|
Chris@0
|
766 $implode_char = str_repeat(' ', $this->_padding) . $vertical
|
Chris@0
|
767 . str_repeat(' ', $this->_padding);
|
Chris@0
|
768
|
Chris@0
|
769 $separator = $this->_getSeparator();
|
Chris@0
|
770 if (!empty($separator) && $this->_borderVisibility['top']) {
|
Chris@0
|
771 $return[] = $separator;
|
Chris@0
|
772 }
|
Chris@0
|
773 for ($j = 0; $j < count($this->_headers); $j++) {
|
Chris@0
|
774 $return[] = $row_begin
|
Chris@0
|
775 . implode($implode_char, $this->_headers[$j]) . $row_end;
|
Chris@0
|
776 }
|
Chris@0
|
777
|
Chris@0
|
778 return implode(PHP_EOL, $return);
|
Chris@0
|
779 }
|
Chris@0
|
780
|
Chris@0
|
781 /**
|
Chris@0
|
782 * Updates values for maximum columns and rows.
|
Chris@0
|
783 *
|
Chris@0
|
784 * @param array $rowdata Data array of a single row.
|
Chris@0
|
785 *
|
Chris@0
|
786 * @return void
|
Chris@0
|
787 */
|
Chris@0
|
788 function _updateRowsCols($rowdata = null)
|
Chris@0
|
789 {
|
Chris@0
|
790 // Update maximum columns.
|
Chris@12
|
791 $this->_max_cols = max($this->_max_cols, is_array($rowdata) ? count($rowdata) : 0);
|
Chris@0
|
792
|
Chris@0
|
793 // Update maximum rows.
|
Chris@0
|
794 ksort($this->_data);
|
Chris@0
|
795 $keys = array_keys($this->_data);
|
Chris@0
|
796 $this->_max_rows = end($keys) + 1;
|
Chris@0
|
797
|
Chris@0
|
798 switch ($this->_defaultAlign) {
|
Chris@0
|
799 case CONSOLE_TABLE_ALIGN_CENTER:
|
Chris@0
|
800 $pad = STR_PAD_BOTH;
|
Chris@0
|
801 break;
|
Chris@0
|
802 case CONSOLE_TABLE_ALIGN_RIGHT:
|
Chris@0
|
803 $pad = STR_PAD_LEFT;
|
Chris@0
|
804 break;
|
Chris@0
|
805 default:
|
Chris@0
|
806 $pad = STR_PAD_RIGHT;
|
Chris@0
|
807 break;
|
Chris@0
|
808 }
|
Chris@0
|
809
|
Chris@0
|
810 // Set default column alignments
|
Chris@0
|
811 for ($i = 0; $i < $this->_max_cols; $i++) {
|
Chris@0
|
812 if (!isset($this->_col_align[$i])) {
|
Chris@0
|
813 $this->_col_align[$i] = $pad;
|
Chris@0
|
814 }
|
Chris@0
|
815 }
|
Chris@0
|
816 }
|
Chris@0
|
817
|
Chris@0
|
818 /**
|
Chris@0
|
819 * Calculates the maximum length for each column of a row.
|
Chris@0
|
820 *
|
Chris@0
|
821 * @param array $row The row data.
|
Chris@0
|
822 *
|
Chris@0
|
823 * @return void
|
Chris@0
|
824 */
|
Chris@0
|
825 function _calculateCellLengths($row)
|
Chris@0
|
826 {
|
Chris@12
|
827 if (is_array($row)) {
|
Chris@12
|
828 for ($i = 0; $i < count($row); $i++) {
|
Chris@12
|
829 if (!isset($this->_cell_lengths[$i])) {
|
Chris@12
|
830 $this->_cell_lengths[$i] = 0;
|
Chris@12
|
831 }
|
Chris@12
|
832 $this->_cell_lengths[$i] = max($this->_cell_lengths[$i],
|
Chris@12
|
833 $this->_strlen($row[$i]));
|
Chris@0
|
834 }
|
Chris@0
|
835 }
|
Chris@0
|
836 }
|
Chris@0
|
837
|
Chris@0
|
838 /**
|
Chris@0
|
839 * Calculates the maximum height for all columns of a row.
|
Chris@0
|
840 *
|
Chris@0
|
841 * @param integer $row_number The row number.
|
Chris@0
|
842 * @param array $row The row data.
|
Chris@0
|
843 *
|
Chris@0
|
844 * @return void
|
Chris@0
|
845 */
|
Chris@0
|
846 function _calculateRowHeight($row_number, $row)
|
Chris@0
|
847 {
|
Chris@0
|
848 if (!isset($this->_row_heights[$row_number])) {
|
Chris@0
|
849 $this->_row_heights[$row_number] = 1;
|
Chris@0
|
850 }
|
Chris@0
|
851
|
Chris@0
|
852 // Do not process horizontal rule rows.
|
Chris@0
|
853 if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
|
Chris@0
|
854 return;
|
Chris@0
|
855 }
|
Chris@0
|
856
|
Chris@0
|
857 for ($i = 0, $c = count($row); $i < $c; ++$i) {
|
Chris@0
|
858 $lines = preg_split('/\r?\n|\r/', $row[$i]);
|
Chris@0
|
859 $this->_row_heights[$row_number] = max($this->_row_heights[$row_number],
|
Chris@0
|
860 count($lines));
|
Chris@0
|
861 }
|
Chris@0
|
862 }
|
Chris@0
|
863
|
Chris@0
|
864 /**
|
Chris@0
|
865 * Returns the character length of a string.
|
Chris@0
|
866 *
|
Chris@0
|
867 * @param string $str A multibyte or singlebyte string.
|
Chris@0
|
868 *
|
Chris@0
|
869 * @return integer The string length.
|
Chris@0
|
870 */
|
Chris@0
|
871 function _strlen($str)
|
Chris@0
|
872 {
|
Chris@0
|
873 static $mbstring;
|
Chris@0
|
874
|
Chris@0
|
875 // Strip ANSI color codes if requested.
|
Chris@0
|
876 if ($this->_ansiColor) {
|
Chris@0
|
877 $str = $this->_ansiColor->strip($str);
|
Chris@0
|
878 }
|
Chris@0
|
879
|
Chris@0
|
880 // Cache expensive function_exists() calls.
|
Chris@0
|
881 if (!isset($mbstring)) {
|
Chris@0
|
882 $mbstring = function_exists('mb_strwidth');
|
Chris@0
|
883 }
|
Chris@0
|
884
|
Chris@0
|
885 if ($mbstring) {
|
Chris@0
|
886 return mb_strwidth($str, $this->_charset);
|
Chris@0
|
887 }
|
Chris@0
|
888
|
Chris@0
|
889 return strlen($str);
|
Chris@0
|
890 }
|
Chris@0
|
891
|
Chris@0
|
892 /**
|
Chris@0
|
893 * Returns part of a string.
|
Chris@0
|
894 *
|
Chris@0
|
895 * @param string $string The string to be converted.
|
Chris@0
|
896 * @param integer $start The part's start position, zero based.
|
Chris@0
|
897 * @param integer $length The part's length.
|
Chris@0
|
898 *
|
Chris@0
|
899 * @return string The string's part.
|
Chris@0
|
900 */
|
Chris@0
|
901 function _substr($string, $start, $length = null)
|
Chris@0
|
902 {
|
Chris@0
|
903 static $mbstring;
|
Chris@0
|
904
|
Chris@0
|
905 // Cache expensive function_exists() calls.
|
Chris@0
|
906 if (!isset($mbstring)) {
|
Chris@0
|
907 $mbstring = function_exists('mb_substr');
|
Chris@0
|
908 }
|
Chris@0
|
909
|
Chris@0
|
910 if (is_null($length)) {
|
Chris@0
|
911 $length = $this->_strlen($string);
|
Chris@0
|
912 }
|
Chris@0
|
913 if ($mbstring) {
|
Chris@0
|
914 $ret = @mb_substr($string, $start, $length, $this->_charset);
|
Chris@0
|
915 if (!empty($ret)) {
|
Chris@0
|
916 return $ret;
|
Chris@0
|
917 }
|
Chris@0
|
918 }
|
Chris@0
|
919 return substr($string, $start, $length);
|
Chris@0
|
920 }
|
Chris@0
|
921
|
Chris@0
|
922 /**
|
Chris@0
|
923 * Returns a string padded to a certain length with another string.
|
Chris@0
|
924 *
|
Chris@0
|
925 * This method behaves exactly like str_pad but is multibyte safe.
|
Chris@0
|
926 *
|
Chris@0
|
927 * @param string $input The string to be padded.
|
Chris@0
|
928 * @param integer $length The length of the resulting string.
|
Chris@0
|
929 * @param string $pad The string to pad the input string with. Must
|
Chris@0
|
930 * be in the same charset like the input string.
|
Chris@0
|
931 * @param const $type The padding type. One of STR_PAD_LEFT,
|
Chris@0
|
932 * STR_PAD_RIGHT, or STR_PAD_BOTH.
|
Chris@0
|
933 *
|
Chris@0
|
934 * @return string The padded string.
|
Chris@0
|
935 */
|
Chris@0
|
936 function _strpad($input, $length, $pad = ' ', $type = STR_PAD_RIGHT)
|
Chris@0
|
937 {
|
Chris@0
|
938 $mb_length = $this->_strlen($input);
|
Chris@0
|
939 $sb_length = strlen($input);
|
Chris@0
|
940 $pad_length = $this->_strlen($pad);
|
Chris@0
|
941
|
Chris@0
|
942 /* Return if we already have the length. */
|
Chris@0
|
943 if ($mb_length >= $length) {
|
Chris@0
|
944 return $input;
|
Chris@0
|
945 }
|
Chris@0
|
946
|
Chris@0
|
947 /* Shortcut for single byte strings. */
|
Chris@0
|
948 if ($mb_length == $sb_length && $pad_length == strlen($pad)) {
|
Chris@0
|
949 return str_pad($input, $length, $pad, $type);
|
Chris@0
|
950 }
|
Chris@0
|
951
|
Chris@0
|
952 switch ($type) {
|
Chris@0
|
953 case STR_PAD_LEFT:
|
Chris@0
|
954 $left = $length - $mb_length;
|
Chris@0
|
955 $output = $this->_substr(str_repeat($pad, ceil($left / $pad_length)),
|
Chris@0
|
956 0, $left, $this->_charset) . $input;
|
Chris@0
|
957 break;
|
Chris@0
|
958 case STR_PAD_BOTH:
|
Chris@0
|
959 $left = floor(($length - $mb_length) / 2);
|
Chris@0
|
960 $right = ceil(($length - $mb_length) / 2);
|
Chris@0
|
961 $output = $this->_substr(str_repeat($pad, ceil($left / $pad_length)),
|
Chris@0
|
962 0, $left, $this->_charset) .
|
Chris@0
|
963 $input .
|
Chris@0
|
964 $this->_substr(str_repeat($pad, ceil($right / $pad_length)),
|
Chris@0
|
965 0, $right, $this->_charset);
|
Chris@0
|
966 break;
|
Chris@0
|
967 case STR_PAD_RIGHT:
|
Chris@0
|
968 $right = $length - $mb_length;
|
Chris@0
|
969 $output = $input .
|
Chris@0
|
970 $this->_substr(str_repeat($pad, ceil($right / $pad_length)),
|
Chris@0
|
971 0, $right, $this->_charset);
|
Chris@0
|
972 break;
|
Chris@0
|
973 }
|
Chris@0
|
974
|
Chris@0
|
975 return $output;
|
Chris@0
|
976 }
|
Chris@0
|
977
|
Chris@0
|
978 }
|