1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @file Lint.php |
5
|
|
|
* @brief This file contains the Lint class. |
6
|
|
|
* @details |
7
|
|
|
* @author Filippo F. Fadda |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
|
11
|
|
|
//! Global namespace. |
|
|
|
|
12
|
|
|
namespace Lint; |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @brief Lint is a wrapper to `php -l` command. |
17
|
|
|
*/ |
18
|
|
|
final class Lint { |
19
|
|
|
|
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @brief Performs the real syntax check. |
23
|
|
|
* @param string $sourceCode The source code. |
24
|
|
|
* @param bool $addTags (optional) Tells if you want add PHP tags to the source code, because PHP lint needs |
25
|
|
|
* them or it will raise an exception. |
26
|
|
|
*/ |
27
|
|
|
protected static function checkSyntax($sourceCode, $addTags = FALSE) { |
28
|
|
|
if ($addTags) |
29
|
|
|
// We add the PHP tags, else the lint ignores the code. The PHP command line option -r doesn't work. |
30
|
|
|
$sourceCode = "<?php ".$sourceCode." ?>"; |
31
|
|
|
|
32
|
|
|
// Try to create a temporary physical file. The function `proc_open` doesn't allow to use a memory file. |
33
|
|
|
if ($fd = fopen("php://temp", "r+")) { |
34
|
|
|
fputs($fd, $sourceCode); // We don't need to flush because we call rewind. |
35
|
|
|
rewind($fd); // Sets the pointer to the beginning of the file stream. |
36
|
|
|
|
37
|
|
|
$dspec = array( |
38
|
|
|
$fd, |
39
|
|
|
1 => array('pipe', 'w'), // stdout |
40
|
|
|
2 => array('pipe', 'w'), // stderr |
41
|
|
|
); |
42
|
|
|
|
43
|
|
|
$proc = proc_open(PHP_BINARY." -l", $dspec, $pipes); |
44
|
|
|
|
45
|
|
|
if (is_resource($proc)) { |
46
|
|
|
// Reads the stdout output. |
47
|
|
|
$output = ""; |
48
|
|
|
while (!feof($pipes[1])) { |
49
|
|
|
$output .= fgets($pipes[1]); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
// Reads the stderr output. |
53
|
|
|
$error = ""; |
54
|
|
|
while (!feof($pipes[2])) { |
55
|
|
|
$error .= fgets($pipes[2]); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
// Free all resources. |
59
|
|
|
fclose($fd); |
60
|
|
|
fclose($pipes[1]); |
61
|
|
|
fclose($pipes[2]); |
62
|
|
|
$exitCode = proc_close($proc); |
63
|
|
|
|
64
|
|
|
if ($exitCode != 0) { |
65
|
|
|
$pattern = array("/\APHP Parse error: /", |
66
|
|
|
"/in - /", |
67
|
|
|
"/\z -\n/"); |
68
|
|
|
|
69
|
|
|
$error = ucfirst(preg_replace($pattern, "", $error)); |
70
|
|
|
|
71
|
|
|
throw new \RuntimeException($error); |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
else |
75
|
|
|
throw new \RuntimeException("Cannot execute the `php -l` command."); |
76
|
|
|
} |
77
|
|
|
else |
78
|
|
|
throw new \RuntimeException("Cannot create the temporary file with the source code."); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @brief Makes the syntax check of the specified file. If an error occurs, generates an exception. |
84
|
|
|
* @warning File source code must be included in PHP tags. |
85
|
|
|
* @param string $fileName The file name you want check. |
86
|
|
|
*/ |
87
|
|
|
public static function checkSourceFile($fileName) { |
88
|
|
|
if (file_exists($fileName)) { |
89
|
|
|
$fd = fopen($fileName, "r"); |
90
|
|
|
|
91
|
|
|
if (is_resource($fd)) { |
92
|
|
|
$sourceCode = ""; |
93
|
|
|
|
94
|
|
|
while (!feof($fd)) |
95
|
|
|
$sourceCode .= fgets($fd); |
96
|
|
|
|
97
|
|
|
self::checkSyntax($sourceCode); |
98
|
|
|
} |
99
|
|
|
else |
100
|
|
|
throw new \RuntimeException("Cannot open the file."); |
101
|
|
|
} |
102
|
|
|
else |
103
|
|
|
throw new \RuntimeException("File not found."); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @brief Makes the syntax check of the given source code. If an error occurs, generates an exception. |
109
|
|
|
* @param string $str The source code. |
110
|
|
|
* @param bool $addTags (optional) Tells if you want add PHP tags to the source code, because PHP lint needs |
111
|
|
|
* them or it will raise an exception. |
112
|
|
|
*/ |
113
|
|
|
public static function checkSourceCode($str, $addTags = TRUE) { |
114
|
|
|
if (is_string($str)) |
115
|
|
|
self::checkSyntax($str, $addTags); |
116
|
|
|
else |
117
|
|
|
throw new \RuntimeException("\$str must be a string."); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
} |
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.