Completed
Push — master ( 64c9c6...973681 )
by Michael
02:15
created

System   D

Complexity

Total Complexity 118

Size/Duplication

Total Lines 574
Duplicated Lines 5.05 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 29
loc 574
rs 4.8717
c 0
b 0
f 0
wmc 118
lcom 1
cbo 1

12 Methods

Rating   Name   Duplication   Size   Complexity  
B _parseArgs() 0 33 5
A raiseError() 0 9 2
C _dirToStruct() 6 35 11
B _multipleToStruct() 8 17 5
C rm() 0 37 12
C mkDir() 0 55 19
C cat() 0 51 12
D mktemp() 0 45 12
A _removeTmpFiles() 0 9 2
C tmpdir() 15 24 12
C which() 0 41 11
C find() 0 64 15

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like System often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use System, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 58 and the first side effect is on line 19.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * File/Directory manipulation
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * @category   pear
8
 * @package    System
9
 * @author     Tomas V.V.Cox <[email protected]>
10
 * @copyright  1997-2009 The Authors
11
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
12
 * @link       http://pear.php.net/package/PEAR
13
 * @since      File available since Release 0.1
14
 */
15
16
/**
17
 * base class
18
 */
19
require_once __DIR__ . '/PEAR.php';
20
require_once __DIR__ . '/Console/Getopt.php';
21
22
$GLOBALS['_System_temp_files'] = array();
23
24
/**
25
 * System offers cross platform compatible system functions
26
 *
27
 * Static functions for different operations. Should work under
28
 * Unix and Windows. The names and usage has been taken from its respectively
29
 * GNU commands. The functions will return (bool) false on error and will
30
 * trigger the error with the PHP trigger_error() function (you can silence
31
 * the error by prefixing a '@' sign after the function call, but this
32
 * is not recommended practice.  Instead use an error handler with
33
 * {@link set_error_handler()}).
34
 *
35
 * Documentation on this class you can find in:
36
 * http://pear.php.net/manual/
37
 *
38
 * Example usage:
39
 * if (!@System::rm('-r file1 dir1')) {
40
 *    print "could not delete file1 or dir1";
41
 * }
42
 *
43
 * In case you need to to pass file names with spaces,
44
 * pass the params as an array:
45
 *
46
 * System::rm(array('-r', $file1, $dir1));
47
 *
48
 * @category   pear
49
 * @package    System
50
 * @author     Tomas V.V. Cox <[email protected]>
51
 * @copyright  1997-2006 The PHP Group
52
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
53
 * @version    Release: 1.10.3
54
 * @link       http://pear.php.net/package/PEAR
55
 * @since      Class available since Release 0.1
56
 * @static
57
 */
