This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * This class creates and maintains progress bars to be printed to the console. |
||
4 | * This file is a replica of the ezComponents console progress bar class (@link http://ezcomponents.org/docs/api/latest/ConsoleTools/ezcConsoleProgressbar.html) |
||
5 | * allows a developer to just use the console progress bar features without the rest of the classes saving all the extra files |
||
6 | * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved. |
||
7 | * @license http://ez.no/licenses/new_bsd New BSD License |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * Creating and maintaining progress-bars to be printed to the console. |
||
12 | * <code> |
||
13 | * // Create progress bar itself |
||
14 | * $progress = new ConsoleProgressBar(100); |
||
15 | * // Perform actions |
||
16 | * $i = 0; |
||
17 | * while ( $i++ < 100 ) |
||
18 | * { |
||
19 | * // Do whatever you want to indicate progress for |
||
20 | * // Advance the progressbar by one step |
||
21 | * $progress->advance(); |
||
22 | * } |
||
23 | * // Finish progress bar and jump to next line. |
||
24 | * $progress->finish(); |
||
25 | * </code> |
||
26 | */ |
||
27 | class ConsoleProgressBar |
||
28 | { |
||
29 | |||
30 | /** |
||
31 | * The current step the progress bar should show. |
||
32 | * @var int |
||
33 | */ |
||
34 | protected $currentStep = 0; |
||
35 | |||
36 | /** |
||
37 | * The maximum number of steps to go. |
||
38 | * Calculated once from the settings. |
||
39 | * @var int |
||
40 | */ |
||
41 | protected $numSteps = 0; |
||
42 | |||
43 | /** |
||
44 | * Indicates if the starting point for the bar has been stored. |
||
45 | * Per default this is false to indicate that no start position has been |
||
46 | * stored, yet. |
||
47 | * @var bool |
||
48 | */ |
||
49 | protected $started = false; |
||
50 | |||
51 | /** |
||
52 | * Whether a position has been stored before, using the storePos() method. |
||
53 | * @var bool |
||
54 | */ |
||
55 | protected $positionStored = false; |
||
56 | |||
57 | /** |
||
58 | * Container to hold the options |
||
59 | * @var array(string=>mixed) |
||
60 | */ |
||
61 | protected $options = array( |
||
62 | 'barChar' => "=", |
||
63 | 'emptyChar' => "-", |
||
64 | 'formatString' => "%act% / %max% [%bar%] %fraction%% %memory%", |
||
65 | 'fractionFormat' => "%01.2f", |
||
66 | 'progressChar' => ">", |
||
67 | 'redrawFrequency' => 1, |
||
68 | 'step' => 1, |
||
69 | 'width' => 100, |
||
70 | 'actFormat' => '%.0f', |
||
71 | 'maxFormat' => '%.0f', |
||
72 | 'max' => 100, |
||
73 | ); |
||
74 | |||
75 | /** |
||
76 | * Storage for actual values to be replaced in the format string. |
||
77 | * Actual values are stored here and will be inserted into the bar |
||
78 | * before printing it. |
||
79 | * @var array(string=>string) |
||
80 | */ |
||
81 | protected $valueMap = array( |
||
82 | 'bar' => '', |
||
83 | 'fraction' => '', |
||
84 | 'act' => '', |
||
85 | 'max' => '', |
||
86 | 'memory' => '' |
||
87 | ); |
||
88 | |||
89 | /** |
||
90 | * Stores the bar utilization. |
||
91 | * This array saves how much space a specific part of the bar utilizes to not |
||
92 | * recalculate those on every step. |
||
93 | * @var array(string=>int) |
||
94 | */ |
||
95 | protected $measures = array( |
||
96 | 'barSpace' => 0, |
||
97 | 'fractionSpace' => 0, |
||
98 | 'actSpace' => 0, |
||
99 | 'maxSpace' => 0, |
||
100 | 'fixedCharSpace' => 0, |
||
101 | ); |
||
102 | |||
103 | /** |
||
104 | * Creates a new progress bar. |
||
105 | * |
||
106 | * @param int $max Maximum value, where progressbar |
||
107 | * reaches 100%. |
||
108 | * @param array(string=>string) $options Options |
||
0 ignored issues
–
show
|
|||
109 | */ |
||
110 | public function __construct($max = null, $options = array()) |
||
111 | { |
||
112 | if( $max ) |
||
0 ignored issues
–
show
The expression
$max of type integer|null is loosely compared to true ; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
113 | { |
||
114 | $this->options['max'] = $max; |
||
115 | } |
||
116 | |||
117 | if( $options && count($options) ) |
||
0 ignored issues
–
show
The expression
$options of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
118 | { |
||
119 | $this->options = array_merge($this->options, $options); |
||
120 | } |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Set new options. |
||
125 | * This method allows you to change the options of progressbar. |
||
126 | * |
||
127 | * @param $key either an array of key=>value pairs or a string of the option |
||
128 | * @param $value only needed if the key is a string |
||
129 | */ |
||
130 | public function setOptions($key, $value = null) |
||
131 | { |
||
132 | if( is_array($key) ) |
||
133 | { |
||
134 | $this->options = array_merge($this->options, $key); |
||
135 | } |
||
136 | else |
||
137 | { |
||
138 | $this->__set($key, $value); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Returns the current options. |
||
144 | * Returns the options currently set for this progressbar. |
||
145 | * @return The current options. |
||
146 | */ |
||
147 | public function getOptions() |
||
148 | { |
||
149 | return $this->options; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Property read access. |
||
154 | * |
||
155 | * @param string $key Name of the property. |
||
156 | * |
||
157 | * @return mixed Value of the property or null. |
||
158 | */ |
||
159 | public function __get($key) |
||
160 | { |
||
161 | switch($key) |
||
162 | { |
||
163 | case 'options': |
||
164 | return $this->options; |
||
165 | case 'step': |
||
166 | // Step is now an option |
||
167 | return $this->options['step']; |
||
168 | case 'max': |
||
169 | return $this->options['max']; |
||
170 | default: |
||
171 | if( isset($this->options[$key]) ) |
||
172 | { |
||
173 | return $this->options[$key]; |
||
174 | } |
||
175 | break; |
||
176 | } |
||
177 | throw new Exception(sprintf("%s does not exists", $key)); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Property write access. |
||
182 | * |
||
183 | * @param string $key Name of the property. |
||
184 | * @param mixed $val The value for the property. |
||
185 | * |
||
186 | * @throws Exception |
||
187 | * If a desired property could not be found. |
||
188 | */ |
||
189 | public function __set($key, $val) |
||
190 | { |
||
191 | switch($key) |
||
192 | { |
||
193 | case 'options': |
||
194 | $this->setOptions($val); |
||
195 | break; |
||
196 | View Code Duplication | case 'max': |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
197 | if( (!is_int($val) && !is_float($val)) || $val < 0 ) |
||
198 | { |
||
199 | throw new Exception(sprintf("%s must be a number greater then 0. Value set: %s", $key, $val)); |
||
200 | } |
||
201 | break; |
||
202 | View Code Duplication | case 'step': |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
203 | if( (!is_int($val) && !is_float($val)) || $val < 0 ) |
||
204 | { |
||
205 | throw new Exception(sprintf("%s must be a number greater then 0. Value set: %s", $key, $val)); |
||
206 | } |
||
207 | // Step is now an option. |
||
208 | $this->options['step'] = $val; |
||
209 | |||
210 | return; |
||
211 | default: |
||
212 | throw new Exception(sprintf("%s does not exists", $key)); |
||
213 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
214 | } |
||
215 | // Changes settings or options, need for recalculating measures |
||
216 | $this->started = false; |
||
217 | $this->options[$key] = $val; |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * Property isset access. |
||
222 | * |
||
223 | * @param string $key Name of the property. |
||
224 | * |
||
225 | * @return bool True is the property is set, otherwise false. |
||
226 | */ |
||
227 | public function __isset($key) |
||
228 | { |
||
229 | switch($key) |
||
230 | { |
||
231 | case 'options': |
||
232 | case 'max': |
||
233 | case 'step': |
||
234 | return true; |
||
235 | } |
||
236 | |||
237 | return false; |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Start the progress bar |
||
242 | * Starts the progress bar and sticks it to the current line. |
||
243 | * No output will be done yet. |
||
244 | * to print the bar. |
||
245 | * @return void |
||
246 | */ |
||
247 | public function start() |
||
248 | { |
||
249 | $this->calculateMeasures(); |
||
250 | $this->storePos(); |
||
251 | $this->started = true; |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * Advance the progress bar. |
||
256 | * Advances the progress bar by $step steps. Redraws the bar by default, |
||
257 | * using the output method. |
||
258 | * |
||
259 | * @param bool $redraw Whether to redraw the bar immediately. |
||
260 | * @param int $step How many steps to advance. |
||
261 | * |
||
262 | * @return void |
||
263 | */ |
||
264 | public function advance($redraw = true, $step = 1) |
||
265 | { |
||
266 | $this->currentStep += $step; |
||
267 | if( $redraw === true && $this->currentStep % $this->options['redrawFrequency'] === 0 ) |
||
268 | { |
||
269 | $this->output(); |
||
270 | } |
||
271 | } |
||
272 | |||
273 | public function setValueMap($key, $value) |
||
274 | { |
||
275 | $this->valueMap[$key] = $value; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Finish the progress bar. |
||
280 | * Finishes the bar (jump to 100% if not happened yet,...) and jumps |
||
281 | * to the next line to allow new output. Also resets the values of the |
||
282 | * @return void |
||
283 | */ |
||
284 | public function finish() |
||
285 | { |
||
286 | $this->currentStep = $this->numSteps; |
||
287 | $this->output(); |
||
288 | echo PHP_EOL; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Draw the progress bar. |
||
293 | * Prints the progress-bar to the screen. If start() has not been called |
||
294 | * yet, the current line is used for start |
||
295 | * @return void |
||
296 | */ |
||
297 | protected function output() |
||
298 | { |
||
299 | if( $this->started === false ) |
||
300 | { |
||
301 | $this->start(); |
||
302 | } |
||
303 | |||
304 | $this->restorePos(); |
||
305 | if( $this->isWindows() ) |
||
306 | { |
||
307 | echo str_repeat("\x8", $this->options['width']); |
||
308 | } |
||
309 | |||
310 | $this->generateValues(); |
||
311 | echo $this->insertValues(); |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * Stores the current cursor position. |
||
316 | * Saves the current cursor position to return to it using |
||
317 | * restorePos. Multiple calls |
||
318 | * to this method will override each other. Only the last |
||
319 | * position is saved. |
||
320 | * @return void |
||
321 | */ |
||
322 | protected function storePos() |
||
323 | { |
||
324 | if( !$this->isWindows() ) |
||
325 | { |
||
326 | echo "\0337"; |
||
327 | $this->positionStored = true; |
||
328 | } |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * Restores a cursor position. |
||
333 | * Restores the cursor position last saved using storePos. |
||
334 | * @throws Exception |
||
335 | * If no position is saved. |
||
336 | * @return void |
||
337 | */ |
||
338 | |||
339 | protected function restorePos() |
||
340 | { |
||
341 | if( !$this->isWindows() ) |
||
342 | { |
||
343 | if( $this->positionStored === false ) |
||
344 | { |
||
345 | throw new Exception("Progress Bar position was not stored."); |
||
346 | } |
||
347 | echo "\0338"; |
||
348 | } |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Generate all values to be replaced in the format string. |
||
353 | * @return void |
||
354 | */ |
||
355 | protected function generateValues() |
||
356 | { |
||
357 | // Bar |
||
358 | $barFilledSpace = ceil($this->measures['barSpace'] / $this->numSteps * $this->currentStep); |
||
359 | // Sanitize value if it gets to large by rounding |
||
360 | $barFilledSpace = $barFilledSpace > $this->measures['barSpace'] ? $this->measures['barSpace'] : $barFilledSpace; |
||
361 | $bar = $this->strPad( |
||
362 | $this->strPad( |
||
363 | $this->options['progressChar'], |
||
364 | $barFilledSpace, |
||
365 | $this->options['barChar'], |
||
366 | STR_PAD_LEFT |
||
367 | ), |
||
368 | $this->measures['barSpace'], |
||
369 | $this->options['emptyChar'], |
||
370 | STR_PAD_RIGHT |
||
371 | ); |
||
372 | $this->valueMap['bar'] = $bar; |
||
373 | |||
374 | // Fraction |
||
375 | $fractionVal = sprintf( |
||
376 | $this->options['fractionFormat'], |
||
377 | ($fractionVal = ($this->options['step'] * $this->currentStep) / $this->options['max'] * 100) > 100 ? 100 : $fractionVal |
||
378 | ); |
||
379 | $this->valueMap['fraction'] = $this->strPad( |
||
380 | $fractionVal, |
||
381 | iconv_strlen(sprintf($this->options['fractionFormat'], 100), 'UTF-8'), |
||
382 | ' ', |
||
383 | STR_PAD_LEFT |
||
384 | ); |
||
385 | |||
386 | // Act / max |
||
387 | $actVal = sprintf( |
||
388 | $this->options['actFormat'], |
||
389 | ($actVal = $this->currentStep * $this->options['step']) > $this->options['max'] ? $this->options['max'] : $actVal |
||
390 | ); |
||
391 | $this->valueMap['act'] = $this->strPad( |
||
392 | $actVal, |
||
393 | iconv_strlen(sprintf($this->options['actFormat'], $this->options['max']), 'UTF-8'), |
||
394 | ' ', |
||
395 | STR_PAD_LEFT |
||
396 | ); |
||
397 | $this->valueMap['max'] = sprintf($this->options['maxFormat'], $this->options['max']); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Insert values into bar format string. |
||
402 | * @return void |
||
403 | */ |
||
404 | protected function insertValues() |
||
405 | { |
||
406 | $bar = $this->options['formatString']; |
||
407 | foreach($this->valueMap as $name => $val) |
||
408 | { |
||
409 | $bar = str_replace("%{$name}%", $val, $bar); |
||
410 | } |
||
411 | |||
412 | return $bar; |
||
413 | } |
||
414 | |||
415 | /** |
||
416 | * Calculate several measures necessary to generate a bar. |
||
417 | * @return void |
||
418 | */ |
||
419 | protected function calculateMeasures() |
||
420 | { |
||
421 | // Calc number of steps bar goes through |
||
422 | $this->numSteps = ( int )round($this->options['max'] / $this->options['step']); |
||
423 | // Calculate measures |
||
424 | $this->measures['fixedCharSpace'] = iconv_strlen($this->stripEscapeSequences($this->insertValues()), 'UTF-8'); |
||
425 | View Code Duplication | if( iconv_strpos($this->options['formatString'], '%max%', 0, 'UTF-8') !== false ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
426 | { |
||
427 | $this->measures['maxSpace'] = iconv_strlen(sprintf($this->options['maxFormat'], $this->options['max']), 'UTF-8'); |
||
428 | } |
||
429 | View Code Duplication | if( iconv_strpos($this->options['formatString'], '%act%', 0, 'UTF-8') !== false ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
430 | { |
||
431 | $this->measures['actSpace'] = iconv_strlen(sprintf($this->options['actFormat'], $this->options['max']), 'UTF-8'); |
||
432 | } |
||
433 | if( iconv_strpos($this->options['formatString'], '%fraction%', 0, 'UTF-8') !== false ) |
||
434 | { |
||
435 | $this->measures['fractionSpace'] = iconv_strlen(sprintf($this->options['fractionFormat'], 100), 'UTF-8'); |
||
436 | } |
||
437 | $this->measures['barSpace'] = $this->options['width'] - array_sum($this->measures); |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Strip all escape sequences from a string to measure it's size correctly. |
||
442 | * |
||
443 | * @param mixed $str |
||
444 | * |
||
445 | * @return void |
||
446 | */ |
||
447 | protected function stripEscapeSequences($str) |
||
448 | { |
||
449 | return preg_replace('/\033\[[0-9a-f;]*m/i', '', $str); |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Check if we currently running under windows |
||
454 | * @return bool |
||
455 | */ |
||
456 | protected function isWindows() |
||
457 | { |
||
458 | return stripos(PHP_OS, 'windows') !== false; |
||
459 | } |
||
460 | |||
461 | /** |
||
462 | * Binary safe str_pad() replacement. |
||
463 | * This method is a multi-byte encoding safe replacement for the PHP |
||
464 | * function str_pad(). It mimics exactly the behavior of str_pad(), but |
||
465 | * uses iconv_* functions with UTF-8 encoding. The parameters received by |
||
466 | * this method equal the parameters of {@link http://php.net/str_pad |
||
467 | * str_pad()}. Note: Make sure to hand only UTF-8 encoded content to this |
||
468 | * method. |
||
469 | * |
||
470 | * @param string $input |
||
471 | * @param int $padLength |
||
472 | * @param string $padString |
||
473 | * @param int $padType |
||
474 | * |
||
475 | * @return string |
||
476 | */ |
||
477 | protected function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT) |
||
478 | { |
||
479 | $input = (string)$input; |
||
480 | |||
481 | $strLen = iconv_strlen($input, 'UTF-8'); |
||
482 | $padStrLen = iconv_strlen($padString, 'UTF-8'); |
||
483 | |||
484 | if( $strLen >= $padLength ) |
||
485 | { |
||
486 | return $input; |
||
487 | } |
||
488 | |||
489 | if( $padType === STR_PAD_BOTH ) |
||
490 | { |
||
491 | return $this->strPad( |
||
492 | $this->strPad( |
||
493 | $input, |
||
494 | $strLen + ceil(($padLength - $strLen) / 2), |
||
495 | $padString |
||
496 | ), |
||
497 | $padLength, |
||
498 | $padString, |
||
499 | STR_PAD_LEFT |
||
500 | ); |
||
501 | } |
||
502 | |||
503 | $fullStrRepeats = (int)(($padLength - $strLen) / $padStrLen); |
||
504 | $partlyPad = iconv_substr( |
||
505 | $padString, |
||
506 | 0, |
||
507 | (($padLength - $strLen) % $padStrLen) |
||
508 | ); |
||
509 | |||
510 | $padding = str_repeat($padString, $fullStrRepeats).$partlyPad; |
||
511 | |||
512 | switch($padType) |
||
513 | { |
||
514 | case STR_PAD_LEFT: |
||
515 | return $padding.$input; |
||
516 | case STR_PAD_RIGHT: |
||
517 | default: |
||
518 | return $input.$padding; |
||
519 | } |
||
520 | } |
||
521 | } |
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.