PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/protected/vendors/AWS/_samples/lib/ProgressBar.php

https://bitbucket.org/ctala/yiiaws
PHP | 410 lines | 189 code | 24 blank | 197 comment | 28 complexity | b7af80295476f281425cfe6095cfcfde MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause
  1. <?php
  2. /* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
  3. // Copyright (c) 2007 Stefan Walk
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. // Authors: Stefan Walk <et@php.net>
  23. /**
  24. * Class to display a progressbar in the console
  25. *
  26. * @package Console_ProgressBar
  27. * @category Console
  28. * @version 0.5.2
  29. * @author Stefan Walk <et@php.net>
  30. * @license MIT License
  31. */
  32. class Console_ProgressBar {
  33. // properties {{{
  34. /**
  35. * Skeleton for use with sprintf
  36. */
  37. var $_skeleton;
  38. /**
  39. * The bar gets filled with this
  40. */
  41. var $_bar;
  42. /**
  43. * The width of the bar
  44. */
  45. var $_blen;
  46. /**
  47. * The total width of the display
  48. */
  49. var $_tlen;
  50. /**
  51. * The position of the counter when the job is `done'
  52. */
  53. var $_target_num;
  54. /**
  55. * Options, like the precision used to display the numbers
  56. */
  57. var $_options = array();
  58. /**
  59. * Length to erase
  60. */
  61. var $_rlen = 0;
  62. /**
  63. * When the progress started
  64. */
  65. var $_start_time = null;
  66. var $_rate_datapoints = array();
  67. /**
  68. * Time when the bar was last drawn
  69. */
  70. var $_last_update_time = 0.0;
  71. // }}}
  72. // constructor() {{{
  73. /**
  74. * Constructor, sets format and size
  75. *
  76. * See the reset() method for documentation.
  77. *
  78. * @param string The format string
  79. * @param string The string filling the progress bar
  80. * @param string The string filling empty space in the bar
  81. * @param int The width of the display
  82. * @param float The target number for the bar
  83. * @param array Options for the progress bar
  84. * @see reset
  85. */
  86. function Console_ProgressBar($formatstring, $bar, $prefill, $width,
  87. $target_num, $options = array())
  88. {
  89. $this->reset($formatstring, $bar, $prefill, $width, $target_num,
  90. $options);
  91. }
  92. // }}}
  93. // {{{ reset($formatstring, $bar, $prefill, $width, $target_num[, $options])
  94. /**
  95. * Re-sets format and size.
  96. *
  97. * <pre>
  98. * The reset method expects 5 to 6 arguments:
  99. * - The first argument is the format string used to display the progress
  100. * bar. It may (and should) contain placeholders that the class will
  101. * replace with information like the progress bar itself, the progress in
  102. * percent, and so on. Current placeholders are:
  103. * %bar% The progress bar
  104. * %current% The current value
  105. * %max% The maximum malue (the "target" value)
  106. * %fraction% The same as %current%/%max%
  107. * %percent% The status in percent
  108. * %elapsed% The elapsed time
  109. * %estimate% An estimate of how long the progress will take
  110. * More placeholders will follow. A format string like:
  111. * "* stuff.tar %fraction% KB [%bar%] %percent%"
  112. * will lead to a bar looking like this:
  113. * "* stuff.tar 391/900 KB [=====>---------] 43.44%"
  114. * - The second argument is the string that is going to fill the progress
  115. * bar. In the above example, the string "=>" was used. If the string you
  116. * pass is too short (like "=>" in this example), the leftmost character
  117. * is used to pad it to the needed size. If the string you pass is too long,
  118. * excessive characters are stripped from the left.
  119. * - The third argument is the string that fills the "empty" space in the
  120. * progress bar. In the above example, that would be "-". If the string
  121. * you pass is too short (like "-" in this example), the rightmost
  122. * character is used to pad it to the needed size. If the string you pass
  123. * is too short, excessive characters are stripped from the right.
  124. * - The fourth argument specifies the width of the display. If the options
  125. * are left untouched, it will tell how many characters the display should
  126. * use in total. If the "absolute_width" option is set to false, it tells
  127. * how many characters the actual bar (that replaces the %bar%
  128. * placeholder) should use.
  129. * - The fifth argument is the target number of the progress bar. For
  130. * example, if you wanted to display a progress bar for a download of a
  131. * file that is 115 KB big, you would pass 115 here.
  132. * - The sixth argument optional. If passed, it should contain an array of
  133. * options. For example, passing array('absolute_width' => false) would
  134. * set the absolute_width option to false. Current options are:
  135. *
  136. * option | def. | meaning
  137. * --------------------------------------------------------------------
  138. * percent_precision | 2 | Number of decimal places to show when
  139. * | | displaying the percentage.
  140. * fraction_precision | 0 | Number of decimal places to show when
  141. * | | displaying the current or target
  142. * | | number.
  143. * percent_pad | ' ' | Character to use when padding the
  144. * | | percentage to a fixed size. Senseful
  145. * | | values are ' ' and '0', but any are
  146. * | | possible.
  147. * fraction_pad | ' ' | Character to use when padding max and
  148. * | | current number to a fixed size.
  149. * | | Senseful values are ' ' and '0', but
  150. * | | any are possible.
  151. * width_absolute | true | If the width passed as an argument
  152. * | | should mean the total size (true) or
  153. * | | the width of the bar alone.
  154. * ansi_terminal | false | If this option is true, a better
  155. * | | (faster) method for erasing the bar is
  156. * | | used. CAUTION - this is known to cause
  157. * | | problems with some terminal emulators,
  158. * | | for example Eterm.
  159. * ansi_clear | false | If the bar should be cleared everytime
  160. * num_datapoints | 5 | How many datapoints to use to create
  161. * | | the estimated remaining time
  162. * min_draw_interval | 0.0 | If the last call to update() was less
  163. * | | than this amount of seconds ago,
  164. * | | don't update.
  165. * </pre>
  166. *
  167. * @param string The format string
  168. * @param string The string filling the progress bar
  169. * @param string The string filling empty space in the bar
  170. * @param int The width of the display
  171. * @param float The target number for the bar
  172. * @param array Options for the progress bar
  173. * @return bool
  174. */
  175. function reset($formatstring, $bar, $prefill, $width, $target_num,
  176. $options = array())
  177. {
  178. if ($target_num == 0) {
  179. trigger_error("PEAR::Console_ProgressBar: Using a target number equal to 0 is invalid, setting to 1 instead");
  180. $this->_target_num = 1;
  181. } else {
  182. $this->_target_num = $target_num;
  183. }
  184. $default_options = array(
  185. 'percent_precision' => 2,
  186. 'fraction_precision' => 0,
  187. 'percent_pad' => ' ',
  188. 'fraction_pad' => ' ',
  189. 'width_absolute' => true,
  190. 'ansi_terminal' => false,
  191. 'ansi_clear' => false,
  192. 'num_datapoints' => 5,
  193. 'min_draw_interval' => 0.0,
  194. );
  195. $intopts = array();
  196. foreach ($default_options as $key => $value) {
  197. if (!isset($options[$key])) {
  198. $intopts[$key] = $value;
  199. } else {
  200. settype($options[$key], gettype($value));
  201. $intopts[$key] = $options[$key];
  202. }
  203. }
  204. $this->_options = $options = $intopts;
  205. // placeholder
  206. $cur = '%2$\''.$options['fraction_pad']{0}.strlen((int)$target_num).'.'
  207. .$options['fraction_precision'].'f';
  208. $max = $cur; $max{1} = 3;
  209. // pre php-4.3.7 %3.2f meant 3 characters before . and two after
  210. // php-4.3.7 and later it means 3 characters for the whole number
  211. if (version_compare(PHP_VERSION, '4.3.7', 'ge')) {
  212. $padding = 4 + $options['percent_precision'];
  213. } else {
  214. $padding = 3;
  215. }
  216. $perc = '%4$\''.$options['percent_pad']{0}.$padding.'.'
  217. .$options['percent_precision'].'f';
  218. $transitions = array(
  219. '%%' => '%%',
  220. '%fraction%' => $cur.'/'.$max,
  221. '%current%' => $cur,
  222. '%max%' => $max,
  223. '%percent%' => $perc.'%%',
  224. '%bar%' => '%1$s',
  225. '%elapsed%' => '%5$s',
  226. '%estimate%' => '%6$s',
  227. );
  228. $this->_skeleton = strtr($formatstring, $transitions);
  229. $slen = strlen(sprintf($this->_skeleton, '', 0, 0, 0, '00:00:00','00:00:00'));
  230. if ($options['width_absolute']) {
  231. $blen = $width - $slen;
  232. $tlen = $width;
  233. } else {
  234. $tlen = $width + $slen;
  235. $blen = $width;
  236. }
  237. $lbar = str_pad($bar, $blen, $bar{0}, STR_PAD_LEFT);
  238. $rbar = str_pad($prefill, $blen, substr($prefill, -1, 1));
  239. $this->_bar = substr($lbar,-$blen).substr($rbar,0,$blen);
  240. $this->_blen = $blen;
  241. $this->_tlen = $tlen;
  242. $this->_first = true;
  243. return true;
  244. }
  245. // }}}
  246. // {{{ update($current)
  247. /**
  248. * Updates the bar with new progress information
  249. *
  250. * @param int current position of the progress counter
  251. * @return bool
  252. */
  253. function update($current)
  254. {
  255. $time = $this->_fetchTime();
  256. $this->_addDatapoint($current, $time);
  257. if ($this->_first) {
  258. if ($this->_options['ansi_terminal']) {
  259. echo "\x1b[s"; // save cursor position
  260. }
  261. $this->_first = false;
  262. $this->_start_time = $this->_fetchTime();
  263. $this->display($current);
  264. return;
  265. }
  266. if ($time - $this->_last_update_time <
  267. $this->_options['min_draw_interval'] and $current != $this->_target_num) {
  268. return;
  269. }
  270. $this->erase();
  271. $this->display($current);
  272. $this->_last_update_time = $time;
  273. }
  274. // }}}
  275. // {{{ display($current)
  276. /**
  277. * Prints the bar. Usually, you don't need this method, just use update()
  278. * which handles erasing the previously printed bar also. If you use a
  279. * custom function (for whatever reason) to erase the bar, use this method.
  280. *
  281. * @param int current position of the progress counter
  282. * @return bool
  283. */
  284. function display($current)
  285. {
  286. $percent = $current / $this->_target_num;
  287. $filled = round($percent * $this->_blen);
  288. $visbar = substr($this->_bar, $this->_blen - $filled, $this->_blen);
  289. $elapsed = $this->_formatSeconds(
  290. $this->_fetchTime() - $this->_start_time
  291. );
  292. $estimate = $this->_formatSeconds($this->_generateEstimate());
  293. $this->_rlen = printf($this->_skeleton,
  294. $visbar, $current, $this->_target_num, $percent * 100, $elapsed,
  295. $estimate
  296. );
  297. // fix for php-versions where printf doesn't return anything
  298. if (is_null($this->_rlen)) {
  299. $this->_rlen = $this->_tlen;
  300. // fix for php versions between 4.3.7 and 5.x.y(?)
  301. } elseif ($this->_rlen < $this->_tlen) {
  302. echo str_repeat(' ', $this->_tlen - $this->_rlen);
  303. $this->_rlen = $this->_tlen;
  304. }
  305. return true;
  306. }
  307. // }}}
  308. // {{{ erase($clear = false)
  309. /**
  310. * Erases a previously printed bar.
  311. *
  312. * @param bool if the bar should be cleared in addition to resetting the
  313. * cursor position
  314. * @return bool
  315. */
  316. function erase($clear = false)
  317. {
  318. if ($this->_options['ansi_terminal'] and !$clear) {
  319. if ($this->_options['ansi_clear']) {
  320. echo "\x1b[2K\x1b[u"; // restore cursor position
  321. } else {
  322. echo "\x1b[u"; // restore cursor position
  323. }
  324. } elseif (!$clear) {
  325. echo str_repeat(chr(0x08), $this->_rlen);
  326. } else {
  327. echo str_repeat(chr(0x08), $this->_rlen),
  328. str_repeat(chr(0x20), $this->_rlen),
  329. str_repeat(chr(0x08), $this->_rlen);
  330. }
  331. }
  332. // }}}
  333. // {{{ format_seconds()
  334. /**
  335. * Returns a string containing the formatted number of seconds
  336. *
  337. * @param float The number of seconds
  338. * @return string
  339. */
  340. function _formatSeconds($seconds)
  341. {
  342. $hou = floor($seconds/3600);
  343. $min = floor(($seconds - $hou * 3600) / 60);
  344. $sec = $seconds - $hou * 3600 - $min * 60;
  345. if ($hou == 0) {
  346. if (version_compare(PHP_VERSION, '4.3.7', 'ge')) {
  347. $format = '%2$02d:%3$05.2f';
  348. } else {
  349. $format = '%2$02d:%3$02.2f';
  350. }
  351. } elseif ($hou < 100) {
  352. $format = '%02d:%02d:%02d';
  353. } else {
  354. $format = '%05d:%02d';
  355. }
  356. return sprintf($format, $hou, $min, $sec);
  357. }
  358. // }}}
  359. function _fetchTime() {
  360. if (!function_exists('microtime')) {
  361. return time();
  362. }
  363. if (version_compare(PHP_VERSION, '5.0.0', 'ge')) {
  364. return microtime(true);
  365. }
  366. return array_sum(explode(' ', microtime()));
  367. }
  368. function _addDatapoint($val, $time) {
  369. if (count($this->_rate_datapoints)
  370. == $this->_options['num_datapoints']) {
  371. array_shift($this->_rate_datapoints);
  372. }
  373. $this->_rate_datapoints[] = array(
  374. 'time' => $time,
  375. 'value' => $val,
  376. );
  377. }
  378. function _generateEstimate() {
  379. if (count($this->_rate_datapoints) < 2) {
  380. return 0.0;
  381. }
  382. $first = $this->_rate_datapoints[0];
  383. $last = end($this->_rate_datapoints);
  384. return ($this->_target_num - $last['value'])/($last['value'] - $first['value']) * ($last['time'] - $first['time']);
  385. }
  386. }