aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documentation/examples/actions/manual_tokens.php6
-rw-r--r--engine/handlers/action_handler.php3
-rw-r--r--engine/lib/actions.php151
3 files changed, 133 insertions, 27 deletions
diff --git a/documentation/examples/actions/manual_tokens.php b/documentation/examples/actions/manual_tokens.php
new file mode 100644
index 000000000..8dcf61fb1
--- /dev/null
+++ b/documentation/examples/actions/manual_tokens.php
@@ -0,0 +1,6 @@
+<?php
+
+$ts = time();
+$token = generate_action_token($ts);
+
+var_dump($ts, $token);
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