58
class System
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
59
{
60
    /**
61
     * returns the commandline arguments of a function
62
     *
63
     * @param    string $argv          the commandline
64
     * @param    string $short_options the allowed option short-tags
65
     * @param    string $long_options  the allowed option long-tags
0 ignored issues
show
Documentation introduced by
Should the type for parameter $long_options not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
66
     * @return   array   the given options and there values
67
     */
68
    public static function _parseArgs($argv, $short_options, $long_options = null)
69
    {
70
        if (!is_array($argv) && $argv !== null) {
71
            /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
72
            // Quote all items that are a short option
73
            $av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((?<!\\\\)((,\s*)|((?<!,)\s+))?)/i', $argv, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
74
            $offset = 0;
75
            foreach ($av as $a) {
76
                $b = trim($a[0]);
77
                if ($b{0} == '"' || $b{0} == "'") {
78
                    continue;
79
                }
80
81
                $escape = escapeshellarg($b);
82
                $pos = $a[1] + $offset;
83
                $argv = substr_replace($argv, $escape, $pos, strlen($b));
84
                $offset += 2;
85
            }
86
            */
87
88
            // Find all items, quoted or otherwise
89
            preg_match_all("/(?:[\"'])(.*?)(?:['\"])|([^\s]+)/", $argv, $av);
90
            $argv = $av[1];
91
            foreach ($av[2] as $k => $a) {
92
                if (empty($a)) {
93
                    continue;
94
                }
95
                $argv[$k] = trim($a);
96
            }
97
        }
98
99
        return Console_Getopt::getopt2($argv, $short_options, $long_options);
100
    }
101
102
    /**
103
     * Output errors with PHP trigger_error(). You can silence the errors
104
     * with prefixing a "@" sign to the function call: @System::mkdir(..);
105
     *
106
     * @param mixed $error a PEAR error or a string with the error message
107
     * @return bool false
108
     */
109
    protected static function raiseError($error)
110
    {
111
        if (PEAR::isError($error)) {
112
            $error = $error->getMessage();
113
        }
114
        trigger_error($error, E_USER_WARNING);
115
116
        return false;
117
    }
118
119
    /**
120
     * Creates a nested array representing the structure of a directory
121
     *
122
     * System::_dirToStruct('dir1', 0) =>
123
     *   Array
124
     *    (
125
     *    [dirs] => Array
126
     *        (
127
     *            [0] => dir1
128
     *        )
129
     *
130
     *    [files] => Array
131
     *        (
132
     *            [0] => dir1/file2
133
     *            [1] => dir1/file3
134
     *        )
135
     *    )
136
     * @param    string  $sPath   Name of the directory
137
     * @param    integer $maxinst max. deep of the lookup
138
     * @param    integer $aktinst starting deep of the lookup
139
     * @param    bool    $silent  if true, do not emit errors.
140
     * @return   array   the structure of the dir
141
     */
142
    protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
143
    {
144
        $struct = array('dirs' => array(), 'files' => array());
145
        if (($dir = @opendir($sPath)) === false) {
146
            if (!$silent) {
147
                System::raiseError("Could not open dir $sPath");
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
148
            }
149
150
            return $struct; // XXX could not open error
151
        }
152
153
        $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
154
        $list             = array();
155
        while (false !== ($file = readdir($dir))) {
156
            if ($file != '.' && $file != '..') {
157
                $list[] = $file;
158
            }
159
        }
160
161
        closedir($dir);
162
        natsort($list);
163
        if ($aktinst < $maxinst || $maxinst == 0) {
164
            foreach ($list as $val) {
165
                $path = $sPath . DIRECTORY_SEPARATOR . $val;
166 View Code Duplication
                if (is_dir($path) && !is_link($path)) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
167
                    $tmp    = System::_dirToStruct($path, $maxinst, $aktinst + 1, $silent);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
168
                    $struct = array_merge_recursive($struct, $tmp);
169
                } else {
170
                    $struct['files'][] = $path;
171
                }
172
            }
173
        }
174
175
        return $struct;
176
    }
177
178
    /**
179
     * Creates a nested array representing the structure of a directory and files
180
     *
181
     * @param    array $files Array listing files and dirs
182
     * @return   array
183
     * @static
184
     * @see System::_dirToStruct()
185
     */
186
    protected static function _multipleToStruct($files)
187
    {
188
        $struct = array('dirs' => array(), 'files' => array());
189
        settype($files, 'array');
190
        foreach ($files as $file) {
191 View Code Duplication
            if (is_dir($file) && !is_link($file)) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
192
                $tmp    = System::_dirToStruct($file, 0);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
193
                $struct = array_merge_recursive($tmp, $struct);
194
            } else {
195
                if (!in_array($file, $struct['files'])) {
196
                    $struct['files'][] = $file;
197
                }
198
            }
199
        }
200
201
        return $struct;
202
    }
203
204
    /**
205
     * The rm command for removing files.
206
     * Supports multiple files and dirs and also recursive deletes
207
     *
208
     * @param    string $args the arguments for rm
209
     * @return   mixed   PEAR_Error or true for success
210
     * @static
211
     * @access   public
212
     */
213
    public static function rm($args)
214
    {
215
        $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
216
        if (PEAR::isError($opts)) {
217
            return System::raiseError($opts);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
218
        }
219
        foreach ($opts[0] as $opt) {
220
            if ($opt[0] == 'r') {
221
                $do_recursive = true;
222
            }
223
        }
224
        $ret = true;
225
        if (isset($do_recursive)) {
226
            $struct = System::_multipleToStruct($opts[1]);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
227
            foreach ($struct['files'] as $file) {
228
                if (!@unlink($file)) {
229
                    $ret = false;
230
                }
231
            }
232
233
            rsort($struct['dirs']);
234
            foreach ($struct['dirs'] as $dir) {
235
                if (!@rmdir($dir)) {
236
                    $ret = false;
237
                }
238
            }
239
        } else {
240
            foreach ($opts[1] as $file) {
241
                $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
242
                if (!@$delete($file)) {
243
                    $ret = false;
244
                }
245
            }
246
        }
247
248
        return $ret;
249
    }
