ElggRewriteTester.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * Elgg RewriteTester.
  4. * Test if URL rewriting is working.
  5. *
  6. * @package Elgg.Core
  7. * @subpackage Installer
  8. */
  9. class ElggRewriteTester {
  10. protected $webserver;
  11. protected $serverSupportsRemoteRead;
  12. protected $rewriteTestPassed;
  13. protected $htaccessIssue;
  14. /**
  15. * Set the webserver as unknown.
  16. */
  17. public function __construct() {
  18. $this->webserver = 'unknown';
  19. }
  20. /**
  21. * Run the rewrite test and return a status array
  22. *
  23. * @param string $url URL of rewrite test
  24. * @param string $path Root directory of Elgg with trailing slash
  25. *
  26. * @return array
  27. */
  28. public function run($url, $path) {
  29. $this->webserver = \ElggRewriteTester::guessWebServer();
  30. $this->rewriteTestPassed = $this->runRewriteTest($url);
  31. if ($this->rewriteTestPassed == FALSE) {
  32. if ($this->webserver == 'apache' || $this->webserver == 'unknown') {
  33. if ($this->createHtaccess($url, $path)) {
  34. $this->rewriteTestPassed = $this->runRewriteTest($url);
  35. }
  36. }
  37. }
  38. return $this->returnStatus($url);
  39. }
  40. /**
  41. * Guess the web server from $_SERVER['SERVER_SOFTWARE']
  42. *
  43. * @return string
  44. */
  45. public static function guessWebServer() {
  46. $serverString = strtolower($_SERVER['SERVER_SOFTWARE']);
  47. $possibleServers = array('apache', 'nginx', 'lighttpd', 'iis');
  48. foreach ($possibleServers as $server) {
  49. if (strpos($serverString, $server) !== FALSE) {
  50. return $server;
  51. }
  52. }
  53. return 'unknown';
  54. }
  55. /**
  56. * Guess if url contains subdirectory or not.
  57. *
  58. * @param string $url Rewrite test URL
  59. *
  60. * @return string|bool Subdirectory string with beginning and trailing slash or false if were unable to determine subdirectory
  61. * or pointing at root of domain already
  62. */
  63. public function guessSubdirectory($url) {
  64. $elements = parse_url($url);
  65. if (!$elements || !isset($elements['path'])) {
  66. return false;
  67. }
  68. $subdir = trim(dirname($elements['path']), '/');
  69. if (!$subdir) {
  70. return false;
  71. } else {
  72. return "/$subdir/";
  73. }
  74. }
  75. /**
  76. * Hit the rewrite test URL to determine if the rewrite rules are working
  77. *
  78. * @param string $url Rewrite test URL
  79. *
  80. * @return bool
  81. */
  82. public function runRewriteTest($url) {
  83. $this->serverSupportsRemoteRead = ($this->fetchUrl($url) === 'success');
  84. return $this->serverSupportsRemoteRead;
  85. }
  86. /**
  87. * Check whether the site homepage can be fetched via curl
  88. *
  89. * @return boolean
  90. */
  91. public function runLocalhostAccessTest() {
  92. $url = _elgg_services()->config->getSiteUrl();
  93. return (bool)$this->fetchUrl($url);
  94. }
  95. /**
  96. * Fetch a URL
  97. *
  98. * @param string $url The URL
  99. *
  100. * @return string Note that empty string may imply failure in fetching or empty response
  101. */
  102. private function fetchUrl($url) {
  103. $response = '';
  104. if (ini_get('allow_url_fopen')) {
  105. $ctx = stream_context_create(array(
  106. 'http' => array(
  107. 'follow_location' => 0,
  108. 'timeout' => 5,
  109. ),
  110. ));
  111. $response = @file_get_contents($url, null, $ctx);
  112. }
  113. if (!$response && function_exists('curl_init')) {
  114. $ch = curl_init();
  115. curl_setopt($ch, CURLOPT_URL, $url);
  116. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  117. curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  118. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  119. $response = curl_exec($ch);
  120. curl_close($ch);
  121. }
  122. return (string)$response;
  123. }
  124. /**
  125. * Create Elgg's .htaccess file or confirm that it exists
  126. *
  127. * @param string $url URL of rewrite test
  128. * @param string $path Elgg's root directory with trailing slash
  129. *
  130. * @return bool
  131. */
  132. public function createHtaccess($url, $path) {
  133. $filename = "{$path}.htaccess";
  134. if (file_exists($filename)) {
  135. // check that this is the Elgg .htaccess
  136. $data = file_get_contents($filename);
  137. if ($data === FALSE) {
  138. // don't have permission to read the file
  139. $this->htaccessIssue = 'read_permission';
  140. return FALSE;
  141. }
  142. if (strpos($data, 'Elgg') === FALSE) {
  143. $this->htaccessIssue = 'non_elgg_htaccess';
  144. return FALSE;
  145. } else {
  146. // check if this is an old Elgg htaccess
  147. if (strpos($data, 'RewriteRule ^rewrite.php$ install.php') == FALSE) {
  148. $this->htaccessIssue = 'old_elgg_htaccess';
  149. return FALSE;
  150. }
  151. return TRUE;
  152. }
  153. }
  154. if (!is_writable($path)) {
  155. $this->htaccessIssue = 'write_permission';
  156. return FALSE;
  157. }
  158. // create the .htaccess file
  159. $result = copy("{$path}install/config/htaccess.dist", $filename);
  160. if (!$result) {
  161. $this->htaccessIssue = 'cannot_copy';
  162. return FALSE;
  163. }
  164. // does default RewriteBase work already?
  165. if (!$this->runRewriteTest($url)) {
  166. //try to rewrite to guessed subdirectory
  167. if ($subdir = $this->guessSubdirectory($url)) {
  168. $contents = file_get_contents($filename);
  169. $contents = preg_replace("/#RewriteBase \/(\r?\n)/", "RewriteBase $subdir\$1", $contents);
  170. if ($contents) {
  171. file_put_contents($filename, $contents);
  172. }
  173. }
  174. }
  175. return TRUE;
  176. }
  177. /**
  178. * Create the status array required by the ElggInstaller
  179. *
  180. * @param string $url Rewrite test URL
  181. *
  182. * @return array
  183. */
  184. protected function returnStatus($url) {
  185. if ($this->rewriteTestPassed) {
  186. return array(
  187. 'severity' => 'pass',
  188. 'message' => _elgg_services()->translator->translate('install:check:rewrite:success'),
  189. );
  190. }
  191. if ($this->serverSupportsRemoteRead == FALSE) {
  192. $msg = _elgg_services()->translator->translate('install:warning:rewrite:unknown', array($url));
  193. $msg .= elgg_view('install/js_rewrite_check', array('url' => $url));
  194. return array(
  195. 'severity' => 'warning',
  196. 'message' => $msg,
  197. );
  198. }
  199. if ($this->webserver == 'apache') {
  200. $serverString = _elgg_services()->translator->translate('install:error:rewrite:apache');
  201. $msg = "$serverString\n\n";
  202. if (!isset($this->htaccessIssue)) {
  203. $msg .= _elgg_services()->translator->translate('install:error:rewrite:allowoverride');
  204. $msg .= elgg_view('install/js_rewrite_check', array('url' => $url));
  205. return array(
  206. 'severity' => 'failure',
  207. 'message' => $msg,
  208. );
  209. }
  210. $msg .= _elgg_services()->translator->translate("install:error:rewrite:htaccess:{$this->htaccessIssue}");
  211. return array(
  212. 'severity' => 'failure',
  213. 'message' => $msg,
  214. );
  215. }
  216. if ($this->webserver != 'unknown') {
  217. $serverString = _elgg_services()->translator->translate("install:error:rewrite:{$this->webserver}");
  218. $msg = "$serverString\n\n";
  219. $msg .= _elgg_services()->translator->translate("install:error:rewrite:altserver");
  220. return array(
  221. 'severity' => 'failure',
  222. 'message' => $msg,
  223. );
  224. }
  225. return array(
  226. 'severity' => 'failure',
  227. 'message' => _elgg_services()->translator->translate('install:error:rewrite:unknown'),
  228. );
  229. }
  230. }