Permalink
Browse files

feature(routing): Removes /export and all secondary front controllers

This removes the “export” URL endpoints and removes all other /engine/handlers.
Requests for these resources now all use the front controller `index.php`.

Fixes #8425
Fixes #5017
  • Loading branch information...
mrclay committed Jun 7, 2015
1 parent 325f8d6 commit ab3c879f8828d4a951a968d1589ca6da9e436447
View
@@ -48,6 +48,14 @@ comments have been discarded now that IE10+ browsers are more standards-complian
If you need browser support farther back than that, you will need to find or build
a plugin that introduces its own compatibility layer or polyfills.
+Update your webserver config
+----------------------------
+
+URL paths like ``cache/*`` and ``rewrite.php`` now use the main front controller
+script. You **must** remove these rewrite rules from your webserver config (e.g. ``.htaccess``).
+
+Also remove the rules for paths like ``export/*``; these endpoints have been removed.
+
From 1.10 to 1.11
========================
@@ -156,6 +156,11 @@ Plugins should use the class ``Elgg\Application`` to boot Elgg. Typical usage:
require_once dirname(dirname(__DIR__)) . '/autoloader.php';
(new \Elgg\Application)->bootCore();
+``export/`` URLs are no longer available
+----------------------------------------
+
+Elgg no longer provides this endpoint for exposing resource data.
+
Introduced third-party library for sending email
------------------------------------------------
@@ -7,12 +7,21 @@
/**
* Load, boot, and implement a front controller for an Elgg application
*
+ * To run as PHP CLI server:
+ * <code>php -S localhost:8888 /full/path/to/elgg/index.php</code>
+ *
+ * The full path is necessary to work around this: https://bugs.php.net/bug.php?id=55726
+ *
* @property-read \Elgg\Services\Config $config
*
* @since 2.0.0
*/
class Application {
+ const GET_PATH_KEY = '__elgg_uri';
+ const REWRITE_TEST_TOKEN = '__testing_rewrite';
+ const REWRITE_TEST_OUTPUT = 'success';
+
/**
* @var ServiceProvider
*/
@@ -269,76 +278,44 @@ public function getDb() {
}
/**
- * Rewrite rules for PHP cli webserver used for testing. Do not use on production sites
- * as normal web server replacement.
- *
- * You need to explicitly point to index.php in order for router to work properly:
- *
- * <code>php -S localhost:8888 index.php</code>
+ * Routes the request, booting core if not yet booted
*
- * @return bool True if Elgg's router will handle the file, false if PHP should serve it directly
+ * @return bool False if Elgg wants the PHP CLI server to handle the request
*/
- protected function runPhpWebServer() {
- $urlPath = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
-
- if (preg_match('/^\/cache\/(.*)$/', $urlPath, $matches)) {
- $_GET['request'] = $matches[1];
- $handler = new CacheHandler($this);
- $handler->handleRequest($_GET, $_SERVER);
- exit;
- }
+ public function run() {
+ $path = $this->setupPath();
- if (preg_match('/^\/export\/([A-Za-z]+)\/([0-9]+)\/?$/', $urlPath, $matches)) {
- $_GET['view'] = $matches[1];
- $_GET['guid'] = $matches[2];
- require "{$this->engine_dir}/handlers/export_handler.php";
- exit;
+ // allow testing from the upgrade page before the site is upgraded.
+ if (isset($_GET[self::REWRITE_TEST_TOKEN])) {
+ if (false !== strpos($path, self::REWRITE_TEST_TOKEN)) {
+ echo self::REWRITE_TEST_OUTPUT;
+ }
+ return true;
}
- if (preg_match('/^\/export\/([A-Za-z]+)\/([0-9]+)\/([A-Za-z]+)\/([A-Za-z0-9\_]+)\/$/', $urlPath, $matches)) {
- $_GET['view'] = $matches[1];
- $_GET['guid'] = $matches[2];
- $_GET['type'] = $matches[3];
- $_GET['idname'] = $matches[4];
- require "{$this->engine_dir}/handlers/export_handler.php";
- exit;
+ if (php_sapi_name() === 'cli-server') {
+ $www_root = "http://{$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']}/";
+ $this->config->set('wwwroot', $www_root);
}
- if (preg_match("/^\/rewrite.php$/", $urlPath, $matches)) {
- require "{$this->install_dir}/install.php";
- exit;
+ if (0 === strpos($path, '/cache/')) {
+ (new Application\CacheHandler($this, $_SERVER))->handleRequest($path);
+ return true;
}
- if ($urlPath !== '/' && file_exists($this->install_dir . $urlPath)) {
- // serve the requested resource as-is.
- return false;
+ if ($path === '/rewrite.php') {
+ require "{$this->install_dir}/install.php";
+ return true;
}
- $_GET['__elgg_uri'] = $urlPath;
- return true;
- }
-
- /**
- * Routes the request, booting core if not yet booted
- *
- * @return bool False if Elgg wants the PHP CLI server to handle the request
- */
- public function run() {
if (php_sapi_name() === 'cli-server') {
- if (!$this->runPhpWebServer()) {
- // PHP will serve this file directly
+ // The CLI server routes ALL requests here (even existing files), so we have to check for these.
+ if ($path !== '/' && file_exists($this->install_dir . $path)) {
+ // serve the requested resource as-is.
return false;
}
}
- // allow testing from the upgrade page before the site is upgraded.
- if (isset($_GET['__testing_rewrite'])) {
- if (isset($_GET['__elgg_uri']) && false !== strpos($_GET['__elgg_uri'], '__testing_rewrite')) {
- echo "success";
- }
- return true;
- }
-
$this->bootCore();
if (!$this->services->router->route($this->services->request)) {
@@ -361,4 +338,24 @@ public function __get($name) {
}
trigger_error("Undefined property: " . __CLASS__ . ":\${$name}");
}
+
+ /**
+ * Get the request URI and store it in $_GET['__elgg_uri']
+ *
+ * @return string e.g. "cache/123..."
+ */
+ private function setupPath() {
+ if (!isset($_GET[self::GET_PATH_KEY]) || is_array($_GET[self::GET_PATH_KEY])) {
+ if (php_sapi_name() === 'cli-server') {
+ $_GET[self::GET_PATH_KEY] = (string)parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
+ } else {
+ $_GET[self::GET_PATH_KEY] = '/';
+ }
+ }
+
+ // normalize
+ $_GET[self::GET_PATH_KEY] = '/' . trim($_GET[self::GET_PATH_KEY], '/');
+
+ return $_GET[self::GET_PATH_KEY];
+ }
}
@@ -1,5 +1,7 @@
<?php
-namespace Elgg;
+namespace Elgg\Application;
+
+use Elgg\Application;
/**
* Simplecache handler
@@ -15,29 +17,32 @@ class CacheHandler {
*/
private $application;
+ /**
+ * @var array
+ */
+ private $server_vars;
+
/**
* Constructor
*
- * @param Application $app Elgg Application
+ * @param Application $app Elgg Application
+ * @param array $server_vars Server vars
*/
- public function __construct(Application $app) {
+ public function __construct(Application $app, $server_vars) {
$this->application = $app;
+ $this->server_vars = $server_vars;
}
/**
* Handle a request for a cached view
*
- * @param array $get_vars $_GET variables
- * @param array $server_vars $_SERVER variables
+ * @param array $path URL path
* @return void
*/
- public function handleRequest($get_vars, $server_vars) {
+ public function handleRequest($path) {
$config = $this->application->config;
- if (empty($get_vars['request'])) {
- $this->send403();
- }
- $request = $this->parseRequestVar($get_vars['request']);
+ $request = $this->parsePath($path);
if (!$request) {
$this->send403();
}
@@ -109,23 +114,23 @@ public function handleRequest($get_vars, $server_vars) {
/**
* Parse a request
*
- * @param string $request_var Request URL
+ * @param string $path Request URL path
* @return array Cache parameters (empty array if failure)
*/
- public function parseRequestVar($request_var) {
+ public function parsePath($path) {
// no '..'
- if (false !== strpos($request_var, '..')) {
+ if (false !== strpos($path, '..')) {
return array();
}
// only alphanumeric characters plus /, ., -, and _
- if (preg_match('#[^a-zA-Z0-9/\.\-_]#', $request_var)) {
+ if (preg_match('#[^a-zA-Z0-9/\.\-_]#', $path)) {
return array();
}
// testing showed regex to be marginally faster than array / string functions over 100000 reps
// it won't make a difference in real life and regex is easier to read.
// <ts>/<viewtype>/<name/of/view.and.dots>.<type>
- if (!preg_match('#^/?([0-9]+)/([^/]+)/(.+)$#', $request_var, $matches)) {
+ if (!preg_match('#^/cache/([0-9]+)/([^/]+)/(.+)$#', $path, $matches)) {
return array();
}
@@ -6,6 +6,7 @@
use Symfony\Component\HttpFoundation\FileBag;
use Symfony\Component\HttpFoundation\ServerBag;
use Symfony\Component\HttpFoundation\HeaderBag;
+use Elgg\Application;
/**
* WARNING: API IN FLUX. DO NOT USE DIRECTLY.
@@ -74,7 +75,7 @@ public function initialize(array $query = array(), array $request = array(), arr
* @return array
*/
public function getUrlSegments() {
- $path = trim($this->query->get('__elgg_uri'), '/');
+ $path = trim($this->query->get(Application::GET_PATH_KEY), '/');
if (!$path) {
return array();
}
@@ -1139,7 +1139,7 @@ protected function checkRewriteRules(&$report) {
*/
protected function processRewriteTest() {
if (strpos($_SERVER['REQUEST_URI'], 'rewrite.php') !== FALSE) {
- echo 'success';
+ echo \Elgg\Application::REWRITE_TEST_OUTPUT;
exit;
}
}
@@ -90,7 +90,7 @@ public function guessSubdirectory($url) {
* @return bool
*/
public function runRewriteTest($url) {
- $this->serverSupportsRemoteRead = ($this->fetchUrl($url) === 'success');
+ $this->serverSupportsRemoteRead = ($this->fetchUrl($url) === \Elgg\Application::REWRITE_TEST_OUTPUT);
return $this->serverSupportsRemoteRead;
}
@@ -1,21 +0,0 @@
-<?php
-/**
- * Action handler.
- *
- * This file dispatches actions. It is called via a URL rewrite in .htaccess
- * from http://site/action/. Anything after 'action/' is considered the action
- * and will be passed to {@link action()}.
- *
- * @warning This sets the input named 'action' to the current action. When calling
- * an action, get_input('action') will always return the action name.
- *
- * @package Elgg.Core
- * @subpackage Actions
- */
-
-require_once(dirname(dirname(__FILE__)) . "/start.php");
-
-register_error("Update your .htaccess file to remove the action handler");
-
-$action = get_input("action");
-action($action);
@@ -1,20 +0,0 @@
-<?php
-/**
- * Cache handler.
- *
- * External access to cached CSS and JavaScript views. The cached file URLS
- * should be of the form: cache/<ts>/<viewtype>/<name/of/view> where
- * ts is an identifier that is updated every time the cache is flushed.
- * The simplest way to maintain a unique identifier is to use the lastcache
- * timestamp in Elgg's config object.
- *
- * @see elgg_register_simplecache_view()
- *
- * @package Elgg.Core
- * @subpackage Cache
- */
-
-require_once dirname(dirname(__DIR__)) . '/autoloader.php';
-
-$handler = new \Elgg\CacheHandler(new Elgg\Application());
-$handler->handleRequest($_GET, $_SERVER);
Oops, something went wrong.

0 comments on commit ab3c879

Please sign in to comment.