250
251
    /**
252
     * Make directories.
253
     *
254
     * The -p option will create parent directories
255
     * @param    string $args the name of the director(y|ies) to create
256
     * @return   bool    True for success
257
     */
258
    public static function mkDir($args)
259
    {
260
        $opts = System::_parseArgs($args, 'pm:');
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
261
        if (PEAR::isError($opts)) {
262
            return System::raiseError($opts);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
263
        }
264
265
        $mode = 0777; // default mode
266
        foreach ($opts[0] as $opt) {
267
            if ($opt[0] == 'p') {
268
                $create_parents = true;
269
            } elseif ($opt[0] == 'm') {
270
                // if the mode is clearly an octal number (starts with 0)
271
                // convert it to decimal
272
                if (strlen($opt[1]) && $opt[1]{0} == '0') {
273
                    $opt[1] = octdec($opt[1]);
274
                } else {
275
                    // convert to int
276
                    $opt[1] += 0;
277
                }
278
                $mode = $opt[1];
279
            }
280
        }
281
282
        $ret = true;
283
        if (isset($create_parents)) {
284
            foreach ($opts[1] as $dir) {
285
                $dirstack = array();
286
                while ((!file_exists($dir) || !is_dir($dir))
287
                       && $dir != DIRECTORY_SEPARATOR) {
288
                    array_unshift($dirstack, $dir);
289
                    $dir = dirname($dir);
290
                }
291
292
                while ($newdir = array_shift($dirstack)) {
293
                    if (!is_writeable(dirname($newdir))) {
294
                        $ret = false;
295
                        break;
296
                    }
297
298
                    if (!mkdir($newdir, $mode)) {
299
                        $ret = false;
300
                    }
301
                }
302
            }
303
        } else {
304
            foreach ($opts[1] as $dir) {
305
                if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
306
                    $ret = false;
307
                }
308
            }
309
        }
310
311
        return $ret;
312
    }
313
314
    /**
315
     * Concatenate files
316
     *
317
     * Usage:
318
     * 1) $var = System::cat('sample.txt test.txt');
319
     * 2) System::cat('sample.txt test.txt > final.txt');
320
     * 3) System::cat('sample.txt test.txt >> final.txt');
321
     *
322
     * Note: as the class use fopen, urls should work also (test that)
323
     *
324
     * @param    string $args the arguments
325
     * @return   boolean true on success
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
326
     */
327
    public static function &cat($args)
328
    {
329
        $ret   = null;
330
        $files = array();
331
        if (!is_array($args)) {
332
            $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
333
        }
334
335
        $count_args = count($args);
336
        for ($i = 0; $i < $count_args; $i++) {
337
            if ($args[$i] == '>') {
338
                $mode       = 'wb';
339
                $outputfile = $args[$i + 1];
340
                break;
341
            } elseif ($args[$i] == '>>') {
342
                $mode       = 'ab+';
343
                $outputfile = $args[$i + 1];
344
                break;
345
            } else {
346
                $files[] = $args[$i];
347
            }
348
        }
349
        $outputfd = false;
350
        if (isset($mode)) {
351
            if (!$outputfd = fopen($outputfile, $mode)) {
352
                $err = System::raiseError("Could not open $outputfile");
0 ignored issues
show
Bug introduced by
The variable $outputfile does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
353
354
                return $err;
355
            }
356
            $ret = true;
357
        }
358
        foreach ($files as $file) {
359
            if (!$fd = fopen($file, 'r')) {
360
                System::raiseError("Could not open $file");
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
361
                continue;
362
            }
363
            while ($cont = fread($fd, 2048)) {
364
                if (is_resource($outputfd)) {
365
                    fwrite($outputfd, $cont);
366
                } else {
367
                    $ret .= $cont;
368
                }
369
            }
370
            fclose($fd);
371
        }
372
        if (is_resource($outputfd)) {
373
            fclose($outputfd);
374
        }
375
376
        return $ret;
377
    }
