5
* This source file is subject to the new BSD license that is bundled
6
* with this package in the file LICENSE.txt.
7
* It is also available through the world-wide-web at this URL:
8
* http://framework.zend.com/license/new-bsd
9
* If you did not receive a copy of the license and are unable to
10
* obtain it through the world-wide-web, please send an email
11
* to license@zend.com so we can send you a copy immediately.
14
* @package Zend_ProgressBar
15
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
16
* @license http://framework.zend.com/license/new-bsd New BSD License
17
* @version $Id: Console.php 12233 2008-11-01 00:11:01Z dasprid $
21
* @see Zend_ProgressBar_Adapter
23
require_once 'Zend/ProgressBar/Adapter.php';
26
* Zend_ProgressBar_Adapter_Console offers a text-based progressbar for console
30
* @package Zend_ProgressBar
31
* @uses Zend_ProgressBar_Adapter_Interface
32
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
* @license http://framework.zend.com/license/new-bsd New BSD License
35
class Zend_ProgressBar_Adapter_Console extends Zend_ProgressBar_Adapter
38
* Percentage value of the progress
40
const ELEMENT_PERCENT = 'ELEMENT_PERCENT';
43
* Visual value of the progress
45
const ELEMENT_BAR = 'ELEMENT_BAR';
50
const ELEMENT_ETA = 'ELEMENT_ETA';
53
* Text part of the progress
55
const ELEMENT_TEXT = 'ELEMENT_TEXT';
58
* Finish action: End of Line
60
const FINISH_ACTION_EOL = 'FINISH_ACTION_EOL';
63
* Finish action: Clear Line
65
const FINISH_ACTION_CLEAR_LINE = 'FINISH_ACTION_CLEAR_LINE';
70
const FINISH_ACTION_NONE = 'FINISH_ACTION_NONE';
73
* Width of the progressbar
77
protected $_width = null;
84
protected $_elements = array(self::ELEMENT_PERCENT,
89
* Which action to do at finish call
93
protected $_finishAction = self::FINISH_ACTION_EOL;
96
* Width of the bar element
100
protected $_barWidth;
103
* Left character(s) within the bar
107
protected $_barLeftChar = '#';
110
* Indicator character(s) within the bar
114
protected $_barIndicatorChar = '';
117
* Right character(s) within the bar
121
protected $_barRightChar = '-';
124
* Stdout stream, when STDOUT is not defined (e.g. in CGI)
128
protected $_stdout = null;
131
* Width of the text element
135
protected $_textWidth = 20;
138
* Wether the output started yet or not
142
protected $_outputStarted = false;
145
* Defined by Zend_ProgressBar_Adapter
147
* @param null|array|Zend_Config $options
149
public function __construct($options = null)
151
// If STDOUT isn't defined, open a local resource
152
if (!defined('STDOUT')) {
153
$this->_stdout = fopen('php://stdout', 'w');
156
// Call parent constructor with options
157
parent::__construct($options);
159
// Check if a width was set, else use auto width
160
if ($this->_width === null) {
166
* Close local stdout, when open
168
public function __destruct()
170
if ($this->_stdout !== null) {
171
fclose($this->_stdout);
176
* Set the width of the progressbar
178
* @param integer $width
179
* @return Zend_ProgressBar_Adapter_Console
181
public function setWidth($width = null)
183
if ($width === null || !is_integer($width)) {
184
if (substr(PHP_OS, 0, 3) === 'WIN') {
185
// We have to default to 79 on windows, because the windows
186
// terminal always has a fixed width of 80 characters and the
187
// cursor is counted to the line, else windows would line break
188
// after every update.
191
// Set the default width of 80
194
// Try to determine the width through stty
195
if (preg_match('#\d+ (\d+)#', @shell_exec('stty size'), $match) === 1) {
196
$this->_width = (int) $match[1];
197
} else if (preg_match('#columns = (\d+);#', @shell_exec('stty'), $match) === 1) {
198
$this->_width = (int) $match[1];
202
$this->_width = (int) $width;
205
$this->_calculateBarWidth();
211
* Set the elements to display with the progressbar
213
* @param array $elements
214
* @throws Zend_ProgressBar_Adapter_Exception When an invalid element is foudn in the array
215
* @return Zend_ProgressBar_Adapter_Console
217
public function setElements(array $elements)
219
$allowedElements = array(self::ELEMENT_PERCENT,
224
if (count(array_diff($elements, $allowedElements)) > 0) {
225
require_once 'Zend/ProgressBar/Adapter/Exception.php';
226
throw new Zend_ProgressBar_Adapter_Exception('Invalid element found in $elements array');
229
$this->_elements = $elements;
231
$this->_calculateBarWidth();
237
* Set the left-hand character for the bar
239
* @param string $char
240
* @throws Zend_ProgressBar_Adapter_Exception When character is empty
241
* @return Zend_ProgressBar_Adapter_Console
243
public function setBarLeftChar($char)
246
require_once 'Zend/ProgressBar/Adapter/Exception.php';
247
throw new Zend_ProgressBar_Adapter_Exception('Character may not be empty');
250
$this->_barLeftChar = (string) $char;
256
* Set the right-hand character for the bar
258
* @param string $char
259
* @throws Zend_ProgressBar_Adapter_Exception When character is empty
260
* @return Zend_ProgressBar_Adapter_Console
262
public function setBarRightChar($char)
265
require_once 'Zend/ProgressBar/Adapter/Exception.php';
266
throw new Zend_ProgressBar_Adapter_Exception('Character may not be empty');
269
$this->_barRightChar = (string) $char;
275
* Set the indicator character for the bar
277
* @param string $char
278
* @return Zend_ProgressBar_Adapter_Console
280
public function setBarIndicatorChar($char)
282
$this->_barIndicatorChar = (string) $char;
288
* Set the width of the text element
290
* @param integer $width
291
* @return Zend_ProgressBar_Adapter_Console
293
public function setTextWidth($width)
295
$this->_textWidth = (int) $width;
297
$this->_calculateBarWidth();
303
* Set the finish action
305
* @param string $action
306
* @throws Zend_ProgressBar_Adapter_Exception When an invalid action is specified
307
* @return Zend_ProgressBar_Adapter_Console
309
public function setFinishAction($action)
311
$allowedActions = array(self::FINISH_ACTION_CLEAR_LINE,
312
self::FINISH_ACTION_EOL,
313
self::FINISH_ACTION_NONE);
315
if (!in_array($action, $allowedActions)) {
316
require_once 'Zend/ProgressBar/Adapter/Exception.php';
317
throw new Zend_ProgressBar_Adapter_Exception('Invalid finish action specified');
320
$this->_finishAction = $action;
326
* Defined by Zend_ProgressBar_Adapter_Interface
328
* @param float $current Current progress value
329
* @param float $max Max progress value
330
* @param flaot $percent Current percent value
331
* @param integer $timeTaken Taken time in seconds
332
* @param integer $timeRemaining Remaining time in seconds
333
* @param string $text Status text
336
public function notify($current, $max, $percent, $timeTaken, $timeRemaining, $text)
338
// See if we must clear the line
339
if ($this->_outputStarted) {
340
$data = str_repeat("\x08", $this->_width);
343
$this->_outputStarted = true;
346
// Build all elements
347
$renderedElements = array();
349
foreach ($this->_elements as $element) {
351
case self::ELEMENT_BAR:
352
$visualWidth = $this->_barWidth - 2;
355
$indicatorWidth = strlen($this->_barIndicatorChar);
357
$doneWidth = min($visualWidth - $indicatorWidth, round($visualWidth * $percent));
358
if ($doneWidth > 0) {
359
$bar .= substr(str_repeat($this->_barLeftChar, ceil($doneWidth / strlen($this->_barLeftChar))), 0, $doneWidth);
362
$bar .= $this->_barIndicatorChar;
364
$leftWidth = $visualWidth - $doneWidth - $indicatorWidth;
365
if ($leftWidth > 0) {
366
$bar .= substr(str_repeat($this->_barRightChar, ceil($leftWidth / strlen($this->_barRightChar))), 0, $leftWidth);
371
$renderedElements[] = $bar;
374
case self::ELEMENT_PERCENT:
375
$renderedElements[] = str_pad(round($percent * 100), 3, ' ', STR_PAD_LEFT) . '%';
378
case self::ELEMENT_ETA:
379
// In the first 5 seconds we don't get accurate results,
380
// this skipping technique is found in many progressbar
382
if ($timeTaken < 5) {
383
$renderedElements[] = str_repeat(' ', 12);
387
if ($timeRemaining === null || $timeRemaining > 86400) {
388
$etaFormatted = '??:??:??';
390
$hours = floor($timeRemaining / 3600);
391
$minutes = floor(($timeRemaining % 3600) / 60);
392
$seconds = ($timeRemaining % 3600 % 60);
394
$etaFormatted = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
397
$renderedElements[] = 'ETA ' . $etaFormatted;
400
case self::ELEMENT_TEXT:
401
$renderedElements[] = str_pad(substr($text, 0, $this->_textWidth), $this->_textWidth, ' ');
406
$data .= implode(' ', $renderedElements);
409
$this->_outputData($data);
413
* Defined by Zend_ProgressBar_Adapter_Interface
417
public function finish()
419
switch ($this->_finishAction) {
420
case self::FINISH_ACTION_EOL:
421
$this->_outputData(PHP_EOL);
424
case self::FINISH_ACTION_CLEAR_LINE:
425
if ($this->_outputStarted) {
426
$data = str_repeat("\x08", $this->_width)
427
. str_repeat(' ', $this->_width)
428
. str_repeat("\x08", $this->_width);
430
$this->_outputData($data);
434
case self::FINISH_ACTION_NONE:
440
* Calculate the bar width when other elements changed
444
protected function _calculateBarWidth()
446
if (in_array(self::ELEMENT_BAR, $this->_elements)) {
447
$barWidth = $this->_width;
449
if (in_array(self::ELEMENT_PERCENT, $this->_elements)) {
453
if (in_array(self::ELEMENT_ETA, $this->_elements)) {
457
if (in_array(self::ELEMENT_TEXT, $this->_elements)) {
458
$barWidth -= $this->_textWidth;
461
$this->_barWidth = $barWidth - (count($this->_elements) - 1);
466
* Outputs given data to STDOUT.
468
* This split-off is required for unit-testing.
470
* @param string $data
473
protected function _outputData($data)
475
if ($this->_stdout !== null) {
476
fwrite($this->_stdout, $data);
478
fwrite(STDOUT, $data);
b'\\ No newline at end of file'