Completed
Push — master ( c60cf3...36f595 )
by Sebastien
07:49
created

HackedFileGroup::scanDirectory()   C

Complexity

Conditions 11
Paths 4

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 32
rs 5.2653
cc 11
eloc 20
nc 4
nop 8

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