378
379
    /**
380
     * Creates temporary files or directories. This function will remove
381
     * the created files when the scripts finish its execution.
382
     *
383
     * Usage:
384
     *   1) $tempfile = System::mktemp("prefix");
385
     *   2) $tempdir  = System::mktemp("-d prefix");
386
     *   3) $tempfile = System::mktemp();
387
     *   4) $tempfile = System::mktemp("-t /var/tmp prefix");
388
     *
389
     * prefix -> The string that will be prepended to the temp name
390
     *           (defaults to "tmp").
391
     * -d     -> A temporary dir will be created instead of a file.
392
     * -t     -> The target dir where the temporary (file|dir) will be created. If
393
     *           this param is missing by default the env vars TMP on Windows or
394
     *           TMPDIR in Unix will be used. If these vars are also missing
395
     *           c:\windows\temp or /tmp will be used.
396
     *
397
     * @param   string $args The arguments
0 ignored issues
show
Documentation introduced by
Should the type for parameter $args not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
398
     * @return  mixed   the full path of the created (file|dir) or false
399
     * @see System::tmpdir()
400
     */
401
    public static function mktemp($args = null)
0 ignored issues
show
Coding Style introduced by
mktemp uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
402
    {
403
        static $first_time = true;
404
        $opts = System::_parseArgs($args, 't:d');
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
405
        if (PEAR::isError($opts)) {
406
            return System::raiseError($opts);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
407
        }
408
409
        foreach ($opts[0] as $opt) {
410
            if ($opt[0] == 'd') {
411
                $tmp_is_dir = true;
412
            } elseif ($opt[0] == 't') {
413
                $tmpdir = $opt[1];
414
            }
415
        }
416
417
        $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
418
        if (!isset($tmpdir)) {
419
            $tmpdir = System::tmpdir();
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
420
        }
421
422
        if (!System::mkDir(array('-p', $tmpdir))) {
0 ignored issues
show
Documentation introduced by
array('-p', $tmpdir) is of type array<integer,?,{"0":"string","1":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
423
            return false;
424
        }
425
426
        $tmp = tempnam($tmpdir, $prefix);
427
        if (isset($tmp_is_dir)) {
428
            unlink($tmp); // be careful possible race condition here
429
            if (!mkdir($tmp, 0700)) {
430
                return System::raiseError("Unable to create temporary directory $tmpdir");
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
431
            }
432
        }
433
434
        $GLOBALS['_System_temp_files'][] = $tmp;
435
        if (isset($tmp_is_dir)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
436
            //$GLOBALS['_System_temp_files'][] = dirname($tmp);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
437
        }
438
439
        if ($first_time) {
440
            PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
441
            $first_time = false;
442
        }
443
444
        return $tmp;
445
    }
446
447
    /**
448
     * Remove temporary files created my mkTemp. This function is executed
449
     * at script shutdown time
450
     */
451
    public static function _removeTmpFiles()
0 ignored issues
show
Coding Style introduced by
_removeTmpFiles uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
452
    {
453
        if (count($GLOBALS['_System_temp_files'])) {
454
            $delete = $GLOBALS['_System_temp_files'];
455
            array_unshift($delete, '-r');
456
            System::rm($delete);
0 ignored issues
show
Documentation introduced by
$delete is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
457
            $GLOBALS['_System_temp_files'] = array();
458
        }
459
    }
460
461
    /**
462
     * Get the path of the temporal directory set in the system
463
     * by looking in its environments variables.
464
     * Note: php.ini-recommended removes the "E" from the variables_order setting,
465
     * making unavaible the $_ENV array, that s why we do tests with _ENV
466
     *
467
     * @return string The temporary directory on the system
468
     */
469
    public static function tmpdir()
0 ignored issues
show
Coding Style introduced by
tmpdir uses the super-global variable $_ENV which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
470
    {
471
        if (OS_WINDOWS) {
472 View Code Duplication
            if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
473
                return $var;
474
            }
475 View Code Duplication
            if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
476
                return $var;
477
            }
478 View Code Duplication
            if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
479
                return $var;
480
            }
481 View Code Duplication
            if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
482
                return $var;
483
            }
484
485
            return getenv('SystemRoot') . '\temp';
486
        }
487 View Code Duplication
        if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
488
            return $var;
489
        }
490
491
        return realpath('/tmp');
492
    }
493
494
    /**
495
     * The "which" command (show the full path of a command)
496
     *
497
     * @param string $program  The command to search for
498
     * @param mixed  $fallback Value to return if $program is not found
499
     *
500
     * @return mixed A string with the full path or false if not found
501
     * @author Stig Bakken <[email protected]>
502
     */
503
    public static function which($program, $fallback = false)
504
    {
505
        // enforce API
506
        if (!is_string($program) || '' == $program) {
507
            return $fallback;
508
        }
509
510
        // full path given
511
        if (basename($program) != $program) {
512
            $path_elements[] = dirname($program);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$path_elements was never initialized. Although not strictly required by PHP, it is generally a good practice to add $path_elements = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
513
            $program         = basename($program);
514
        } else {
515
            $path = getenv('PATH');
516
            if (!$path) {
517
                $path = getenv('Path'); // some OSes are just stupid enough to do this
518
            }
519
520
            $path_elements = explode(PATH_SEPARATOR, $path);
521
        }
522
523
        if (OS_WINDOWS) {
524
            $exe_suffixes = getenv('PATHEXT') ? explode(PATH_SEPARATOR, getenv('PATHEXT')) : array('.exe', '.bat', '.cmd', '.com');
525
            // allow passing a command.exe param
526
            if (strpos($program, '.') !== false) {
527
                array_unshift($exe_suffixes, '');
528
            }
529
        } else {
530
            $exe_suffixes = array('');
531
        }
532
533
        foreach ($exe_suffixes as $suff) {
534
            foreach ($path_elements as $dir) {
535
                $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
536
                if (is_executable($file)) {
537
                    return $file;
538
                }
539
            }
540
        }
541
542
        return $fallback;
543
    }
544
545
    /**
546
     * The "find" command
547
     *
548
     * Usage:
549
     *
550
     * System::find($dir);
551
     * System::find("$dir -type d");
552
     * System::find("$dir -type f");
553
     * System::find("$dir -name *.php");
554
     * System::find("$dir -name *.php -name *.htm*");
555
     * System::find("$dir -maxdepth 1");
556
     *
557
     * Params implemented:
558
     * $dir            -> Start the search at this directory
559
     * -type d         -> return only directories
560
     * -type f         -> return only files
561
     * -maxdepth <n>   -> max depth of recursion
562
     * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
563
     *
564
     * @param  mixed Either array or string with the command line
565
     * @return array Array of found files
566
     */
567
    public static function find($args)
568
    {
569
        if (!is_array($args)) {
570
            $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
571
        }
572
        $dir = realpath(array_shift($args));
573
        if (!$dir) {
574
            return array();
575
        }
576
        $patterns   = array();
577
        $depth      = 0;
578
        $do_files   = $do_dirs = true;
579
        $args_count = count($args);
580
        for ($i = 0; $i < $args_count; $i++) {
581
            switch ($args[$i]) {
582
                case '-type':
583
                    if (in_array($args[$i + 1], array('d', 'f'))) {
584
                        if ($args[$i + 1] == 'd') {
585
                            $do_files = false;
586
                        } else {
587
                            $do_dirs = false;
588
                        }
589
                    }
590
                    $i++;
591
                    break;
592
                case '-name':
593
                    $name = preg_quote($args[$i + 1], '#');
594
                    // our magic characters ? and * have just been escaped,
595
                    // so now we change the escaped versions to PCRE operators
596
                    $name       = strtr($name, array('\?' => '.', '\*' => '.*'));
597
                    $patterns[] = '(' . $name . ')';
598
                    $i++;
599
                    break;
600
                case '-maxdepth':
601
                    $depth = $args[$i + 1];
602
                    break;
603
            }
604
        }
605
        $path = System::_dirToStruct($dir, $depth, 0, true);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
606
        if ($do_files && $do_dirs) {
607
            $files = array_merge($path['files'], $path['dirs']);
608
        } elseif ($do_dirs) {
609
            $files = $path['dirs'];
610
        } else {
611
            $files = $path['files'];
612
        }
613
        if (count($patterns)) {
614
            $dsq         = preg_quote(DIRECTORY_SEPARATOR, '#');
615
            $pattern     = '#(^|' . $dsq . ')' . implode('|', $patterns) . '($|' . $dsq . ')#';
616
            $ret         = array();
617
            $files_count = count($files);
618
            for ($i = 0; $i < $files_count; $i++) {
619
                // only search in the part of the file below the current directory
620
                $filepart = basename($files[$i]);
621
                if (preg_match($pattern, $filepart)) {
622
                    $ret[] = $files[$i];
623
                }
624
            }
625
626
            return $ret;
627
        }
628
629
        return $files;
630
    }
631
}
632