1 | <?php |
||||
2 | |||||
3 | use Elgg\Filesystem\Directory; |
||||
4 | use Elgg\Application; |
||||
5 | use Elgg\Project\Paths; |
||||
6 | use Elgg\Http\Request; |
||||
7 | |||||
8 | /** |
||||
9 | * Elgg RewriteTester. |
||||
10 | * Test if URL rewriting is working. |
||||
11 | */ |
||||
12 | class ElggRewriteTester { |
||||
13 | protected $webserver; |
||||
14 | protected $serverSupportsRemoteRead; |
||||
15 | protected $rewriteTestPassed; |
||||
16 | protected $htaccessIssue; |
||||
17 | |||||
18 | /** |
||||
19 | * Set the webserver as unknown. |
||||
20 | */ |
||||
21 | public function __construct() { |
||||
22 | $this->webserver = 'unknown'; |
||||
23 | } |
||||
24 | |||||
25 | /** |
||||
26 | * Run the rewrite test and return a status array |
||||
27 | * |
||||
28 | * @param string $url URL of rewrite test |
||||
29 | * @param string $path Root directory of Elgg with trailing slash |
||||
30 | * |
||||
31 | * @return array |
||||
32 | */ |
||||
33 | public function run($url, $path) { |
||||
34 | |||||
35 | $this->webserver = \ElggRewriteTester::guessWebServer(); |
||||
36 | |||||
37 | $this->rewriteTestPassed = $this->runRewriteTest($url); |
||||
38 | |||||
39 | if ($this->rewriteTestPassed == false) { |
||||
0 ignored issues
–
show
|
|||||
40 | if ($this->webserver == 'apache' || $this->webserver == 'unknown') { |
||||
41 | if ($this->createHtaccess($url, $path)) { |
||||
0 ignored issues
–
show
The call to
ElggRewriteTester::createHtaccess() has too many arguments starting with $path .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||
42 | $this->rewriteTestPassed = $this->runRewriteTest($url); |
||||
43 | } |
||||
44 | } |
||||
45 | } |
||||
46 | |||||
47 | return $this->returnStatus($url); |
||||
48 | } |
||||
49 | |||||
50 | /** |
||||
51 | * Guess the web server from $_SERVER['SERVER_SOFTWARE'] |
||||
52 | * |
||||
53 | * @return string |
||||
54 | */ |
||||
55 | public static function guessWebServer() { |
||||
56 | if (empty($_SERVER['SERVER_SOFTWARE'])) { |
||||
57 | return 'unknown'; |
||||
58 | } |
||||
59 | |||||
60 | $serverString = strtolower($_SERVER['SERVER_SOFTWARE']); |
||||
61 | $possibleServers = ['apache', 'nginx', 'lighttpd', 'iis']; |
||||
62 | foreach ($possibleServers as $server) { |
||||
63 | if (strpos($serverString, $server) !== false) { |
||||
64 | return $server; |
||||
65 | } |
||||
66 | } |
||||
67 | return 'unknown'; |
||||
68 | } |
||||
69 | |||||
70 | /** |
||||
71 | * Guess if url contains subdirectory or not. |
||||
72 | * |
||||
73 | * @param string $url Rewrite test URL |
||||
74 | * |
||||
75 | * @return string|bool Subdirectory string with beginning and trailing slash or false if were unable to determine subdirectory |
||||
76 | * or pointing at root of domain already |
||||
77 | */ |
||||
78 | public function guessSubdirectory($url) { |
||||
79 | $elements = parse_url($url); |
||||
80 | if (!$elements || !isset($elements['path'])) { |
||||
81 | return false; |
||||
82 | } |
||||
83 | $subdir = trim(dirname($elements['path']), '/'); |
||||
84 | if (!$subdir) { |
||||
85 | return false; |
||||
86 | } else { |
||||
87 | return "/$subdir/"; |
||||
88 | } |
||||
89 | } |
||||
90 | |||||
91 | /** |
||||
92 | * Hit the rewrite test URL to determine if the rewrite rules are working |
||||
93 | * |
||||
94 | * @param string $url Rewrite test URL |
||||
95 | * |
||||
96 | * @return bool |
||||
97 | */ |
||||
98 | public function runRewriteTest($url) { |
||||
99 | $this->serverSupportsRemoteRead = ($this->fetchUrl($url) === Request::REWRITE_TEST_OUTPUT); |
||||
100 | return $this->serverSupportsRemoteRead; |
||||
101 | } |
||||
102 | |||||
103 | /** |
||||
104 | * Check whether the site homepage can be fetched via curl |
||||
105 | * |
||||
106 | * @return boolean |
||||
107 | */ |
||||
108 | public function runLocalhostAccessTest() { |
||||
109 | $url = _elgg_config()->wwwroot; |
||||
110 | return (bool) $this->fetchUrl($url); |
||||
111 | } |
||||
112 | |||||
113 | /** |
||||
114 | * Fetch a URL |
||||
115 | * |
||||
116 | * @param string $url The URL |
||||
117 | * |
||||
118 | * @return string Note that empty string may imply failure in fetching or empty response |
||||
119 | */ |
||||
120 | private function fetchUrl($url) { |
||||
121 | $response = ''; |
||||
122 | |||||
123 | if (ini_get('allow_url_fopen')) { |
||||
124 | $ctx = stream_context_create([ |
||||
125 | 'http' => [ |
||||
126 | 'follow_location' => 0, |
||||
127 | 'timeout' => 5, |
||||
128 | ], |
||||
129 | ]); |
||||
130 | $response = @file_get_contents($url, null, $ctx); |
||||
131 | } |
||||
132 | |||||
133 | if (!$response && function_exists('curl_init')) { |
||||
134 | $ch = curl_init(); |
||||
135 | curl_setopt($ch, CURLOPT_URL, $url); |
||||
136 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||||
137 | curl_setopt($ch, CURLOPT_TIMEOUT, 5); |
||||
138 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
||||
139 | $response = curl_exec($ch); |
||||
140 | curl_close($ch); |
||||
141 | } |
||||
142 | |||||
143 | return (string) $response; |
||||
144 | } |
||||
145 | |||||
146 | /** |
||||
147 | * Create Elgg's .htaccess file or confirm that it exists |
||||
148 | * |
||||
149 | * @param string $url URL of rewrite test |
||||
150 | * |
||||
151 | * @return bool |
||||
152 | */ |
||||
153 | public function createHtaccess($url) { |
||||
154 | $root = Directory\Local::projectRoot(); |
||||
155 | $file = $root->getFile(".htaccess"); |
||||
156 | |||||
157 | if ($file->exists()) { |
||||
158 | // check that this is the Elgg .htaccess |
||||
159 | $data = $file->getContents(); |
||||
160 | if ($data === false) { |
||||
161 | // don't have permission to read the file |
||||
162 | $this->htaccessIssue = 'read_permission'; |
||||
163 | return false; |
||||
164 | } |
||||
165 | |||||
166 | if (strpos($data, 'Elgg') === false) { |
||||
167 | $this->htaccessIssue = 'non_elgg_htaccess'; |
||||
168 | return false; |
||||
169 | } |
||||
170 | |||||
171 | // check if this is an old Elgg htaccess |
||||
172 | if (strpos($data, 'RewriteRule ^rewrite.php$ install.php') == false) { |
||||
173 | $this->htaccessIssue = 'old_elgg_htaccess'; |
||||
174 | return false; |
||||
175 | } |
||||
176 | return true; |
||||
177 | } |
||||
178 | |||||
179 | if (!is_writable($root->getPath())) { |
||||
180 | $this->htaccessIssue = 'write_permission'; |
||||
181 | return false; |
||||
182 | } |
||||
183 | |||||
184 | // create the .htaccess file |
||||
185 | $result = copy(Paths::elgg() . "install/config/htaccess.dist", $file->getPath()); |
||||
186 | if (!$result) { |
||||
187 | $this->htaccessIssue = 'cannot_copy'; |
||||
188 | return false; |
||||
189 | } |
||||
190 | |||||
191 | // does default RewriteBase work already? |
||||
192 | if (!$this->runRewriteTest($url)) { |
||||
193 | //try to rewrite to guessed subdirectory |
||||
194 | if ($subdir = $this->guessSubdirectory($url)) { |
||||
195 | $contents = $file->getContents(); |
||||
196 | $contents = preg_replace("/#RewriteBase \/(\r?\n)/", "RewriteBase $subdir\$1", $contents); |
||||
197 | if ($contents) { |
||||
198 | $file->putContents($contents); |
||||
199 | } |
||||
200 | } |
||||
201 | } |
||||
202 | |||||
203 | return true; |
||||
204 | } |
||||
205 | |||||
206 | /** |
||||
207 | * Create the status array required by the ElggInstaller |
||||
208 | * |
||||
209 | * @param string $url Rewrite test URL |
||||
210 | * |
||||
211 | * @return array |
||||
212 | */ |
||||
213 | protected function returnStatus($url) { |
||||
214 | if ($this->rewriteTestPassed) { |
||||
215 | return [ |
||||
216 | 'severity' => 'pass', |
||||
217 | 'message' => _elgg_services()->translator->translate('install:check:rewrite:success'), |
||||
218 | ]; |
||||
219 | } |
||||
220 | |||||
221 | if ($this->serverSupportsRemoteRead == false) { |
||||
222 | $msg = _elgg_services()->translator->translate('install:warning:rewrite:unknown', [$url]); |
||||
223 | $msg .= elgg_view('install/js_rewrite_check', ['url' => $url]); |
||||
224 | |||||
225 | return [ |
||||
226 | 'severity' => 'warning', |
||||
227 | 'message' => $msg, |
||||
228 | ]; |
||||
229 | } |
||||
230 | |||||
231 | if ($this->webserver == 'apache') { |
||||
232 | $serverString = _elgg_services()->translator->translate('install:error:rewrite:apache'); |
||||
233 | $msg = "$serverString\n\n"; |
||||
234 | if (!isset($this->htaccessIssue)) { |
||||
235 | $msg .= _elgg_services()->translator->translate('install:error:rewrite:allowoverride'); |
||||
236 | $msg .= elgg_view('install/js_rewrite_check', ['url' => $url]); |
||||
237 | |||||
238 | return [ |
||||
239 | 'severity' => 'warning', |
||||
240 | 'message' => $msg, |
||||
241 | ]; |
||||
242 | } |
||||
243 | $msg .= _elgg_services()->translator->translate("install:error:rewrite:htaccess:{$this->htaccessIssue}"); |
||||
244 | return [ |
||||
245 | 'severity' => 'warning', |
||||
246 | 'message' => $msg, |
||||
247 | ]; |
||||
248 | } |
||||
249 | |||||
250 | if ($this->webserver != 'unknown') { |
||||
251 | $serverString = _elgg_services()->translator->translate("install:error:rewrite:{$this->webserver}"); |
||||
252 | $msg = "$serverString\n\n"; |
||||
253 | $msg .= _elgg_services()->translator->translate("install:error:rewrite:altserver"); |
||||
254 | return [ |
||||
255 | 'severity' => 'warning', |
||||
256 | 'message' => $msg, |
||||
257 | ]; |
||||
258 | } |
||||
259 | |||||
260 | return [ |
||||
261 | 'severity' => 'warning', |
||||
262 | 'message' => _elgg_services()->translator->translate('install:error:rewrite:unknown'), |
||||
263 | ]; |
||||
264 | } |
||||
265 | } |
||||
266 |
When comparing two booleans, it is generally considered safer to use the strict comparison operator.