Elgg  Version master
RewriteTester.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Router;
4 
7 
14 
15  protected string $webserver;
16 
17  protected bool $serverSupportsRemoteRead;
18 
19  protected bool $rewriteTestPassed;
20 
21  protected string $htaccessIssue;
22 
26  public function __construct() {
27  $this->webserver = 'unknown';
28  }
29 
37  public function run(string $url): array {
38 
39  $this->webserver = $this->guessWebServer();
40 
41  $this->rewriteTestPassed = $this->runRewriteTest($url);
42 
43  if ($this->rewriteTestPassed === false) {
44  if ($this->webserver == 'apache' || $this->webserver == 'unknown') {
45  if ($this->createHtaccess($url)) {
46  $this->rewriteTestPassed = $this->runRewriteTest($url);
47  }
48  }
49  }
50 
51  return $this->returnStatus($url);
52  }
53 
59  protected function guessWebServer(): string {
60  if (empty($_SERVER['SERVER_SOFTWARE'])) {
61  return 'unknown';
62  }
63 
64  $serverString = strtolower($_SERVER['SERVER_SOFTWARE']);
65  $possibleServers = ['apache', 'nginx', 'lighttpd', 'iis'];
66  foreach ($possibleServers as $server) {
67  if (elgg_strpos($serverString, $server) !== false) {
68  return $server;
69  }
70  }
71 
72  return 'unknown';
73  }
74 
83  protected function guessSubdirectory(string $url): string|false {
84  $elements = parse_url($url);
85  if (!is_array($elements) || !isset($elements['path'])) {
86  return false;
87  }
88 
89  $subdir = trim(dirname($elements['path']), '/');
90  if (!$subdir) {
91  return false;
92  }
93 
94  return "/{$subdir}/";
95  }
96 
104  public function runRewriteTest(string $url): bool {
105  $this->serverSupportsRemoteRead = ($this->fetchUrl($url) === Request::REWRITE_TEST_OUTPUT);
107  }
108 
114  public function runLocalhostAccessTest(): bool {
115  return (bool) $this->fetchUrl(_elgg_services()->config->wwwroot);
116  }
117 
125  private function fetchUrl(string $url): string {
126  $response = '';
127 
128  if (ini_get('allow_url_fopen')) {
129  $ctx = stream_context_create([
130  'http' => [
131  'follow_location' => 0,
132  'timeout' => 5,
133  ],
134  ]);
135  $response = @file_get_contents($url, false, $ctx);
136  }
137 
138  if (!$response && function_exists('curl_init')) {
139  $ch = curl_init();
140  curl_setopt($ch, CURLOPT_URL, $url);
141  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
142  curl_setopt($ch, CURLOPT_TIMEOUT, 5);
143  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
144  $response = curl_exec($ch);
145  curl_close($ch);
146  }
147 
148  return (string) $response;
149  }
150 
158  public function createHtaccess(string $url): bool {
159  $htaccess = Paths::project() . '.htaccess';
160 
161  if (file_exists($htaccess)) {
162  // check that this is the Elgg .htaccess
163  $data = file_get_contents($htaccess);
164  if (empty($data)) {
165  // don't have permission to read the file
166  $this->htaccessIssue = 'read_permission';
167  return false;
168  }
169 
170  if (elgg_strpos($data, 'Elgg') === false) {
171  $this->htaccessIssue = 'non_elgg_htaccess';
172  return false;
173  }
174 
175  // check if this is an old Elgg htaccess
176  if (elgg_strpos($data, 'RewriteRule ^rewrite.php$ install.php') === false) {
177  $this->htaccessIssue = 'old_elgg_htaccess';
178  return false;
179  }
180 
181  return true;
182  }
183 
184  if (!is_writable(Paths::project())) {
185  $this->htaccessIssue = 'write_permission';
186  return false;
187  }
188 
189  // create the .htaccess file
190  $result = copy(Paths::elgg() . 'install/config/htaccess.dist', $htaccess);
191  if (!$result) {
192  $this->htaccessIssue = 'cannot_copy';
193  return false;
194  }
195 
196  // does default RewriteBase work already?
197  if (!$this->runRewriteTest($url)) {
198  //try to rewrite to guessed subdirectory
199  $subdir = $this->guessSubdirectory($url);
200  if (!empty($subdir)) {
201  $contents = file_get_contents($htaccess);
202  $contents = preg_replace("/#RewriteBase \/(\r?\n)/", "RewriteBase $subdir\$1", $contents);
203  if ($contents) {
204  file_put_contents($htaccess, $contents);
205  }
206  }
207  }
208 
209  return true;
210  }
211 
219  protected function returnStatus(string $url): array {
220  if ($this->rewriteTestPassed) {
221  return [
222  'severity' => 'success',
223  'message' => _elgg_services()->translator->translate('install:check:rewrite:success'),
224  ];
225  }
226 
227  if ($this->serverSupportsRemoteRead === false) {
228  $msg = _elgg_services()->translator->translate('install:warning:rewrite:unknown', [$url]);
229  $msg .= elgg_view('install/js_rewrite_check', ['url' => $url]);
230 
231  return [
232  'severity' => 'warning',
233  'message' => $msg,
234  ];
235  }
236 
237  if ($this->webserver === 'apache') {
238  $msg = _elgg_services()->translator->translate('install:error:rewrite:apache');
239  $msg .= PHP_EOL . PHP_EOL;
240  if (!isset($this->htaccessIssue)) {
241  $msg .= _elgg_services()->translator->translate('install:error:rewrite:allowoverride');
242  $msg .= elgg_view('install/js_rewrite_check', ['url' => $url]);
243 
244  return [
245  'severity' => 'warning',
246  'message' => $msg,
247  ];
248  }
249 
250  $msg .= _elgg_services()->translator->translate("install:error:rewrite:htaccess:{$this->htaccessIssue}");
251  return [
252  'severity' => 'warning',
253  'message' => $msg,
254  ];
255  }
256 
257  if ($this->webserver !== 'unknown') {
258  $msg = _elgg_services()->translator->translate("install:error:rewrite:{$this->webserver}");
259  $msg .= PHP_EOL . PHP_EOL;
260  $msg .= _elgg_services()->translator->translate('install:error:rewrite:altserver');
261  return [
262  'severity' => 'warning',
263  'message' => $msg,
264  ];
265  }
266 
267  return [
268  'severity' => 'warning',
269  'message' => _elgg_services()->translator->translate('install:error:rewrite:unknown'),
270  ];
271  }
272 }
static project()
Get the project root (where composer is installed) path with "/".
Definition: Paths.php:25
static elgg()
Get the Elgg codebase path with "/".
Definition: Paths.php:44
guessSubdirectory(string $url)
Guess if url contains subdirectory or not.
$response
Definition: content.php:10
run(string $url)
Run the rewrite test and return a status array.
returnStatus(string $url)
Create the status array required by the ElggInstaller.
__construct()
Set the webserver as unknown.
Test if URL rewriting is working.
runRewriteTest(string $url)
Hit the rewrite test URL to determine if the rewrite rules are working.
if(!$entity instanceof\ElggUser) $data
Definition: attributes.php:13
runLocalhostAccessTest()
Check whether the site homepage can be fetched via curl.
elgg_view(string $view, array $vars=[], string $viewtype= '')
Return a parsed view.
Definition: views.php:156
createHtaccess(string $url)
Create Elgg&#39;s .htaccess file or confirm that it exists.
elgg_strpos()
Wrapper function for mb_strpos().
Definition: mb_wrapper.php:71
guessWebServer()
Guess the web server from $_SERVER[&#39;SERVER_SOFTWARE&#39;].
and give any other recipients of the Program a copy of this License along with the Program You may charge a fee for the physical act of transferring a copy
Definition: LICENSE.txt:140
foreach($plugin_guids as $guid) if(empty($deactivated_plugins)) $url
Definition: deactivate.php:39
_elgg_services()
Get the global service provider.
Definition: elgglib.php:351
if(!empty($title)&&!empty($icon_name)) if(!empty($title)) if(!empty($menu)) if(!empty($header)) if(!empty($body)) $contents
Definition: message.php:73