Completed
Push — master ( fda08e...d5e2fd )
by Sebastien
02:30
created

HackedFileGroup::scanDirectory()   C

Complexity

Conditions 11
Paths 4

Size

Total Lines 52
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 52
rs 6
cc 11
eloc 38
nc 4
nop 8

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Cerbere\Model\Hacked;
4
5
/**
6
 * Represents a group of files on the local filesystem.
7
 */
8
class HackedFileGroup
9
{
10
    /**
11
     * @var string
12
     */
13
    protected $base_path = '';
14
15
    /**
16
     * @var array
17
     */
18
    protected $files = array();
19
20
    /**
21
     * @var array
22
     */
23
    protected $files_hashes = array();
24
25
    /**
26
     * @var array
27
     */
28
    protected $file_mtimes = array();
29
30
    /**
31
     * @var HackedFileHasher
32
     */
33
    protected $hasher;
34
35
    /**
36
     * Constructor.
37
     *
38
     * @param string $base_path
39
     * @param HackedFileHasher $hasher
40
     */
41
    public function __construct($base_path, HackedFileHasher $hasher = null)
42
    {
43
        if (null === $hasher) {
44
            $hasher = new HackedFileIgnoreEndingsHasher();
45
        }
46
47
        $this->base_path = $base_path;
48
        $this->hasher = $hasher;
49
    }
50
51
    /**
52
     * Hash all files listed in the file group.
53
     */
54
    public function computeHashes()
55
    {
56
        foreach ($this->files as $filename) {
57
            $this->files_hashes[$filename] = $this->hasher->hash($this->base_path . DIRECTORY_SEPARATOR . $filename);
58
        }
59
    }
60
61
    /**
62
     * Determine if a file exists.
63
     * @param string $file
64
     * @return bool
65
     */
66
    public function fileExists($file)
67
    {
68
        return file_exists($this->base_path . DIRECTORY_SEPARATOR . $file);
69
    }
70
71
    /**
72
     * Return a new hackedFileGroup listing all files inside the given $path.
73
     *
74
     * @param string $path
75
     *
76
     * @return HackedFileGroup
77
     */
78
    public static function createFromDirectory($path)
79
    {
80
        $filegroup = new self($path);
81
        // Find all the files in the path, and add them to the file group.
82
        $filegroup->scanBasePath();
83
84
        return $filegroup;
85
    }
86
87
    /**
88
     * Locate all sensible files at the base path of the file group.
89
     */
90
    public function scanBasePath()
91
    {
92
        $files = self::scanDirectory(
93
          $this->base_path,
94
          '/.*/',
95
          array(
96
            '.',
97
            '..',
98
            'CVS',
99
            '.svn',
100
            '.git',
101
          )
102
        );
103
104
        foreach ($files as $file) {
105
            $filename = str_replace($this->base_path . DIRECTORY_SEPARATOR, '', $file->filename);
106
            $this->files[] = $filename;
107
        }
108
    }
109
110
    /**
111
     * @param string $dir
112
     * @param int $mask
113
     * @param array $nomask
114
     * @param callable $callback
115
     * @param bool|true $recurse
116
     * @param string $key
117
     * @param int $min_depth
118
     * @param int $depth
119
     *
120
     * @return array
121
     */
122
    public static function scanDirectory(
123
      $dir,
124
      $mask,
125
      $nomask = array('.', '..', 'CVS'),
126
      $callback = null,
127
      $recurse = true,
128
      $key = 'filename',
129
      $min_depth = 0,
130
      $depth = 0
131
    ) {
132
        $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
133
        $files = array();
134
135
        if (is_dir($dir) && $handle = opendir($dir)) {
136
            while (false !== ($file = readdir($handle))) {
137
                if (!in_array($file, $nomask)) {
138
                    if (is_dir($dir . DIRECTORY_SEPARATOR . $file) && $recurse) {
139
                        // Give priority to files in this folder by merging them in after any subdirectory files.
140
                        $files = array_merge(
141
                          self::scanDirectory(
142
                            $dir . DIRECTORY_SEPARATOR . $file,
143
                            $mask,
144
                            $nomask,
145
                            $callback,
146
                            $recurse,
147
                            $key,
148
                            $min_depth,
149
                            $depth + 1
150
                          ),
151
                          $files
152
                        );
153
                    } elseif ($depth >= $min_depth && preg_match($mask, $file)) {
154
                        // Always use this match over anything already set in $files with the same $$key.
155
                        $filename = $dir . DIRECTORY_SEPARATOR . $file;
156
                        $basename = basename($file);
157
                        $name = substr($basename, 0, strrpos($basename, '.'));
158
                        $files[$$key] = new \stdClass();
159
                        $files[$$key]->filename = $filename;
160
                        $files[$$key]->basename = $basename;
161
                        $files[$$key]->name = $name;
162
                        if (is_callable($callback)) {
163
                            $callback($filename);
164
                        }
165
                    }
166
                }
167
            }
168
169
            closedir($handle);
170
        }
171
172
        return $files;
173
    }
174
175
    /**
176
     * Return a new hackedFileGroup listing all files specified.
177
     *
178
     * @param string $path
179
     * @param array $files
180
     *
181
     * @return HackedFileGroup
182
     */
183
    public static function createFromList($path, array $files)
184
    {
185
        $filegroup = new self($path);
186
        // Find all the files in the path, and add them to the file group.
187
        $filegroup->files = $files;
188
189
        return $filegroup;
190
    }
191
192
    /**
193
     * @param string $file
194
     *
195
     * @return string|bool
196
     */
197
    public function getFileHash($file)
198
    {
199
        if (isset($this->files_hashes[$file])) {
200
            return $this->files_hashes[$file];
201
        }
202
203
        return false;
204
    }
205
206
    /**
207
     * @param string $file
208
     * @return string
209
     */
210
    public function getFileLocation($file)
211
    {
212
        return $this->base_path . DIRECTORY_SEPARATOR . $file;
213
    }
214
215
    /**
216
     * @return array
217
     */
218
    public function getFiles()
219
    {
220
        return $this->files;
221
    }
222
223
    /**
224
     * Determine if the given file is binary.
225
     * @param string $file
226
     * @return bool
227
     */
228
    public function isNotBinary($file)
229
    {
230
        return is_readable($this->base_path . DIRECTORY_SEPARATOR . $file)
231
        && !self::isBinary($this->base_path . DIRECTORY_SEPARATOR . $file);
232
    }
233
234
    /**
235
     * Determine if a file is a binary file.
236
     *
237
     * Taken from: http://www.ultrashock.com/forums/server-side/checking-if-a-file-is-binary-98391.html
238
     * and then tweaked in: http://drupal.org/node/760362.
239
     *
240
     * @param string $file
241
     *
242
     * @return bool
243
     */
244
    public static function isBinary($file)
245
    {
246
        if (file_exists($file)) {
247
            if (!is_file($file)) {
248
                return 0;
249
            }
250
            if (!is_readable($file)) {
251
                return 1;
252
            }
253
254
            $fh = fopen($file, "r");
255
            $blk = fread($fh, 512);
256
            fclose($fh);
257
            clearstatcache();
258
259
            return (
260
              0 or substr_count($blk, "^\r\n") / 512 > 0.3
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
261
              or substr_count($blk, "^ -~") / 512 > 0.3
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
262
              or substr_count($blk, "\x00") > 0
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
263
            );
264
        }
265
266
        return 0;
267
    }
268
269
    /**
270
     * Determine if the given file is readable.
271
     * @param string $file
272
     * @return bool
273
     */
274
    public function isReadable($file)
275
    {
276
        return is_readable($this->base_path . DIRECTORY_SEPARATOR . $file);
277
    }
278
}
279