1 | <?php |
||||
2 | |||||
3 | use Elgg\Filesystem\Directory; |
||||
0 ignored issues
–
show
|
|||||
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) { |
||||
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'])) { |
||||
0 ignored issues
–
show
The expression
$elements of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||||
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) { |
||||
0 ignored issues
–
show
|
|||||
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 |
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: