diff options
Diffstat (limited to 'engine')
-rw-r--r-- | engine/handlers/action_handler.php | 3 | ||||
-rw-r--r-- | engine/lib/actions.php | 151 |
2 files changed, 127 insertions, 27 deletions
diff --git a/engine/handlers/action_handler.php b/engine/handlers/action_handler.php index 8a1f1276b..a6bdaeae9 100644 --- a/engine/handlers/action_handler.php +++ b/engine/handlers/action_handler.php @@ -6,6 +6,9 @@ * 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 * @link http://docs.elgg.org/Tutorials/Actions diff --git a/engine/lib/actions.php b/engine/lib/actions.php index cdad8ebab..b889476b3 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -1,21 +1,56 @@ <?php /** - * Elgg actions - * Allows system modules to specify actions + * Elgg Actions * - * @package Elgg - * @subpackage Core - * @author Curverider Ltd - * @link http://elgg.org/ + * Actions are the primary controllers (The C in MVC) in Elgg. The are + * registered by {@link register_elgg_action()} and are called either by URL + * http://elggsite.org/action/action_name or {@link action($action_name}. For + * URLs, rewrite a rule in .htaccess passes the action name to + * engine/handlers/action_handler.php, which dispatches the action. + * + * An action name should be registered to exactly one file in the system, usually under + * the actions/ directory. + * + * All actions require security tokens. Using the {@elgg_view input/form} view + * will automatically add tokens as hidden inputs. To manually add hidden inputs, + * use the {@elgg_view input/securitytoken} view. + * + * To include security tokens for actions called via GET, use + * {@link elgg_add_security_tokens_to_url()}. + * + * Action tokens can be manually generated by using {@link generate_action_token()}. + * + * @tip When registered, actions can be restricted to logged in or admin users. + * + * @tip Action URLs should be called with a trailing / to prevent 301 redirects. + * + * @package Elgg.Core + * @subpackage Actions + * @link http://docs.elgg.org/Actions + * @link http://docs.elgg.org/Actions/Tokens */ -// Action setting and run ************************************************* - /** -* Loads an action script, if it exists, then forwards elsewhere +* Perform an action. +* +* This function executes the action with name $action as +* registered by {@link register_action()}. +* +* The plugin hook action, $action_name will be emitted before +* the action is executed. If a handler returns false, it will +* prevent the action from being called. +* +* @note If an action isn't registered in the system or is registered +* to an unavailable file the user will be forwarded to the site front +* page and an error will be emitted via {@link regiser_error()}. +* +* @warning All actions require {@link http://docs.elgg.org/Actions/Tokens Action Tokens}. +* @warning Most plugin shouldn't call this manually. * * @param string $action The requested action * @param string $forwarder Optionally, the location to forward to +* @link http://docs.elgg.org/Actions +* @see register_action() */ function action($action, $forwarder = "") { global $CONFIG; @@ -55,17 +90,17 @@ function action($action, $forwarder = "") { if ($CONFIG->actions[$action]['public'] || get_loggedin_userid()) { // Trigger action event - // @todo This is only called before the primary action is called. We need to rethink actions for 1.5 + // @todo This is only called before the primary action is called. $event_result = true; $event_result = trigger_plugin_hook('action', $action, null, $event_result); // Include action - // Event_result being false doesn't produce an error - + // Event_result being false doesn't produce an error // since i assume this will be handled in the hook itself. // @todo make this better! if ($event_result) { if (!include($CONFIG->actions[$action]['file'])) { - register_error(sprintf(elgg_echo('actionundefined'),$action)); + register_error(sprintf(elgg_echo('actionundefined'), $action)); } } } else { @@ -75,19 +110,47 @@ function action($action, $forwarder = "") { register_error(elgg_echo('actionunauthorized')); } } else { - register_error(sprintf(elgg_echo('actionundefined'),$action)); + register_error(sprintf(elgg_echo('actionundefined'), $action)); } forward($CONFIG->url . $forwarder); } /** - * Registers a particular action in memory + * Registers an action. + * + * Actions are registered to a single file in the system and are executed + * either by the URL http://elggsite.org/action/action_name or by calling + * {@link action()}. + * + * $file must be the full path of the file to register, or a path relative + * to the core actions/ dir. + * + * Actions should be namedspaced for your plugin. Example: + * <code> + * register_action('myplugin/save_settings', ...); + * </code> + * + * @tip Put action files under the actions/ directory of your plugin. + * + * @tip You don't need to include engine/start.php, call {@link gatekeeper()}, + * or call {@link admin_gatekeeper()}. + * + * @internal Actions are saved in $CONFIG->actions as an array in the form: + * <code> + * array( + * 'file' => '/location/to/file.php', + * 'public' => BOOL If false, user must be logged in. + * 'admin' => BOOL If true, user must be admin (implies plugin = false) + * ) + * </code> * * @param string $action The name of the action (eg "register", "account/settings/save") * @param boolean $public Can this action be accessed by people not logged into the system? * @param string $filename Optionally, the filename where this action is located * @param boolean $admin_only Whether this action is only available to admin users. + * @see action() + * @see http://docs.elgg.org/Actions */ function register_action($action, $public = false, $filename = "", $admin_only = false) { global $CONFIG; @@ -119,6 +182,7 @@ function register_action($action, $public = false, $filename = "", $admin_only = * @param string $event Events API required parameters * @param string $object_type Events API required parameters * @param string $object Events API required parameters + * @todo remove */ function actions_init($event, $object_type, $object) { register_action("error"); @@ -126,9 +190,21 @@ function actions_init($event, $object_type, $object) { } /** - * Validate an action token, returning true if valid and false if not + * Validate an action token. + * + * Calls to actions will automatically validate tokens. + * If tokens are not present or invalid, the action will be + * denied and the user will be redirected to the front page. * - * @return unknown + * Plugin authors should never have to manually validate action tokens. + * + * @access private + * @param bool $visibleerrors Emit {@link register_error()} errors on failure? + * @param mixed $token The token to test against. Pulls from $_REQUEST['__elgg_token'] if NULL. + * @param mixed $ts The time stamp to test against. Pulls from $_REQUEST['__elgg_ts'] if NULL. + * @return bool + * @see generate_action_token() + * @link http://docs.elgg.org/Actions/Tokens */ function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL) { if (!$token) { @@ -181,11 +257,16 @@ function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL) } /** -* Action gatekeeper. +* Validates the presence of action tokens. +* +* This function is called for all actions. If action tokens are missing, +* the user will be forwarded to the site front page and an error emitted. +* * This function verifies form input for security features (like a generated token), and forwards * the page if they are invalid. * -* Place at the head of actions. +* @access private +* @return mixed True if valid, or redirects to front page and exists. */ function action_gatekeeper() { if (validate_action_token()) { @@ -197,30 +278,41 @@ function action_gatekeeper() { } /** - * Generate a token for the current user suitable for being placed in a hidden field in action forms. + * Generate an action token. + * + * Action tokens are based on timestamps as returned by {@link time()}. + * They are valid for one hour. + * + * Action tokens should be passed to all actions name __elgg_ts and __elgg_token. + * + * @warning Action tokens are required for all actions. * * @param int $timestamp Unix timestamp + * @see @elgg_view input/securitytoken + * @see @elgg_view input/form + * @example actions/manual_tokens.php */ function generate_action_token($timestamp) { - // Get input values $site_secret = get_site_secret(); - - // Current session id $session_id = session_id(); - // Session token $st = $_SESSION['__elgg_session']; if (($site_secret) && ($session_id)) { - return md5($site_secret.$timestamp.$session_id.$st); + return md5($site_secret . $timestamp . $session_id . $st); } return FALSE; } /** - * Initialise the site secret. + * Initialise the site secret hash. + * + * Used during installation and saves as a datalist. * + * @return mixed The site secret hash or false + * @access private + * @todo Move to better file. */ function init_site_secret() { $secret = md5(rand().microtime()); @@ -232,8 +324,13 @@ function init_site_secret() { } /** - * Retrieve the site secret. + * Returns the site secret. + * + * Used to generate difficult to guess hashes for sessions and action tokens. * + * @return string Site secret. + * @access private + * @todo Move to better file. */ function get_site_secret() { $secret = datalist_get('__site_secret__'); @@ -257,4 +354,4 @@ function elgg_action_exist($action) { return (isset($CONFIG->actions[$action]) && file_exists($CONFIG->actions[$action]['file'])); } -register_elgg_event_handler("init","system","actions_init"); +register_elgg_event_handler("init", "system", "actions_init");
\ No newline at end of file |