These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Cerbere\Model\Hacked; |
||
4 | |||
5 | use Cerbere\Model\Project; |
||
6 | |||
7 | /** |
||
8 | * Encapsulates a Hacked! project. |
||
9 | * |
||
10 | * This class should handle all the complexity for you, and so you should be able to do: |
||
11 | * <code> |
||
12 | * $project = hackedProject('context'); |
||
13 | * $project->compute_differences(); |
||
14 | * </code> |
||
15 | * |
||
16 | * Which is quite nice I think. |
||
17 | */ |
||
18 | class HackedProject { |
||
19 | const STATUS_UNCHECKED = 1; |
||
20 | |||
21 | const STATUS_PERMISSION_DENIED = 2; |
||
22 | |||
23 | const STATUS_HACKED = 3; |
||
24 | |||
25 | const STATUS_DELETED = 4; |
||
26 | |||
27 | const STATUS_UNHACKED = 5; |
||
28 | |||
29 | /** @var Project */ |
||
30 | var $project; |
||
0 ignored issues
–
show
|
|||
31 | |||
32 | var $name = ''; |
||
0 ignored issues
–
show
The visibility should be declared for property
$name .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
33 | |||
34 | var $project_info = array(); |
||
0 ignored issues
–
show
The visibility should be declared for property
$project_info .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
35 | |||
36 | /** @var HackedProjectWebDownloader */ |
||
37 | var $remote_files_downloader; |
||
0 ignored issues
–
show
The visibility should be declared for property
$remote_files_downloader .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
38 | |||
39 | /* @var hackedFileGroup $remote_files */ |
||
40 | var $remote_files; |
||
0 ignored issues
–
show
The visibility should be declared for property
$remote_files .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
41 | |||
42 | /* @var hackedFileGroup $local_files */ |
||
43 | var $local_files; |
||
0 ignored issues
–
show
The visibility should be declared for property
$local_files .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
44 | |||
45 | var $local_folder; |
||
0 ignored issues
–
show
The visibility should be declared for property
$local_folder .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
46 | |||
47 | var $project_type = ''; |
||
0 ignored issues
–
show
The visibility should be declared for property
$project_type .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
48 | var $existing_version = ''; |
||
0 ignored issues
–
show
The visibility should be declared for property
$existing_version .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
49 | |||
50 | var $result = array(); |
||
0 ignored issues
–
show
The visibility should be declared for property
$result .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
51 | |||
52 | var $project_identified = FALSE; |
||
0 ignored issues
–
show
The visibility should be declared for property
$project_identified .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
53 | var $remote_downloaded = FALSE; |
||
0 ignored issues
–
show
The visibility should be declared for property
$remote_downloaded .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
54 | var $remote_hashed = FALSE; |
||
0 ignored issues
–
show
The visibility should be declared for property
$remote_hashed .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
55 | var $local_hashed = FALSE; |
||
0 ignored issues
–
show
The visibility should be declared for property
$local_hashed .
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using class A {
var $property;
}
the property is implicitly global. To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.
Loading history...
|
|||
56 | |||
57 | /** |
||
58 | * Constructor. |
||
59 | * @param Project $project |
||
60 | * @param string $local_folder |
||
61 | */ |
||
62 | public function __construct(Project $project, $local_folder = null) { |
||
63 | if (null === $local_folder) { |
||
64 | $local_folder = getcwd(); |
||
65 | } |
||
66 | $this->project = $project; |
||
67 | $this->local_folder = $local_folder; |
||
68 | $this->name = $project->getProject(); |
||
69 | $this->remote_files_downloader = new HackedProjectWebFilesDownloader($project); |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * @return Project |
||
74 | */ |
||
75 | public function getProject() |
||
76 | { |
||
77 | return $this->project; |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Get the Human readable title of this project. |
||
82 | */ |
||
83 | public function getTitle() { |
||
84 | $this->identifyProject(); |
||
85 | |||
86 | return isset($this->project_info['title']) ? $this->project_info['title'] : $this->name; |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * Identify the project from the name we've been created with. |
||
91 | * |
||
92 | * We leverage the update (status) module to get the data we require about |
||
93 | * projects. We just pull the information in, and make descisions about this |
||
94 | * project being from CVS or not. |
||
95 | */ |
||
96 | public function identifyProject() { |
||
97 | // Only do this once, no matter how many times we're called. |
||
98 | if (!empty($this->project_identified)) { |
||
99 | return; |
||
100 | } |
||
101 | |||
102 | $data = (array) $this->project; |
||
103 | $this->project_info = array(); |
||
104 | |||
105 | foreach ($data as $key => $value) { |
||
106 | $key = str_replace('*', '', $key); |
||
107 | $this->project_info[$key] = $value; |
||
108 | } |
||
109 | |||
110 | $this->project_info['releases'] = $this->project->getReleases(); |
||
111 | $this->project_identified = TRUE; |
||
112 | $this->existing_version = $this->project->getExistingVersion(); |
||
113 | $this->project_type = 'module'; |
||
114 | $this->project_info['includes'] = array($this->name . '.module'); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Downloads the remote project to be hashed later. |
||
119 | */ |
||
120 | public function downloadRemoteProject() { |
||
121 | // Only do this once, no matter how many times we're called. |
||
122 | if (!empty($this->remote_downloaded)) { |
||
123 | return; |
||
124 | } |
||
125 | |||
126 | $this->identifyProject(); |
||
127 | $this->remote_downloaded = (bool) $this->remote_files_downloader->downloadFile(); |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * Hashes the remote project downloaded earlier. |
||
132 | */ |
||
133 | View Code Duplication | public function hashRemoteProject() { |
|
0 ignored issues
–
show
This method seems to be duplicated in 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...
|
|||
134 | // Only do this once, no matter how many times we're called. |
||
135 | if (!empty($this->remote_hashed)) { |
||
136 | return; |
||
137 | } |
||
138 | |||
139 | // Ensure that the remote project has actually been downloaded. |
||
140 | $this->downloadRemoteProject(); |
||
141 | |||
142 | // Set up the remote file group. |
||
143 | $base_path = $this->remote_files_downloader->getFinalDestination(); |
||
144 | $this->remote_files = HackedFileGroup::fromDirectory($base_path); |
||
145 | $this->remote_files->computeHashes(); |
||
146 | |||
147 | $this->remote_hashed = count($this->remote_files->getFiles()) > 0; |
||
148 | |||
149 | // Logging. |
||
150 | if (!$this->remote_hashed) { |
||
151 | //throw new \Exception('Could not hash remote project: ' . $this->getTitle()); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
59% 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...
|
|||
152 | echo 'Could not hash remote project: ' . $this->getTitle() . "\n"; |
||
153 | } |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Locate the base directory of the local project. |
||
158 | */ |
||
159 | public function locateLocalProject() { |
||
160 | // we need a remote project to do this :( |
||
161 | $this->hashRemoteProject(); |
||
162 | |||
163 | $project_type = $this->project->getProjectType(); |
||
164 | |||
165 | if ($project_type == Project::TYPE_PROJECT_CORE || $project_type == Project::TYPE_PROJECT_DISTRIBUTION) { |
||
166 | $folder = dirname(dirname($this->local_folder)); |
||
167 | } else { |
||
168 | $folder = $this->local_folder; |
||
169 | } |
||
170 | |||
171 | return realpath($folder); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Hash the local version of the project. |
||
176 | */ |
||
177 | View Code Duplication | public function hashLocalProject() { |
|
0 ignored issues
–
show
This method seems to be duplicated in 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...
|
|||
178 | // Only do this once, no matter how many times we're called. |
||
179 | if (!empty($this->local_hashed)) { |
||
180 | return; |
||
181 | } |
||
182 | |||
183 | $location = $this->locateLocalProject(); |
||
184 | $this->local_files = hackedFileGroup::fromList($location, $this->remote_files->getFiles()); |
||
185 | $this->local_files->computeHashes(); |
||
186 | $this->local_hashed = count($this->local_files->getFiles()) > 0; |
||
187 | |||
188 | // Logging. |
||
189 | if (!$this->local_hashed) { |
||
190 | //throw new \Exception('Could not hash remote project: ' . $this->getTitle()); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
59% 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...
|
|||
191 | echo 'Could not hash local project: ' . $this->getTitle() . "\n"; |
||
192 | } |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Compute the differences between our version and the canonical version of the project. |
||
197 | */ |
||
198 | public function computeDifferences() { |
||
199 | // Make sure we've hashed both remote and local files. |
||
200 | $this->hashRemoteProject(); |
||
201 | $this->hashLocalProject(); |
||
202 | |||
203 | $results = array( |
||
204 | 'same' => array(), |
||
205 | 'different' => array(), |
||
206 | 'missing' => array(), |
||
207 | 'access_denied' => array(), |
||
208 | ); |
||
209 | |||
210 | // Now compare the two file groups. |
||
211 | foreach ($this->remote_files->getFiles() as $file) { |
||
212 | if ($this->remote_files->getFileHash($file) == $this->local_files->getFileHash($file)) { |
||
213 | $results['same'][] = $file; |
||
214 | } |
||
215 | elseif (!$this->local_files->fileExists($file)) { |
||
216 | $results['missing'][] = $file; |
||
217 | } |
||
218 | elseif (!$this->local_files->isReadable($file)) { |
||
219 | $results['access_denied'][] = $file; |
||
220 | } |
||
221 | else { |
||
222 | $results['different'][] = $file; |
||
223 | } |
||
224 | } |
||
225 | |||
226 | $this->result = $results; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Return a nice report, a simple overview of the status of this project. |
||
231 | */ |
||
232 | public function computeReport() { |
||
233 | // Ensure we know the differences. |
||
234 | $this->computeDifferences(); |
||
235 | |||
236 | // Do some counting |
||
237 | $report = array( |
||
238 | 'project_name' => $this->name, |
||
239 | 'status' => self::STATUS_UNCHECKED, |
||
240 | 'counts' => array( |
||
241 | 'same' => count($this->result['same']), |
||
242 | 'different' => count($this->result['different']), |
||
243 | 'missing' => count($this->result['missing']), |
||
244 | 'access_denied' => count($this->result['access_denied']), |
||
245 | ), |
||
246 | 'title' => $this->getTitle(), |
||
247 | ); |
||
248 | |||
249 | // Add more details into the report result (if we can). |
||
250 | $details = array( |
||
251 | 'link', |
||
252 | 'name', |
||
253 | 'existing_version', |
||
254 | 'install_type', |
||
255 | 'datestamp', |
||
256 | 'project_type', |
||
257 | 'includes', |
||
258 | ); |
||
259 | |||
260 | foreach ($details as $item) { |
||
261 | if (isset($this->project_info[$item])) { |
||
262 | $report[$item] = $this->project_info[$item]; |
||
263 | } |
||
264 | } |
||
265 | |||
266 | if ($report['counts']['access_denied'] > 0) { |
||
267 | $report['status'] = self::STATUS_PERMISSION_DENIED; |
||
268 | } |
||
269 | elseif ($report['counts']['missing'] > 0) { |
||
270 | $report['status'] = self::STATUS_HACKED; |
||
271 | } |
||
272 | elseif ($report['counts']['different'] > 0) { |
||
273 | $report['status'] = self::STATUS_HACKED; |
||
274 | } |
||
275 | elseif ($report['counts']['same'] > 0) { |
||
276 | $report['status'] = self::STATUS_UNHACKED; |
||
277 | } |
||
278 | |||
279 | return $report; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Return a nice detailed report. |
||
284 | * @return array |
||
285 | */ |
||
286 | public function computeDetails() { |
||
287 | // Ensure we know the differences. |
||
288 | $report = $this->computeReport(); |
||
289 | |||
290 | $report['files'] = array(); |
||
291 | |||
292 | // Add extra details about every file. |
||
293 | $states = array( |
||
294 | 'access_denied' => self::STATUS_PERMISSION_DENIED, |
||
295 | 'missing' => self::STATUS_DELETED, |
||
296 | 'different' => self::STATUS_HACKED, |
||
297 | 'same' => self::STATUS_UNHACKED, |
||
298 | ); |
||
299 | |||
300 | foreach ($states as $state => $status) { |
||
301 | foreach ($this->result[$state] as $file) { |
||
302 | $report['files'][$file] = $status; |
||
303 | $report['diffable'][$file] = $this->fileIsDiffable($file); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | return $report; |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * @param string $file |
||
312 | * |
||
313 | * @return bool |
||
314 | */ |
||
315 | public function fileIsDiffable($file) { |
||
316 | $this->hashRemoteProject(); |
||
317 | $this->hashLocalProject(); |
||
318 | |||
319 | return $this->remote_files->isNotBinary($file) && $this->local_files->isNotBinary($file); |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * @param string $storage |
||
324 | * @param string $file |
||
325 | * |
||
326 | * @return bool|string |
||
327 | */ |
||
328 | public function getFileLocation($storage = 'local', $file) { |
||
329 | switch ($storage) { |
||
330 | case 'remote': |
||
331 | $this->downloadRemoteProject(); |
||
332 | return $this->remote_files->getFileLocation($file); |
||
333 | case 'local': |
||
334 | $this->hashLocalProject(); |
||
335 | return $this->local_files->getFileLocation($file); |
||
336 | } |
||
337 | |||
338 | return FALSE; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * @param string $status |
||
343 | * @return string |
||
344 | */ |
||
345 | public static function getStatusLabel($status) { |
||
346 | switch ($status) { |
||
347 | case self::STATUS_PERMISSION_DENIED: |
||
348 | return 'Permission denied'; |
||
349 | case self::STATUS_HACKED: |
||
350 | return 'Hacked'; |
||
351 | case self::STATUS_DELETED: |
||
352 | return 'Deleted'; |
||
353 | case self::STATUS_UNHACKED: |
||
354 | return 'Unhacked'; |
||
355 | case self::STATUS_UNCHECKED: |
||
356 | default: |
||
357 | return 'Unchecked'; |
||
358 | } |
||
359 | } |
||
360 | } |
||
361 |
The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using
the property is implicitly global.
To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.