Source Code
Requested
by: Dr. Eric Breimer
Web Master & Assistant Professor
Department of Computer Science
Dr.
Tim Lederman
Professor
Department
of Computer Science
Alumni Spotlight Web System
(ASWS)
Initrode Solutions
Prepared
by: Anthony Angelucci
Charles Feltes
Elise Hearn
Christopher McConnell
Monday, April 30th
2007
<?php
// $Id: form.inc,v 1.174.2.3
2007/01/29 21:51:53 drumm Exp $
/**
* @defgroup form Form generation
* @{
* Functions to enable the processing and
display of HTML forms.
*
* Drupal uses these functions to achieve
consistency in its form processing and
* presentation, while simplifying code and
reducing the amount of HTML that
* must be explicitly generated by modules.
*
* The drupal_get_form() function handles
retrieving, processing, and
* displaying a rendered HTML form for modules
automatically. For example:
*
* // Display the user registration form.
* $output = drupal_get_form('user_register');
*
* Forms can also be built and submitted
programmatically without any user input
* using the drupal_execute() function.
*
*
* For information on the format of the
structured arrays used to define forms,
* and more detailed explanations of the Form
API workflow, see the reference at
*
http://api.drupal.org/api/HEAD/file/developer/topics/forms_api_reference.html
* and the quickstart guide at
*
http://api.drupal.org/api/HEAD/file/developer/topics/forms_api.html
*/
/**
* Retrieves a form from a builder function,
passes it on for
* processing, and renders the form or
redirects to its destination
* as appropriate. In multi-step form
scenarios, it handles properly
* processing the values using the previous
step's form definition,
* then rendering the requested step for display.
*
* @param $form_id
* The
unique string identifying the desired form. If a function
* with
that name exists, it is called to build the form array.
*
Modules that need to generate the same form (or very similar forms)
*
using different $form_ids can implement hook_forms(), which maps
*
different $form_id values to the proper form building function. Examples
* may
be found in node_forms(), search_forms(), and user_forms().
* @param ...
* Any
additional arguments needed by the form building function.
* @return
* The
rendered form.
*/
function
drupal_get_form($form_id) {
// In multi-step form scenarios, the incoming
$_POST values are not
// necessarily intended for the current form.
We need to build
// a copy of the previously built form for
validation and processing,
// then go on to the one that was requested
if everything works.
$form_build_id = md5(mt_rand());
if (isset($_POST['form_build_id']) &&
isset(XXXXXXXXX['form'][$_POST['form_build_id']]['args']) && $_POST['form_id']
== $form_id) {
// There's a previously stored multi-step
form. We should handle
// IT first.
$stored = TRUE;
$args =
XXXXXXXXX['form'][$_POST['form_build_id']]['args'];
$form =
call_user_func_array('drupal_retrieve_form', $args);
$form['#build_id'] =
$_POST['form_build_id'];
}
else {
// We're coming in fresh; build things as
they would be. If the
// form's #multistep flag is set, store the
build parameters so
// the same form can be reconstituted for
validation.
$args = func_get_args();
$form =
call_user_func_array('drupal_retrieve_form', $args);
if (isset($form['#multistep']) &&
$form['#multistep']) {
// Clean up old multistep form session
data.
_drupal_clean_form_sessions();
XXXXXXXXX['form'][$form_build_id] =
array('timestamp' => time(), 'args' => $args);
$form['#build_id'] = $form_build_id;
}
$stored = FALSE;
}
// Process the form, submit it, and store any
errors if necessary.
drupal_process_form($args[0], $form);
if ($stored && !form_get_errors()) {
// If it's a stored form and there were no
errors, we processed the
// stored form successfully. Now we need to
build the form that was
// actually requested. We always pass in
the current $_POST values
// to the builder function, as values from
one stage of a multistep
// form can determine how subsequent steps
are displayed.
$args = func_get_args();
$args[] = $_POST;
$form =
call_user_func_array('drupal_retrieve_form', $args);
unset(XXXXXXXXX['form'][$_POST['form_build_id']]);
if (isset($form['#multistep']) &&
$form['#multistep']) {
XXXXXXXXX['form'][$form_build_id] =
array('timestamp' => time(), 'args' => $args);
$form['#build_id'] = $form_build_id;
}
drupal_prepare_form($args[0], $form);
}
return drupal_render_form($args[0], $form);
}
/**
* Remove form information that's at least a
day old from the
* XXXXXXXXX['form'] array.
*/
function
_drupal_clean_form_sessions() {
if (isset(XXXXXXXXX['form'])) {
foreach (XXXXXXXXX['form'] as $build_id
=> $data) {
if ($data['timestamp'] < (time() -
84600)) {
unset(XXXXXXXXX['form'][$build_id]);
}
}
}
}
/**
* Retrieves a form using a form_id, populates
it with $form_values,
* processes it, and returns any validation
errors encountered. This
* function is the programmatic counterpart to
drupal_get_form().
*
* @param $form_id
* The
unique string identifying the desired form. If a function
* with
that name exists, it is called to build the form array.
*
Modules that need to generate the same form (or very similar forms)
*
using different $form_ids can implement hook_forms(), which maps
*
different $form_id values to the proper form building function. Examples
* may
be found in node_forms(), search_forms(), and user_forms().
* @param $form_values
* An
array of values mirroring the values returned by a given form
* when
it is submitted by a user.
* @param ...
* Any
additional arguments needed by the form building function.
* @return
* Any
form validation errors encountered.
*
* For example:
*
* // register a new user
* $values['name'] = 'robo-user';
* $values['mail'] = 'robouser@example.com';
* $values['pass'] = 'password';
* drupal_execute('user_register', $values);
*
* // Create a new node
* $node = array('type' => 'story');
* $values['title'] = 'My node';
* $values['body'] = 'This is the body text!';
* $values['name'] = 'robo-user';
* drupal_execute('story_node_form', $values,
$node);
*/
function
drupal_execute($form_id, $form_values) {
$args = func_get_args();
$form_id = array_shift($args);
$form_values = array_shift($args);
array_unshift($args, $form_id);
if (isset($form_values)) {
$form = call_user_func_array('drupal_retrieve_form',
$args);
$form['#post'] = $form_values;
return drupal_process_form($form_id,
$form);
}
}
/**
* Retrieves the structured array that defines
a given form.
*
* @param $form_id
* The
unique string identifying the desired form. If a function
* with
that name exists, it is called to build the form array.
*
Modules that need to generate the same form (or very similar forms)
*
using different $form_ids can implement hook_forms(), which maps
*
different $form_id values to the proper form building function.
* @param ...
* Any
additional arguments needed by the form building function.
*/
function
drupal_retrieve_form($form_id) {
static $forms;
// We save two copies of the incoming
arguments: one for modules to use
// when mapping form ids to builder
functions, and another to pass to
// the builder function itself. We shift out
the first argument -- the
// $form_id itself -- from the list to pass
into the builder function,
// since it's already known.
$args = func_get_args();
$saved_args = $args;
array_shift($args);
// We first check to see if there's a
function named after the $form_id.
// If there is, we simply pass the arguments
on to it to get the form.
if (!function_exists($form_id)) {
// In cases where many form_ids need to
share a central builder function,
// such as the node editing form, modules
can implement hook_forms(). It
// maps one or more form_ids to the correct
builder functions.
//
// We cache the results of that hook to
save time, but that only works
// for modules that know all their form_ids
in advance. (A module that
// adds a small 'rate this comment' form to
each comment in a list
// would need a unique form_id for each
one, for example.)
//
// So, we call the hook if $forms isn't yet
populated, OR if it doesn't
// yet have an entry for the requested
form_id.
if (!isset($forms) ||
!isset($forms[$form_id])) {
$forms = module_invoke_all('forms',
$saved_args);
}
$form_definition = $forms[$form_id];
if (isset($form_definition['callback
arguments'])) {
$args =
array_merge($form_definition['callback arguments'], $args);
}
if (isset($form_definition['callback'])) {
$callback = $form_definition['callback'];
}
}
// If $callback was returned by a
hook_forms() implementation, call it.
// Otherwise, call the function named after
the form id.
$form = call_user_func_array(isset($callback)
? $callback : $form_id, $args);
// We store the original function arguments,
rather than the final $arg
// value, so that form_alter functions can
see what was originally
// passed to drupal_retrieve_form(). This
allows the contents of #parameters
// to be saved and passed in at a later date
to recreate the form.
$form['#parameters'] = $saved_args;
return $form;
}
/**
* This function is the heart of form API. The
form gets built, validated and in
* appropriate cases, submitted.
*
* @param $form_id
* The
unique string identifying the current form.
* @param $form
* An
associative array containing the structure of the form.
* @return
* The
path to redirect the user to upon completion.
*/
function
drupal_process_form($form_id, &$form) {
global $form_values, $form_submitted, $user,
$form_button_counter;
static $saved_globals = array();
// In some scenarios, this function can be
called recursively. Pushing any pre-existing
// $form_values and form submission data lets
us start fresh without clobbering work done
// in earlier recursive calls.
array_push($saved_globals,
array($form_values, $form_submitted, $form_button_counter));
$form_values = array();
$form_submitted = FALSE;
$form_button_counter = array(0, 0);
drupal_prepare_form($form_id, $form);
if (($form['#programmed']) || (!empty($_POST)
&& (($_POST['form_id'] == $form_id) || ($_POST['form_id'] ==
$form['#base'])))) {
drupal_validate_form($form_id, $form);
// IE does not send a button value when
there is only one submit button (and no non-submit buttons)
// and you submit by pressing enter.
// In that case we accept a submission
without button values.
if ((($form['#programmed']) ||
$form_submitted || (!$form_button_counter[0] &&
$form_button_counter[1])) && !form_get_errors()) {
$redirect = drupal_submit_form($form_id,
$form);
if (!$form['#programmed']) {
drupal_redirect_form($form, $redirect);
}
}
}
// We've finished calling functions that
alter the global values, so we can
// restore the ones that were there before
this function was called.
list($form_values, $form_submitted,
$form_button_counter) = array_pop($saved_globals);
return $redirect;
}
/**
* Prepares a structured form array by adding
required elements,
* executing any hook_form_alter functions, and
optionally inserting
* a validation token to prevent tampering.
*
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
* @param $form
* An
associative array containing the structure of the form.
*/
function
drupal_prepare_form($form_id, &$form) {
global $user;
$form['#type'] = 'form';
if (!isset($form['#post'])) {
$form['#post'] = $_POST;
$form['#programmed'] = FALSE;
}
else {
$form['#programmed'] = TRUE;
}
// In multi-step form scenarios, this id is
used to identify
// a unique instance of a particular form for
retrieval.
if (isset($form['#build_id'])) {
$form['form_build_id'] = array(
'#type' => 'hidden',
'#value' => $form['#build_id'],
'#id' => $form['#build_id'],
'#name' => 'form_build_id',
);
}
// If $base is set, it is used in place of
$form_id when constructing validation,
// submission, and theming functions. Useful
for mapping many similar or duplicate
// forms with different $form_ids to the same
processing functions.
if (isset($form['#base'])) {
$base = $form['#base'];
}
// Add a token, based on either #token or
form_id, to any form displayed to
// authenticated users. This ensures that any
submitted form was actually
// requested previously by the user and
protects against cross site request
// forgeries.
if (isset($form['#token'])) {
if ($form['#token'] === FALSE ||
$user->uid == 0 || $form['#programmed']) {
unset($form['#token']);
}
else {
$form['form_token'] = array('#type' =>
'token', '#default_value' => drupal_get_token($form['#token']));
}
}
else if ($user->uid &&
!$form['#programmed']) {
$form['#token'] = $form_id;
$form['form_token'] = array(
'#id' => form_clean_id('edit-'.
$form_id .'-form-token'),
'#type' => 'token',
'#default_value' =>
drupal_get_token($form['#token']),
);
}
if (isset($form_id)) {
$form['form_id'] = array('#type' =>
'hidden', '#value' => $form_id, '#id' =>
form_clean_id("edit-$form_id"));
}
if (!isset($form['#id'])) {
$form['#id'] = form_clean_id($form_id);
}
$form += _element_info('form');
if (!isset($form['#validate'])) {
if (function_exists($form_id .'_validate'))
{
$form['#validate'] = array($form_id
.'_validate' => array());
}
elseif (function_exists($base
.'_validate')) {
$form['#validate'] = array($base
.'_validate' => array());
}
}
if (!isset($form['#submit'])) {
if (function_exists($form_id .'_submit')) {
// We set submit here so that it can be
altered.
$form['#submit'] = array($form_id
.'_submit' => array());
}
elseif (function_exists($base .'_submit'))
{
$form['#submit'] = array($base .'_submit'
=> array());
}
}
foreach (module_implements('form_alter') as
$module) {
$function = $module .'_form_alter';
$function($form_id, $form);
}
$form = form_builder($form_id, $form);
}
/**
* Validates user-submitted form data from a
global variable using
* the validate functions defined in a
structured form array.
*
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
* @param $form
* An
associative array containing the structure of the form.
*
*/
function
drupal_validate_form($form_id, $form) {
global $form_values;
static $validated_forms = array();
if (isset($validated_forms[$form_id])) {
return;
}
// If the session token was set by
drupal_prepare_form(), ensure that it
// matches the current user's session.
if (isset($form['#token'])) {
if
(!drupal_valid_token($form_values['form_token'], $form['#token'])) {
// Setting this error will cause the form
to fail validation.
form_set_error('form_token',
t('Validation error, please try again. If this error persists, please contact
the site administrator.'));
}
}
_form_validate($form, $form_id);
$validated_forms[$form_id] = TRUE;
}
/**
* Processes user-submitted form data from a
global variable using
* the submit functions defined in a structured
form array.
*
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
* @param $form
* An
associative array containing the structure of the form.
* @return
* A
string containing the path of the page to display when processing
* is
complete.
*
*/
function
drupal_submit_form($form_id, $form) {
global $form_values;
$default_args = array($form_id,
&$form_values);
if (isset($form['#submit'])) {
foreach ($form['#submit'] as $function
=> $args) {
if (function_exists($function)) {
$args = array_merge($default_args,
(array) $args);
// Since we can only redirect to one
page, only the last redirect
// will work.
$redirect =
call_user_func_array($function, $args);
if (isset($redirect)) {
$goto = $redirect;
}
}
}
}
return $goto;
}
/**
* Renders a structured form array into themed
HTML.
*
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
* @param $form
* An
associative array containing the structure of the form.
* @return
* A
string containing the path of the page to display when processing
* is
complete.
*
*/
function
drupal_render_form($form_id, &$form) {
// Don't override #theme if someone already
set it.
if (isset($form['#base'])) {
$base = $form['#base'];
}
if (!isset($form['#theme'])) {
if (theme_get_function($form_id)) {
$form['#theme'] = $form_id;
}
elseif (theme_get_function($base)) {
$form['#theme'] = $base;
}
}
if (isset($form['#pre_render'])) {
foreach ($form['#pre_render'] as $function)
{
if (function_exists($function)) {
$function($form_id, $form);
}
}
}
$output = drupal_render($form);
return $output;
}
/**
* Redirect the user to a URL after a form has
been processed.
*
* @param $form
* An
associative array containing the structure of the form.
* @param $redirect
* An
optional string containing the destination path to redirect
* to
if none is specified by the form.
*
*/
function drupal_redirect_form($form,
$redirect = NULL) {
if (isset($redirect)) {
$goto = $redirect;
}
if (isset($form['#redirect'])) {
$goto = $form['#redirect'];
}
if ($goto !== FALSE) {
if (is_array($goto)) {
call_user_func_array('drupal_goto',
$goto);
}
elseif (!isset($goto)) {
drupal_goto($_GET['q']);
}
else {
drupal_goto($goto);
}
}
}
/**
* Performs validation on form elements. First
ensures required fields are
* completed, #maxlength is not exceeded, and
selected options were in the
* list of options given to the user. Then
calls user-defined validators.
*
* @param $elements
* An
associative array containing the structure of the form.
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
*/
function
_form_validate($elements, $form_id = NULL) {
// Recurse through all children.
foreach (element_children($elements) as $key)
{
if (isset($elements[$key]) && $elements[$key])
{
_form_validate($elements[$key]);
}
}
/* Validate the current input */
if (!isset($elements['#validated']) ||
!$elements['#validated']) {
if (isset($elements['#needs_validation']))
{
// An empty textfield returns '' so we
use empty(). An empty checkbox
// and a textfield could return '0' and
empty('0') returns TRUE so we
// need a special check for the '0'
string.
if ($elements['#required'] &&
empty($elements['#value']) && $elements['#value'] !== '0') {
form_error($elements, t('!name field is
required.', array('!name' => $elements['#title'])));
}
// Verify that the value is not longer
than #maxlength.
if (isset($elements['#maxlength'])
&& drupal_strlen($elements['#value']) > $elements['#maxlength']) {
form_error($elements, t('!name cannot
be longer than %max characters but is currently %length characters long.',
array('!name' => empty($elements['#title']) ? $elements['#parents'][0] :
$elements['#title'], '%max' => $elements['#maxlength'], '%length' =>
drupal_strlen($elements['#value']))));
}
// Add legal choice check if element has
#options. Can be skipped, but
// then you must validate your own
element.
if (isset($elements['#options'])
&& isset($elements['#value']) &&
!isset($elements['#DANGEROUS_SKIP_CHECK'])) {
if ($elements['#type'] == 'select') {
$options =
form_options_flatten($elements['#options']);
}
else {
$options = $elements['#options'];
}
if (is_array($elements['#value'])) {
$value = $elements['#type'] ==
'checkboxes' ? array_keys(array_filter($elements['#value'])) :
$elements['#value'];
foreach ($value as $v) {
if (!isset($options[$v])) {
form_error($elements, t('An illegal
choice has been detected. Please contact the site administrator.'));
watchdog('form', t('Illegal
choice %choice in !name element.', array('%choice' => $v, '!name' =>
empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])),
WATCHDOG_ERROR);
}
}
}
elseif
(!isset($options[$elements['#value']])) {
form_error($elements, t('An illegal
choice has been detected. Please contact the site administrator.'));
watchdog('form', t('Illegal choice
%choice in %name element.', array('%choice' => $elements['#value'], '%name'
=> empty($elements['#title']) ? $elements['#parents'][0] :
$elements['#title'])), WATCHDOG_ERROR);
}
}
}
// Call user-defined validators.
if (isset($elements['#validate'])) {
foreach ($elements['#validate'] as
$function => $args) {
$args = array_merge(array($elements),
$args);
// For the full form we hand over a
copy of $form_values.
if (isset($form_id)) {
$args = array_merge(array($form_id,
$GLOBALS['form_values']), $args);
}
if (function_exists($function)) {
call_user_func_array($function,
$args);
}
}
}
$elements['#validated'] = TRUE;
}
}
/**
* File an error against a form element. If the
name of the element is
* edit[foo][bar] then you may pass either foo
or foo][bar as $name
* foo will set an error for all its children.
*/
function form_set_error($name
= NULL, $message = '') {
static $form = array();
if (isset($name) &&
!isset($form[$name])) {
$form[$name] = $message;
if ($message) {
drupal_set_message($message, 'error');
}
}
return $form;
}
/**
* Return an associative array of all errors.
*/
function form_get_errors() {
$form = form_set_error();
if (!empty($form)) {
return $form;
}
}
/**
* Return the error message filed against the
form with the specified name.
*/
function
form_get_error($element) {
$form = form_set_error();
$key = $element['#parents'][0];
if (isset($form[$key])) {
return $form[$key];
}
$key = implode('][', $element['#parents']);
if (isset($form[$key])) {
return $form[$key];
}
}
/**
* Flag an element as having an error.
*/
function
form_error(&$element, $message = '') {
$element['#error'] = TRUE;
form_set_error(implode('][',
$element['#parents']), $message);
}
/**
* Adds some required properties to each form
element, which are used
* internally in the form API. This function
also automatically assigns
* the value property from the $edit array,
provided the element doesn't
* already have an assigned value.
*
* @param $form_id
* A
unique string identifying the form for validation, submission,
*
theming, and hook_form_alter functions.
* @param $form
* An
associative array containing the structure of the form.
*/
function
form_builder($form_id, $form) {
global $form_values, $form_submitted,
$form_button_counter;
// Initialize as unprocessed.
$form['#processed'] = FALSE;
/* Use element defaults */
if ((!empty($form['#type'])) &&
($info = _element_info($form['#type']))) {
// Overlay $info onto $form, retaining
preexisting keys in $form.
$form += $info;
}
if (isset($form['#input']) &&
$form['#input']) {
if (!isset($form['#name'])) {
$name = array_shift($form['#parents']);
$form['#name'] = $name;
if ($form['#type'] == 'file') {
// To make it easier to handle $_FILES
in file.inc, we place all
// file fields in the 'files' array.
Also, we do not support
// nested file names.
$form['#name'] = 'files['.
$form['#name'] .']';
}
elseif (count($form['#parents'])) {
$form['#name'] .= '['. implode('][',
$form['#parents']) .']';
}
array_unshift($form['#parents'], $name);
}
if (!isset($form['#id'])) {
$form['#id'] = form_clean_id('edit-'.
implode('-', $form['#parents']));
}
if (isset($form['#disabled']) &&
$form['#disabled']) {
$form['#attributes']['disabled'] =
'disabled';
}
if (!isset($form['#value']) &&
!array_key_exists('#value', $form)) {
if (($form['#programmed']) ||
((!isset($form['#access']) || $form['#access']) &&
isset($form['#post']) && (isset($form['#post']['form_id']) &&
$form['#post']['form_id'] == $form_id))) {
$edit = $form['#post'];
foreach ($form['#parents'] as $parent)
{
$edit = isset($edit[$parent]) ?
$edit[$parent] : NULL;
}
if (!$form['#programmed'] || isset($edit))
{
switch ($form['#type']) {
case 'checkbox':
$form['#value'] = !empty($edit) ?
$form['#return_value'] : 0;
break;
case 'select':
if (isset($form['#multiple'])
&& $form['#multiple']) {
if (isset($edit) &&
is_array($edit)) {
$form['#value'] =
drupal_map_assoc($edit);
}
else {
$form['#value'] = array();
}
}
elseif (isset($edit)) {
$form['#value'] = $edit;
}
break;
case 'textfield':
if (isset($edit)) {
// Equate $edit to the form
value to ensure it's marked for
// validation.
$edit =
str_replace(array("\r", "\n"), '', $edit);
$form['#value'] = $edit;
}
break;
case 'token':
$form['#value'] = (string)$edit;
break;
default:
if (isset($edit)) {
$form['#value'] = $edit;
}
}
// Mark all posted values for
validation.
if ((isset($form['#value'])
&& $form['#value'] === $edit) || (isset($form['#required']) &&
$form['#required'])) {
$form['#needs_validation'] = TRUE;
}
}
}
if (!isset($form['#value'])) {
$function = $form['#type'] . '_value';
if (function_exists($function)) {
$function($form);
}
else {
$form['#value'] =
isset($form['#default_value']) ? $form['#default_value'] : '';
}
}
}
if
(isset($form['#executes_submit_callback'])) {
// Count submit and non-submit buttons.
$form_button_counter[$form['#executes_submit_callback']]++;
// See if a submit button was pressed.
if (isset($form['#post'][$form['#name']])
&& $form['#post'][$form['#name']] == $form['#value']) {
$form_submitted = $form_submitted ||
$form['#executes_submit_callback'];
// In most cases, we want to use
form_set_value() to manipulate the
// global variables. In this special
case, we want to make sure that
// the value of this element is listed
in $form_variables under 'op'.
$form_values[$form['#name']] =
$form['#value'];
}
}
}
// Allow for elements to expand to multiple
elements, e.g., radios,
// checkboxes and files.
if (isset($form['#process']) &&
!$form['#processed']) {
foreach ($form['#process'] as $process
=> $args) {
if (function_exists($process)) {
$args = array_merge(array($form),
array($edit), $args);
$form = call_user_func_array($process,
$args);
}
}
$form['#processed'] = TRUE;
}
// Set the $form_values key that gets passed
to validate and submit.
// We call this after #process gets called so
that #process has a
// chance to update #value if desired.
if (isset($form['#input']) &&
$form['#input']) {
form_set_value($form, $form['#value']);
}
// We start off assuming all form elements
are in the correct order.
$form['#sorted'] = TRUE;
// Recurse through all child elements.
$count = 0;
foreach (element_children($form) as $key) {
$form[$key]['#post'] = $form['#post'];
$form[$key]['#programmed'] =
$form['#programmed'];
// Don't squash an existing tree value.
if (!isset($form[$key]['#tree'])) {
$form[$key]['#tree'] = $form['#tree'];
}
// Deny access to child elements if parent
is denied.
if (isset($form['#access']) &&
!$form['#access']) {
$form[$key]['#access'] = FALSE;
}
// Don't squash existing parents value.
if (!isset($form[$key]['#parents'])) {
// Check to see if a tree of child
elements is present. If so,
// continue down the tree if required.
$form[$key]['#parents'] =
$form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'],
array($key)) : array($key);
}
// Assign a decimal placeholder weight to
preserve original array order.
if (!isset($form[$key]['#weight'])) {
$form[$key]['#weight'] = $count/1000;
}
else {
// If one of the child elements has a
weight then we will need to sort
// later.
unset($form['#sorted']);
}
$form[$key] = form_builder($form_id,
$form[$key]);
$count++;
}
if (isset($form['#after_build']) &&
!isset($form['#after_build_done'])) {
foreach ($form['#after_build'] as
$function) {
if (function_exists($function)) {
$form = $function($form, $form_values);
}
}
$form['#after_build_done'] = TRUE;
}
return $form;
}
/**
* Use this function to make changes to form
values in the form validate
* phase, so they will be available in the
submit phase in $form_values.
*
* Specifically, if $form['#parents'] is
array('foo', 'bar')
* and $value is 'baz' then this function will
make
* $form_values['foo']['bar'] to be 'baz'.
*
* @param $form
* The
form item. Keys used: #parents, #value
* @param $value
* The
value for the form item.
*/
function
form_set_value($form, $value) {
global $form_values;
_form_set_value($form_values, $form,
$form['#parents'], $value);
}
/**
* Helper function for form_set_value().
*
* We iterate over $parents and create nested arrays
for them
* in $form_values if needed. Then we insert
the value into
* the right array.
*/
function
_form_set_value(&$form_values, $form, $parents, $value) {
$parent = array_shift($parents);
if (empty($parents)) {
$form_values[$parent] = $value;
}
else {
if (!isset($form_values[$parent])) {
$form_values[$parent] = array();
}
_form_set_value($form_values[$parent],
$form, $parents, $value);
}
return $form;
}
/**
* Retrieve the default properties for the
defined element type.
*/
function _element_info($type,
$refresh = NULL) {
static $cache;
$basic_defaults = array(
'#description' => NULL,
'#attributes' => array(),
'#required' => FALSE,
'#tree' => FALSE,
'#parents' => array()
);
if (!isset($cache) || $refresh) {
$cache = array();
foreach (module_implements('elements') as
$module) {
$elements = module_invoke($module,
'elements');
if (isset($elements) &&
is_array($elements)) {
$cache = array_merge_recursive($cache,
$elements);
}
}
if (sizeof($cache)) {
foreach ($cache as $element_type =>
$info) {
$cache[$element_type] =
array_merge_recursive($basic_defaults, $info);
}
}
}
return $cache[$type];
}
function form_options_flatten($array,
$reset = TRUE) {
static $return;
if ($reset) {
$return = array();
}
foreach ($array as $key => $value) {
if (is_object($value)) {
form_options_flatten($value->option,
FALSE);
}
else if (is_array($value)) {
form_options_flatten($value, FALSE);
}
else {
$return[$key] = 1;
}
}
return $return;
}
/**
* Format a dropdown menu or scrolling
selection box.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value, options, description, extra, multiple,
required
* @return
* A
themed HTML string representing the form element.
*
* It is possible to group options together; to
do this, change the format of
* $options to an associative array in which
the keys are group labels, and the
* values are associative arrays in the normal
$options format.
*/
function
theme_select($element) {
$select = '';
$size = $element['#size'] ? ' size="' .
$element['#size'] . '"' : '';
_form_set_class($element,
array('form-select'));
$multiple = isset($element['#multiple'])
&& $element['#multiple'];
return theme('form_element', $element,
'<select name="'. $element['#name'] .''. ($multiple ? '[]' : '')
.'"'. ($multiple ? ' multiple="multiple" ' : '') .
drupal_attributes($element['#attributes']) .' id="'. $element['#id']
.'" '. $size .'>'. form_select_options($element) .'</select>');
}
function
form_select_options($element, $choices = NULL) {
if (!isset($choices)) {
$choices = $element['#options'];
}
// array_key_exists() accommodates the rare
event where $element['#value'] is NULL.
// isset() fails in this situation.
$value_valid = isset($element['#value']) ||
array_key_exists('#value', $element);
$value_is_array = is_array($element['#value']);
$options = '';
foreach ($choices as $key => $choice) {
if (is_array($choice)) {
$options .= '<optgroup label="'.
$key .'">';
$options .= form_select_options($element,
$choice);
$options .= '</optgroup>';
}
elseif (is_object($choice)) {
$options .= form_select_options($element,
$choice->option);
}
else {
$key = (string)$key;
if ($value_valid &&
((string)$element['#value'] === $key || ($value_is_array &&
in_array($key, $element['#value'])))) {
$selected = '
selected="selected"';
}
else {
$selected = '';
}
$options .= '<option value="'.
check_plain($key) .'"'. $selected .'>'. check_plain($choice)
.'</option>';
}
}
return $options;
}
/**
* Traverses a select element's #option array
looking for any values
* that hold the given key. Returns an array of
indexes that match.
*
* This function is useful if you need to
modify the options that are
* already in a form element; for example, to
remove choices which are
* not valid because of additional filters
imposed by another module.
* One example might be altering the choices in
a taxonomy selector.
* To correctly handle the case of a multiple
hierarchy taxonomy,
* #options arrays can now hold an array of
objects, instead of a
* direct mapping of keys to labels, so that
multiple choices in the
* selector can have the same key (and label).
This makes it difficult
* to manipulate directly, which is why this
helper function exists.
*
* This function does not support optgroups
(when the elements of the
* #options array are themselves arrays), and
will return FALSE if
* arrays are found. The caller must either
flatten/restore or
* manually do their manipulations in this
case, since returning the
* index is not sufficient, and supporting this
would make the
* "helper" too complicated and
cumbersome to be of any help.
*
* As usual with functions that can return
array() or FALSE, do not
* forget to use === and !== if needed.
*
* @param $element
* The
select element to search.
* @param $key
* The
key to look for.
* @return
* An
array of indexes that match the given $key. Array will be
*
empty if no elements were found. FALSE if optgroups were found.
*/
function form_get_options($element,
$key) {
$keys = array();
foreach ($element['#options'] as $index =>
$choice) {
if (is_array($choice)) {
return FALSE;
}
else if (is_object($choice)) {
if (isset($choice->option[$key])) {
$keys[] = $index;
}
}
else if ($index == $key) {
$keys[] = $index;
}
}
return $keys;
}
/**
* Format a group of form items.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: attributes, title, value, description, children,
collapsible, collapsed
* @return
* A
themed HTML string representing the form item group.
*/
function
theme_fieldset($element) {
if ($element['#collapsible']) {
drupal_add_js('misc/collapse.js');
if
(!isset($element['#attributes']['class'])) {
$element['#attributes']['class'] = '';
}
$element['#attributes']['class'] .= '
collapsible';
if ($element['#collapsed']) {
$element['#attributes']['class'] .= '
collapsed';
}
}
return '<fieldset' .
drupal_attributes($element['#attributes']) .'>' . ($element['#title'] ?
'<legend>'. $element['#title'] .'</legend>' : '') .
($element['#description'] ? '<div class="description">'.
$element['#description'] .'</div>' : '') . $element['#children'] .
$element['#value'] . "</fieldset>\n";
}
/**
* Format a radio button.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: required, return_value, value, attributes, title, description
* @return
* A
themed HTML string representing the form item group.
*/
function
theme_radio($element) {
_form_set_class($element,
array('form-radio'));
$output = '<input type="radio"
';
$output .= 'name="' . $element['#name']
.'" ';
$output .= 'value="'.
$element['#return_value'] .'" ';
$output .= (check_plain($element['#value'])
== $element['#return_value']) ? ' checked="checked" ' : ' ';
$output .=
drupal_attributes($element['#attributes']) .' />';
if (!is_null($element['#title'])) {
$output = '<label
class="option">'. $output .' '. $element['#title']
.'</label>';
}
unset($element['#title']);
return theme('form_element', $element,
$output);
}
/**
* Format a set of radio buttons.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value, options, description, required and
attributes.
* @return
* A
themed HTML string representing the radio button set.
*/
function
theme_radios($element) {
$class = 'form-radios';
if (isset($element['#attributes']['class']))
{
$class .= ' '.
$element['#attributes']['class'];
}
$element['#children'] = '<div
class="'. $class .'">'. $element['#children'] .'</div>';
if ($element['#title'] ||
$element['#description']) {
unset($element['#id']);
return theme('form_element', $element,
$element['#children']);
}
else {
return $element['#children'];
}
}
/**
* Format a password_confirm item.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value, id, required, error.
* @return
* A
themed HTML string representing the form item.
*/
function
theme_password_confirm($element) {
return theme('form_element', $element,
$element['#children']);
}
/*
* Expand a password_confirm field into two
text boxes.
*
* Added #maxlength to password fields - CF
*/
function
expand_password_confirm($element) {
$element['pass1'] = array(
'#type' => 'password',
'#title' => t('Password'),
'#value' => $element['#value']['pass1'],
'#maxlength' => 12,
);
$element['pass2'] = array(
'#type' => 'password',
'#title' => t('Confirm password'),
'#value' => $element['#value']['pass2'],
'#maxlength' => 12,
);
$element['#validate'] =
array('password_confirm_validate' => array());
$element['#tree'] = TRUE;
if (isset($element['#size'])) {
$element['pass1']['#size'] =
$element['pass2']['#size'] = $element['#size'];
}
return $element;
}
/**
* Validate password_confirm element.
*/
function
password_confirm_validate($form) {
$pass1 = trim($form['pass1']['#value']);
if ( $form['#required'] )
{
if (!empty($pass1)) {
$pass2 = trim($form['pass2']['#value']);
if ($pass1 != $pass2) {
form_error($form, t('The specified
passwords do not match.'));
}
}
elseif ($form['#required'] &&
!empty($form['#post'])) {
form_error($form, t('Password field is
required.'));
}
if(!(ctype_alnum($pass1) &&
strlen($pass1)>5 && strlen($pass1)<13
&&
preg_match('`[0-9]`',$pass1) && (preg_match('`[A-Z]`',$pass1)
||
preg_match('`[a-z]`',$pass1))) )
{
form_error($form, t('The password must be
6-12 characters in length and contain at least one digit and one character.'));
}
}
else
{
if (!empty($pass1))
{
$pass2 =
trim($form['pass2']['#value']);
if ($pass1 != $pass2) {
form_error($form, t('The specified
passwords do not match.'));
}
if(!(ctype_alnum($pass1) &&
strlen($pass1)>5 && strlen($pass1)<13
&&
preg_match('`[0-9]`',$pass1) && (preg_match('`[A-Z]`',$pass1)
||
preg_match('`[a-z]`',$pass1))) )
{
form_error($form, t('The password must be
6-12 characters in length and contain at least one digit and one character.'));
}
}
}
// Password field must be converted from a
two-element array into a single
// string regardless of validation results.
form_set_value($form['pass1'], NULL);
form_set_value($form['pass2'], NULL);
form_set_value($form, $pass1);
return $form;
}
/**
* Format a date selection element.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value, options, description, required and
attributes.
* @return
* A
themed HTML string representing the date selection boxes.
*/
function theme_date($element)
{
return theme('form_element', $element,
'<div class="container-inline">'. $element['#children']
.'</div>');
}
/**
* Roll out a single date element.
*/
function
expand_date($element) {
// Default to current date
if (!isset($element['#value'])) {
$element['#value'] = array('day' =>
format_date(time(), 'custom', 'j'),
'month' =>
format_date(time(), 'custom', 'n'),
'year' =>
format_date(time(), 'custom', 'Y'));
}
$element['#tree'] = TRUE;
// Determine the order of day, month, year in
the site's chosen date format.
$format = variable_get('date_format_short',
'm/d/Y - H:i');
$sort =
array();
$sort['day'] = max(strpos($format, 'd'),
strpos($format, 'j'));
$sort['month'] = max(strpos($format, 'm'),
strpos($format, 'M'));
$sort['year'] = strpos($format, 'Y');
asort($sort);
$order = array_keys($sort);
// Output multi-selector for date.
foreach ($order as $type) {
switch ($type) {
case 'day':
$options = drupal_map_assoc(range(1,
31));
break;
case 'month':
$options = drupal_map_assoc(range(1,
12), 'map_month');
break;
case 'year':
$options = drupal_map_assoc(range(1900,
2050));
break;
}
$parents = $element['#parents'];
$parents[] = $type;
$element[$type] = array(
'#type' => 'select',
'#value' => $element['#value'][$type],
'#attributes' =>
$element['#attributes'],
'#options' => $options,
);
}
return $element;
}
/**
* Validates the date type to stop dates like
February 30, 2006.
*/
function date_validate($form)
{
if (!checkdate($form['#value']['month'],
$form['#value']['day'], $form['#value']['year'])) {
form_error($form, t('The specified date is
invalid.'));
}
}
/**
* Helper function for usage with
drupal_map_assoc to display month names.
*/
function map_month($month) {
return format_date(gmmktime(0, 0, 0, $month,
2, 1970), 'custom', 'M', 0);
}
/**
* Helper function to load value from default
value for checkboxes.
*/
function
checkboxes_value(&$form) {
$value = array();
foreach ((array)$form['#default_value'] as
$key) {
$value[$key] = 1;
}
$form['#value'] = $value;
}
/**
* If no default value is set for weight select
boxes, use 0.
*/
function
weight_value(&$form) {
if (isset($form['#default_value'])) {
$form['#value'] = $form['#default_value'];
}
else {
$form['#value'] = 0;
}
}
/**
* Roll out a single radios element to a list
of radios,
* using the options array as index.
*/
function
expand_radios($element) {
if (count($element['#options']) > 0) {
foreach ($element['#options'] as $key =>
$choice) {
if (!isset($element[$key])) {
$element[$key] = array('#type' =>
'radio', '#title' => $choice, '#return_value' => check_plain($key),
'#default_value' => $element['#default_value'], '#attributes' =>
$element['#attributes'], '#parents' => $element['#parents'], '#spawned'
=> TRUE);
}
}
}
return $element;
}
/**
* Format a form item.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value,
description, required, error
* @return
* A
themed HTML string representing the form item.
*/
function theme_item($element)
{
return theme('form_element', $element,
$element['#value'] . $element['#children']);
}
/**
* Format a checkbox.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value,
return_value, description, required
* @return
* A
themed HTML string representing the checkbox.
*/
function
theme_checkbox($element) {
_form_set_class($element,
array('form-checkbox'));
$checkbox = '<input ';
$checkbox .= 'type="checkbox" ';
$checkbox .= 'name="'. $element['#name']
.'" ';
$checkbox .= 'id="'.
$element['#id'].'" ' ;
$checkbox .= 'value="'.
$element['#return_value'] .'" ';
$checkbox .= $element['#value'] ? '
checked="checked" ' : ' ';
$checkbox .=
drupal_attributes($element['#attributes']) . ' />';
if (!is_null($element['#title'])) {
$checkbox = '<label
class="option">'. $checkbox .' '. $element['#title']
.'</label>';
}
unset($element['#title']);
return theme('form_element', $element,
$checkbox);
}
/**
* Format a set of checkboxes.
*
* @param $element
* An
associative array containing the properties of the element.
* @return
* A
themed HTML string representing the checkbox set.
*/
function
theme_checkboxes($element) {
$class = 'form-checkboxes';
if (isset($element['#attributes']['class']))
{
$class .= ' '.
$element['#attributes']['class'];
}
$element['#children'] = '<div
class="'. $class .'">'. $element['#children'] .'</div>';
if ($element['#title'] ||
$element['#description']) {
unset($element['#id']);
return theme('form_element', $element,
$element['#children']);
}
else {
return $element['#children'];
}
}
function expand_checkboxes($element)
{
$value = is_array($element['#value']) ?
$element['#value'] : array();
$element['#tree'] = TRUE;
if (count($element['#options']) > 0) {
if (!isset($element['#default_value']) ||
$element['#default_value'] == 0) {
$element['#default_value'] = array();
}
foreach ($element['#options'] as $key =>
$choice) {
if (!isset($element[$key])) {
$element[$key] = array('#type' =>
'checkbox', '#processed' => TRUE, '#title' => $choice, '#return_value'
=> $key, '#default_value' => isset($value[$key]), '#attributes' =>
$element['#attributes']);
}
}
}
return $element;
}
function
theme_submit($element) {
return theme('button', $element);
}
function
theme_button($element) {
// Make sure not to overwrite classes.
if (isset($element['#attributes']['class']))
{
$element['#attributes']['class'] = 'form-'.
$element['#button_type'] .' '. $element['#attributes']['class'];
}
else {
$element['#attributes']['class'] = 'form-'.
$element['#button_type'];
}
return '<input type="submit" '.
(empty($element['#name']) ? '' : 'name="'. $element['#name'] .'"
') .'id="'. $element['#id'].'"
value="'. check_plain($element['#value']) .'" '.
drupal_attributes($element['#attributes']) ." />\n";
}
/**
* Format a hidden form field.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: value, edit
* @return
* A
themed HTML string representing the hidden form field.
*/
function
theme_hidden($element) {
return '<input type="hidden"
name="'. $element['#name'] . '" id="'. $element['#id'] . '"
value="'. check_plain($element['#value']) ."\" " .
drupal_attributes($element['#attributes']) ." />\n";
}
function
theme_token($element) {
return theme('hidden', $element);
}
/**
* Format a textfield.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value,
description, size, maxlength, required, attributes autocomplete_path
* @return
* A themed
HTML string representing the textfield.
*/
function
theme_textfield($element) {
$size = $element['#size'] ? ' size="' .
$element['#size'] . '"' : '';
$class = array('form-text');
$extra = '';
$output = '';
if ($element['#autocomplete_path']) {
drupal_add_js('misc/autocomplete.js');
$class[] = 'form-autocomplete';
$extra =
'<input class="autocomplete" type="hidden"
id="'. $element['#id'] .'-autocomplete" value="'.
check_url(url($element['#autocomplete_path'], NULL, NULL, TRUE)) .'"
disabled="disabled" />';
}
_form_set_class($element, $class);
if (isset($element['#field_prefix'])) {
$output .= '<span
class="field-prefix">'. $element['#field_prefix'] .'</span>
';
}
$output .= '<input type="text"
maxlength="'. $element['#maxlength'] .'" name="'.
$element['#name'] .'" id="'. $element['#id'] .'" '. $size .'
value="'. check_plain($element['#value']) .'"'.
drupal_attributes($element['#attributes']) .' />';
if (isset($element['#field_suffix'])) {
$output .= ' <span
class="field-suffix">'. $element['#field_suffix']
.'</span>';
}
return theme('form_element', $element,
$output). $extra;
}
/**
* Format a form.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: action, method, attributes, children
* @return
* A
themed HTML string representing the form.
*/
function theme_form($element)
{
// Anonymous div to satisfy XHTML compliance.
$action = $element['#action'] ?
'action="' . check_url($element['#action']) . '" ' : '';
return '<form '. $action . '
method="'. $element['#method'] .'" '. 'id="'. $element['#id']
.'"'. drupal_attributes($element['#attributes'])
.">\n<div>". $element['#children']
."\n</div></form>\n";
}
/**
* Format a textarea.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: title, value, description, rows, cols, required,
attributes
* @return
* A
themed HTML string representing the textarea.
*/
function theme_textarea($element)
{
$class = array('form-textarea');
if ($element['#resizable'] !== FALSE) {
drupal_add_js('misc/textarea.js');
$class[] = 'resizable';
}
$cols = $element['#cols'] ? ' cols="'.
$element['#cols'] .'"' : '';
_form_set_class($element, $class);
return theme('form_element', $element,
'<textarea'. $cols .' rows="'. $element['#rows'] .'" name="'.
$element['#name'] .'" id="'. $element['#id'] .'" '.
drupal_attributes($element['#attributes']) .'>'.
check_plain($element['#value']) .'</textarea>');
}
/**
* Format HTML markup for use in forms.
*
* This is used in more advanced forms, such as
theme selection and filter format.
*
* @param $element
* An
associative array containing the properties of the element.
*
Properties used: value, children.
* @return
* A
themed HTML string representing the HTML markup.
*/
function
theme_markup($element) {
return (isset($element['#value']) ?
$element['#value'] : '') . (isset($element['#children']) ?
$element['#children'] : '');
}
/**
* Format a password field.
*
* @param $element
* An associative array containing the
properties of the element.
* Properties used: title, value, description, size, maxlength,
required, attributes
* @return
* A themed HTML string representing the form.
*/
function
theme_password($element) {
$size = $element['#size'] ? ' size="'.
$element['#size'] .'" ' : '';
$maxlength = $element['#maxlength'] ? '
maxlength="'. $element['#maxlength'] .'" ' : '';
_form_set_class($element,
array('form-text'));
$output = '<input
type="password" name="'. $element['#name'] .'" id="'.
$element['#id'] .'" '. $maxlength . $size .
drupal_attributes($element['#attributes']) .' />';
return theme('form_element', $element,
$output);
}
/**
* Expand weight elements into selects.
*/
function
process_weight($element) {
for ($n = (-1 * $element['#delta']); $n <=
$element['#delta']; $n++) {
$weights[$n] = $n;
}
$element['#options'] = $weights;
$element['#type'] = 'select';
$element['#is_weight'] = TRUE;
return $element;
}
/**
* Format a file upload field.
*
* @param $title
* The
label for the file upload field.
* @param $name
* The
internal name used to refer to the field.
* @param $size
* A
measure of the visible size of the field (passed directly to HTML).
* @param $description
*
Explanatory text to display after the form item.
* @param $required
*
Whether the user must upload a file to the field.
* @return
* A
themed HTML string representing the field.
*
* For assistance with handling the uploaded
file correctly, see the API
* provided by file.inc.
*/
function theme_file($element)
{
_form_set_class($element,
array('form-file'));
return theme('form_element', $element,
'<input type="file" name="'. $element['#name'] .'"'. ($element['#attributes']
? ' '. drupal_attributes($element['#attributes']) : '') .' id="'.
$element['#id'] .'" size="'. $element['#size'] ."\"
/>\n");
}
/**
* Return a themed form element.
*
* @param element
* An
associative array containing the properties of the element.
*
Properties used: title, description, id, required
* @param $value
* The
form element's data.
* @return
* A
string representing the form element.
*/
function
theme_form_element($element, $value) {
$output
= '<div class="form-item">'."\n";
$required = !empty($element['#required']) ?
'<span class="form-required" title="'. t('This field is
required.') .'">*</span>' : '';
if (!empty($element['#title'])) {
$title = $element['#title'];
if (!empty($element['#id'])) {
$output .= ' <label for="'.
$element['#id'] .'">'. t('!title: !required', array('!title' =>
filter_xss_admin($title), '!required' => $required))
."</label>\n";
}
else {
$output .= ' <label>'. t('!title:
!required', array('!title' => filter_xss_admin($title), '!required' =>
$required)) ."</label>\n";
}
}
$output .= " $value\n";
if (!empty($element['#description'])) {
$output .= ' <div
class="description">'. $element['#description']
."</div>\n";
}
$output .= "</div>\n";
return $output;
}
/**
* Sets a form element's class attribute.
*
* Adds 'required' and 'error' classes as
needed.
*
* @param &$element
* The
form element.
* @param $name
*
Array of new class names to be added.
*/
function _form_set_class(&$element,
$class = array()) {
if ($element['#required']) {
$class[] = 'required';
}
if (form_get_error($element)){
$class[] = 'error';
}
if (isset($element['#attributes']['class']))
{
$class[] =
$element['#attributes']['class'];
}
$element['#attributes']['class'] = implode('
', $class);
}
/**
* Remove invalid characters from an HTML ID
attribute string.
*
* @param $id
* The
ID to clean.
* @return
* The
cleaned ID.
*/
function form_clean_id($id =
NULL) {
$id = str_replace(array('][', '_', ' '), '-',
$id);
return $id;
}
/**
* @} End of "defgroup form".
*/
COMMON.INC
<?php
// $Id: common.inc,v 1.611
2007/01/10 23:30:07 unconed Exp $
/**
* @file
* Common functions that many Drupal modules
will need to reference.
*
* The functions that are critical and need to
be available even when serving
* a cached page are instead located in
bootstrap.inc.
*/
/**
* Return status for saving which involved
creating a new item.
*/
define('SAVED_NEW', 1);
/**
* Return status for saving which involved an
update to an existing item.
*/
define('SAVED_UPDATED', 2);
/**
* Return status for saving which deleted an
existing item.
*/
define('SAVED_DELETED', 3);
/**
* Set content for a specified region.
*
* @param $region
* Page
region the content is assigned to.
*
* @param $data
*
Content to be set.
*/
function
drupal_set_content($region = NULL, $data = NULL) {
static $content = array();
if (!is_null($region) &&
!is_null($data)) {
$content[$region][] = $data;
}
return $content;
}
/**
* Get assigned content.
*
* @param $region
* A
specified region to fetch content for. If NULL, all regions will be returned.
*
* @param $delimiter
*
Content to be inserted between exploded array elements.
*/
function
drupal_get_content($region = NULL, $delimiter = ' ') {
$content = drupal_set_content();
if (isset($region)) {
if (isset($content[$region]) &&
is_array($content[$region])) {
return implode($delimiter,
$content[$region]);
}
}
else {
foreach (array_keys($content) as $region) {
if (is_array($content[$region])) {
$content[$region] = implode($delimiter,
$content[$region]);
}
}
return $content;
}
}
/**
* Set the breadcrumb trail for the current
page.
*
* @param $breadcrumb
*
Array of links, starting with "home" and proceeding up to but
not including
* the
current page.
*/
function
drupal_set_breadcrumb($breadcrumb = NULL) {
static $stored_breadcrumb;
if (!is_null($breadcrumb)) {
$stored_breadcrumb = $breadcrumb;
}
return $stored_breadcrumb;
}
/**
* Get the breadcrumb trail for the current
page.
*/
function
drupal_get_breadcrumb() {
$breadcrumb = drupal_set_breadcrumb();
if (is_null($breadcrumb)) {
$breadcrumb = menu_get_active_breadcrumb();
}
return $breadcrumb;
}
/**
* Add output to the head tag of the HTML page.
* This function can be called as long the
headers aren't sent.
*/
function
drupal_set_html_head($data = NULL) {
static $stored_head = '';
if (!is_null($data)) {
$stored_head .= $data ."\n";
}
return $stored_head;
}
/**
* Retrieve output to be displayed in the head
tag of the HTML page.
*/
function
drupal_get_html_head() {
$output = "<meta
http-equiv=\"Content-Type\" content=\"text/html;
charset=utf-8\" />\n";
return $output . drupal_set_html_head();
}
/**
* Reset the static variable which holds the
aliases mapped for this request.
*/
function
drupal_clear_path_cache() {
drupal_lookup_path('wipe');
}
/**
* Set an HTTP response header for the current
page.
*
* Note: when sending a Content-Type header,
always include a 'charset' type
* too. This is necessary to avoid security
bugs (e.g. UTF-7 XSS).
*/
function
drupal_set_header($header = NULL) {
// We use an array to guarantee there are no
leading or trailing delimiters.
// Otherwise, header('') could get called
when serving the page later, which
// ends HTTP headers prematurely on some PHP
versions.
static $stored_headers = array();
if (strlen($header)) {
header($header);
$stored_headers[] = $header;
}
return implode("\n",
$stored_headers);
}
/**
* Get the HTTP response headers for the
current page.
*/
function drupal_get_headers()
{
return drupal_set_header();
}
/**
* Add a feed URL for the current page.
*
* @param $url
* The
url for the feed
* @param $title
* The
title of the feed
*/
function drupal_add_feed($url
= NULL, $title = '') {
static $stored_feed_links = array();
if (!is_null($url)) {
$stored_feed_links[$url] = theme('feed_icon',
$url);
drupal_add_link(array('rel' =>
'alternate',
'type' =>
'application/rss+xml',
'title' => $title,
'href' => $url));
}
return $stored_feed_links;
}
/**
* Get the feed URLs for the current page.
*
* @param $delimiter
* The
delimiter to split feeds by
*/
function
drupal_get_feeds($delimiter = "\n") {
$feeds = drupal_add_feed();
return implode($feeds, $delimiter);
}
/**
* @name HTTP handling
* @{
* Functions to properly handle HTTP responses.
*/
/**
* Parse an array into a valid urlencoded query
string.
*
* @param $query
* The
array to be processed e.g. $_GET
* @param $exclude
* The
array filled with keys to be excluded. Use parent[child] to exclude nested
items.
* @param $urlencode
* If
TRUE, the keys and values are both urlencoded.
* @param $parent
*
Should not be passed, only used in recursive calls
* @return
*
urlencoded string which can be appended to/as the URL query string
*/
function
drupal_query_string_encode($query, $exclude = array(), $parent = '') {
$params = array();
foreach ($query as $key => $value) {
$key = drupal_urlencode($key);
if ($parent) {
$key = $parent .'['. $key .']';
}
if (in_array($key, $exclude)) {
continue;
}
if (is_array($value)) {
$params[] =
drupal_query_string_encode($value, $exclude, $key);
}
else {
$params[] = $key .'='.
drupal_urlencode($value);
}
}
return implode('&', $params);
}
/**
* Prepare a destination query string for use
in combination with
* drupal_goto(). Used to direct the user back
to the referring page
* after completing a form. By default the
current URL is returned.
* If a destination exists in the previous
request, that destination
* is returned. As such, a destination can
persist across multiple
* pages.
*
* @see drupal_goto()
*/
function
drupal_get_destination() {
if (isset($_REQUEST['destination'])) {
return 'destination='. urlencode($_REQUEST['destination']);
}
else {
// Use $_GET here to retrieve the original
path in source form.
$path = isset($_GET['q']) ? $_GET['q'] :
'';
$query = drupal_query_string_encode($_GET,
array('q'));
if ($query != '') {
$path .= '?'. $query;
}
return 'destination='. urlencode($path);
}
}
/**
* Send the user to a different Drupal page.
*
* This issues an on-site HTTP redirect. The
function makes sure the redirected
* URL is formatted correctly.
*
* Usually the redirected URL is constructed
from this function's input
* parameters. However you may override that
behavior by setting a
* <em>destination</em> in either
the $_REQUEST-array (i.e. by using
* the query string of an URI) or the
$_REQUEST['edit']-array (i.e. by
* using a hidden form field). This is used to
direct the user back to
* the proper page after completing a form. For
example, after editing
* a post on the 'admin/content/node'-page or
after having logged on using the
* 'user login'-block in a sidebar. The
function drupal_get_destination()
* can be used to help set the destination URL.
*
* It is advised to use drupal_goto() instead
of PHP's header(), because
* drupal_goto() will append the user's session
ID to the URI when PHP is
* compiled with
"--enable-trans-sid".
*
* This function ends the request; use it
rather than a print theme('page')
* statement in your menu callback.
*
* @param $path
* A
Drupal path or a full URL.
* @param $query
* The
query string component, if any.
* @param $fragment
* The
destination fragment identifier (named anchor).
* @param $http_response_code
*
Valid values for an actual "goto" as per RFC 2616 section 10.3
are:
* -
301 Moved Permanently (the recommended value for most redirects)
* -
302 Found (default in Drupal and PHP, sometimes used for spamming search
*
engines)
* -
303 See Other
* -
304 Not Modified
* -
305 Use Proxy
* -
307 Temporary Redirect (an alternative to "503 Site Down for
Maintenance")
*
Note: Other values are defined by RFC 2616, but are rarely used and
poorly
*
supported.
* @see drupal_get_destination()
*/
function drupal_goto($path =
'', $query = NULL, $fragment = NULL, $http_response_code = 302) {
if (isset($_REQUEST['destination'])) {
extract(parse_url(urldecode($_REQUEST['destination'])));
}
else if
(isset($_REQUEST['edit']['destination'])) {
extract(parse_url(urldecode($_REQUEST['edit']['destination'])));
}
$url = url($path, $query, $fragment, TRUE);
// Before the redirect, allow modules to
react to the end of the page request.
module_invoke_all('exit', $url);
header('Location: '. $url, TRUE,
$http_response_code);
// The "Location" header sends a
REDIRECT status code to the http
// daemon. In some cases this can go wrong,
so we make sure none
// of the code below the drupal_goto() call
gets executed when we redirect.
exit();
}
/**
* Generates a site off-line message
*/
function
drupal_site_offline() {
drupal_set_header('HTTP/1.1 503 Service unavailable');
drupal_set_title(t('Site off-line'));
print theme('maintenance_page',
filter_xss_admin(variable_get('site_offline_message',
t('@site is currently under maintenance. We
should be back shortly. Thank you for your patience.', array('@site' =>
variable_get('site_name', 'Drupal'))))));
}
/**
* Generates a 404 error if the request can not
be handled.
*/
function drupal_not_found() {
drupal_set_header('HTTP/1.1 404 Not Found');
watchdog('page not found',
check_plain($_GET['q']), WATCHDOG_WARNING);
// Keep old path for reference
if (!isset($_REQUEST['destination'])) {
$_REQUEST['destination'] = $_GET['q'];
}
$path =
drupal_get_normal_path(variable_get('site_404', ''));
if ($path && $path != $_GET['q']) {
menu_set_active_item($path);
$return = menu_execute_active_handler();
}
else {
// Redirect to a non-existent menu item to
make possible tabs disappear.
menu_set_active_item('');
}
if (empty($return)) {
drupal_set_title(t('Page not found'));
}
// To conserve CPU and bandwidth, omit the
blocks
print theme('page', $return, FALSE);
}
/**
* Generates a 403 error if the request is not
allowed.
*/
function
drupal_access_denied() {
drupal_set_header('HTTP/1.1 403 Forbidden');
watchdog('access denied',
check_plain($_GET['q']), WATCHDOG_WARNING);
// Keep old path for
reference
if (!isset($_REQUEST['destination'])) {
$_REQUEST['destination'] = $_GET['q'];
}
$path =
drupal_get_normal_path(variable_get('site_403', ''));
if ($path && $path != $_GET['q']) {
menu_set_active_item($path);
$return = menu_execute_active_handler();
}
else {
// Redirect to a non-existent menu item to
make possible tabs disappear.
menu_set_active_item('');
}
if (empty($return)) {
drupal_set_title(t('Access denied'));
$return = t('You are not authorized to
access this page.');
}
print theme('page', $return);
}
/**
* Perform an HTTP request.
*
* This is a flexible and powerful HTTP client
implementation. Correctly handles
* GET, POST, PUT or any other HTTP requests.
Handles redirects.
*
* @param $url
* A
string containing a fully qualified URI.
* @param $headers
* An
array containing an HTTP header => value pair.
* @param $method
* A
string defining the HTTP request to use.
* @param $data
* A
string containing data to include in the request.
* @param $retry
* An
integer representing how many times to retry the request in case of a
*
redirect.
* @return
* An
object containing the HTTP request headers, response code, headers,
*
data, and redirect status.
*/
function
drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL,
$retry = 3) {
$result = new stdClass();
// Parse the URL, and make sure we can handle
the schema.
$uri =
parse_url($url);
switch ($uri['scheme']) {
case 'http':
$port = isset($uri['port']) ?
$uri['port'] : 80;
$host = $uri['host'] . ($port != 80 ?
':'. $port : '');
$fp = @fsockopen($uri['host'], $port,
$errno, $errstr, 15);
break;
case 'https':
// Note: Only works for PHP 4.3 compiled
with OpenSSL.
$port = isset($uri['port']) ?
$uri['port'] : 443;
$host = $uri['host'] . ($port != 443 ?
':'. $port : '');
$fp = @fsockopen('ssl://'. $uri['host'],
$port, $errno, $errstr, 20);
break;
default:
$result->error = 'invalid schema '.
$uri['scheme'];
return $result;
}
// Make sure the socket opened properly.
if (!$fp) {
$result->error = trim($errno .' '.
$errstr);
return $result;
}
// Construct the path to act on.
$path = isset($uri['path']) ? $uri['path'] :
'/';
if (isset($uri['query'])) {
$path .= '?'. $uri['query'];
}
// Create HTTP request.
$defaults = array(
// RFC 2616: "non-standard ports MUST,
default ports MAY be included".
// We don't add the port to prevent from
breaking rewrite rules checking
// the host that do not take into account
the port number.
'Host' => "Host: $host",
'User-Agent' => 'User-Agent: Drupal
(+http://drupal.org/)',
'Content-Length' => 'Content-Length: '.
strlen($data)
);
foreach ($headers as $header => $value) {
$defaults[$header] = $header .': '. $value;
}
$request = $method .' '. $path ."
HTTP/1.0\r\n";
$request .= implode("\r\n", $defaults);
$request .= "\r\n\r\n";
if ($data) {
$request .= $data ."\r\n";
}
$result->request = $request;
fwrite($fp, $request);
// Fetch response.
$response = '';
while (!feof($fp) && $chunk =
fread($fp, 1024)) {
$response .= $chunk;
}
fclose($fp);
// Parse response.
list($split, $result->data) =
explode("\r\n\r\n", $response, 2);
$split = preg_split("/\r\n|\n|\r/",
$split);
list($protocol, $code, $text) = explode(' ',
trim(array_shift($split)), 3);
$result->headers = array();
// Parse headers.
while ($line = trim(array_shift($split))) {
list($header, $value) = explode(':', $line,
2);
if (isset($result->headers[$header])
&& $header == 'Set-Cookie') {
// RFC 2109: the Set-Cookie response
header comprises the token Set-
// Cookie:, followed by a comma-separated
list of one or more cookies.
$result->headers[$header] .= ','.
trim($value);
}
else {
$result->headers[$header] =
trim($value);
}
}
$responses = array(
100 => 'Continue', 101 => 'Switching
Protocols',
200 => 'OK', 201 => 'Created', 202
=> 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No
Content', 205 => 'Reset Content', 206 => 'Partial Content',
300 => 'Multiple Choices', 301 =>
'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not
Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
400 => 'Bad Request', 401 =>
'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 =>
'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407
=> 'Proxy Authentication Required', 408 => 'Request Time-out', 409 =>
'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 =>
'Precondition Failed', 413 => 'Request Entity Too Large', 414 =>
'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 =>
'Requested range not satisfiable', 417 => 'Expectation Failed',
500 => 'Internal Server Error', 501
=> 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service
Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not
supported'
);
// RFC 2616 states that all unknown HTTP
codes must be treated the same as
// the base code in their class.
if (!isset($responses[$code])) {
$code = floor($code / 100) * 100;
}
switch ($code) {
case 200: // OK
case 304: // Not modified
break;
case 301: // Moved permanently
case 302: // Moved temporarily
case 307: // Moved temporarily
$location =
$result->headers['Location'];
if ($retry) {
$result = drupal_http_request($result->headers['Location'],
$headers, $method, $data, --$retry);
$result->redirect_code =
$result->code;
}
$result->redirect_url = $location;
break;
default:
$result->error = $text;
}
$result->code = $code;
return $result;
}
/**
* @} End of "HTTP handling".
*/
/**
* Log errors as defined by administrator
* Error levels:
* 0 =
Log errors to database.
* 1 =
Log errors to database and to screen.
*/
function
error_handler($errno, $message, $filename, $line) {
// If the @ error suppression operator was
used, error_reporting is temporarily set to 0
if (error_reporting() == 0) {
return;
}
if ($errno & (E_ALL ^ E_NOTICE)) {
$types = array(1 => 'error', 2 =>
'warning', 4 => 'parse error', 8 => 'notice', 16 => 'core error', 32
=> 'core warning', 64 => 'compile error', 128 => 'compile warning',
256 => 'user error', 512 => 'user warning', 1024 => 'user notice',
2048 => 'strict warning');
$entry = $types[$errno] .': '. $message .'
in '. $filename .' on line '. $line .'.';
// Force display of error messages in
update.php
if (variable_get('error_level', 1) == 1 ||
strstr($_SERVER['PHP_SELF'], 'update.php')) {
drupal_set_message($entry, 'error');
}
watchdog('php', t('%message in %file on
line %line.', array('%error' => $types[$errno], '%message' => $message,
'%file' => $filename, '%line' => $line)), WATCHDOG_ERROR);
}
}
function
_fix_gpc_magic(&$item) {
if (is_array($item)) {
array_walk($item, '_fix_gpc_magic');
}
else {
$item = stripslashes($item);
}
}
/**
* Helper function to strip slashes from
$_FILES skipping over the tmp_name keys
* since PHP generates single backslashes for
file paths on Windows systems.
*
* tmp_name does not have backslashes added see
*
http://php.net/manual/en/features.file-upload.php#42280
*/
function
_fix_gpc_magic_files(&$item, $key) {
if ($key != 'tmp_name') {
if (is_array($item)) {
array_walk($item,
'_fix_gpc_magic_files');
}
else {
$item = stripslashes($item);
}
}
}
/**
* Correct double-escaping problems caused by
"magic quotes" in some PHP
* installations.
*/
function fix_gpc_magic() {
static $fixed = FALSE;
if (!$fixed &&
ini_get('magic_quotes_gpc')) {
array_walk($_GET, '_fix_gpc_magic');
array_walk($_POST, '_fix_gpc_magic');
array_walk($_COOKIE, '_fix_gpc_magic');
array_walk($_REQUEST, '_fix_gpc_magic');
array_walk($_FILES,
'_fix_gpc_magic_files');
$fixed = TRUE;
}
}
/**
* Initialize the localization system.
*/
function locale_initialize()
{
global $user;
if (function_exists('i18n_get_lang')) {
return i18n_get_lang();
}
if (function_exists('locale')) {
$languages = locale_supported_languages();
$languages = $languages['name'];
}
else {
// Ensure the locale/language is correctly
returned, even without locale.module.
// Useful for e.g. XML/HTML 'lang'
attributes.
$languages = array('en' => 'English');
}
if ($user->uid &&
isset($languages[$user->language])) {
return $user->language;
}
else {
return key($languages);
}
}
/**
* Translate strings to the current locale.
*
* All human-readable text that will be
displayed somewhere within a page should be
* run through the t() function.
*
* Examples:
* @code
* if
(!$info || !$info['extension']) {
*
form_set_error('picture_upload', t('The uploaded file was not an
image.'));
* }
*
*
$form['submit'] = array(
*
'#type' => 'submit',
*
'#value' => t('Log in'),
* );
* @endcode
*
* Any text within t() can be extracted by
translators and changed into
* the equivalent text in their native
language.
*
* Special variables called
"placeholders" are used to signal dynamic
* information in a string which should not be
translated. Placeholders
* can also be used for text that may change
from time to time
* (such as link paths) to be changed without
requiring updates to translations.
*
* For example:
* @code
*
$output = t('There are currently %members and %visitors online.', array(
*
'%members' => format_plural($total_users, '1 user', '@count users'),
*
'%visitors' => format_plural($guests->count, '1 guest', '@count
guests')));
* @endcode
*
* There are three styles of placeholders:
* - !variable, which indicates that the text
should be inserted as-is. This is
*
useful for inserting variables into things like e-mail.
*
@code
*
$message[] = t("If you don't want to receive such e-mails, you can
change your settings at !url.", array('!url' => url("user/$account->uid",
NULL, NULL, TRUE)));
*
@endcode
*
* - @variable, which indicates that the text
should be run through check_plain,
* to
strip out HTML characters. Use this for any output that's displayed within
* a
Drupal page.
*
@code
*
drupal_set_title($title = t("@name's blog", array('@name'
=> $account->name)));
*
@endcode
*
* - %variable, which indicates that the string
should be highlighted with
*
theme_placeholder() which shows up by default as
<em>emphasized</em>.
*
@code
*
watchdog('mail', t('%name-from sent %name-to an e-mail.',
array('%name-from' => $user->name, '%name-to' => $account->name)));
*
@endcode
*
* When using t(), try to put entire sentences
and strings in one t() call.
* This makes it easier for translators, as it
provides context as to what
* each word refers to. HTML markup within
translation strings is allowed,
* but should be avoided if possible. The
exception is embedded links; link
* titles add additional context for
translators so should be kept in the main
* string.
*
* Here is an example of an incorrect use if
t():
* @code
*
$output .= t('<p>Go to the @contact-page.</p>',
array('@contact-page' => l(t('contact page'), 'contact')));
* @endcode
*
* Here is an example of t() used correctly:
* @code
*
$output .= '<p>'. t('Go to the <a
href="@contact-page">contact page</a>.',
array('@contact-page' => url('contact'))) .'</p>';
* @endcode
*
* Also avoid escaping quotation marks wherever
possible.
*
* Incorrect:
* @code
*
$output .= t('Don\'t click me.');
* @endcode
*
* Correct:
* @code
*
$output .= t("Don't click me.");
* @endcode
*
* @param $string
* A
string containing the English string to translate.
* @param $args
* An
associative array of replacements to make after translation. Incidences
* of
any key in this array are replaced with the corresponding value.
*
Based on the first character of the key, the value is escaped and/or
themed:
* -
!variable: inserted as is
* -
@variable: escape plain text to HTML (check_plain)
* -
%variable: escape text and theme as a placeholder for user-submitted
*
content (check_plain + theme_placeholder)
* @return
* The
translated string.
*/
function t($string, $args =
0) {
global $locale;
if (function_exists('locale') &&
$locale != 'en') {
$string = locale($string);
}
if (!$args) {
return $string;
}
else {
// Transform arguments before inserting
them
foreach ($args as $key => $value) {
switch ($key[0]) {
// Escaped only
case '@':
$args[$key] = check_plain($value);
break;
// Escaped and placeholder
case '%':
default:
$args[$key] = theme('placeholder',
$value);
break;
// Pass-through
case '!':
}
}
return strtr($string, $args);
}
}
/**
* @defgroup validation Input validation
* @{
* Functions to validate user input.
*/
/**
* Verify the syntax of the given e-mail
address.
*
* Empty e-mail addresses are allowed. See RFC
2822 for details.
*
* @param $mail
* A
string containing an e-mail address.
* @return
* TRUE
if the address is in a valid format.
*/
function
valid_email_address($mail) {
$user =
'[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\']+';
$domain =
'(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.?)+';
$ipv4 = '[0-9]{1,3}(\.[0-9]{1,3}){3}';
$ipv6 =
'[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7}';
$ipv7 = '[0-9a-zA-Z]{2,4}';
/* return
preg_match("/^$user@($domain|(\[($ipv4|$ipv6)\]))$/", $mail); */
return
preg_match("/^$user@$domain\.($ipv7)$/", $mail);
}
/**
* Verify the syntax of the given URL.
*
* This function should only be used on actual
URLs. It should not be used for
* Drupal menu paths, which can contain
arbitrary characters.
*
* @param $url
* The
URL to verify.
* @param $absolute
*
Whether the URL is absolute (beginning with a scheme such as
"http:").
* @return
* TRUE
if the URL is in a valid format.
*/
function valid_url($url,
$absolute = FALSE) {
$allowed_characters =
'[a-z0-9\/:_\-_\.\?\$,;~=#&%\+]';
if ($absolute) {
return
preg_match("/^(http|https|ftp):\/\/". $allowed_characters
."+$/i", $url);
}
else {
return preg_match("/^".
$allowed_characters ."+$/i", $url);
}
}
/**
* Register an event for the current visitor
(hostname/IP) to the flood control mechanism.
*
* @param $name
* The
name of the event.
*/
function
flood_register_event($name) {
db_query("INSERT INTO {flood} (event,
hostname, timestamp) VALUES ('%s', '%s', %d)", $name,
$_SERVER['REMOTE_ADDR'], time());
}
/**
* Check if the current visitor (hostname/IP)
is allowed to proceed with the specified event.
* The user is allowed to proceed if he did not
trigger the specified event more than
* $threshold times per hour.
*
* @param $name
* The
name of the event.
* @param $number
* The
maximum number of the specified event per hour (per visitor).
* @return
* True
if the user did not exceed the hourly threshold. False otherwise.
*/
function flood_is_allowed($name,
$threshold) {
$number = db_num_rows(db_query("SELECT
event FROM {flood} WHERE event = '%s' AND hostname = '%s' AND timestamp >
%d", $name, $_SERVER['REMOTE_ADDR'], time() - 3600));
return ($number < $threshold ? TRUE :
FALSE);
}
function check_file($filename)
{
return is_uploaded_file($filename);
}
/**
* Prepare a URL for use in an HTML attribute.
Strips harmful protocols.
*
*/
function check_url($uri) {
return filter_xss_bad_protocol($uri, FALSE);
}
/**
* @defgroup format Formatting
* @{
* Functions to format numbers, strings, dates,
etc.
*/
/**
* Formats an RSS channel.
*
* Arbitrary elements may be added using the
$args associative array.
*/
function
format_rss_channel($title, $link, $description, $items, $language = 'en', $args
= array()) {
// arbitrary elements may be added using the
$args associative array
$output = "<channel>\n";
$output .= ' <title>'.
check_plain($title) ."</title>\n";
$output .= ' <link>'. check_url($link)
."</link>\n";
// The RSS 2.0 "spec" doesn't
indicate HTML can be used in the description.
// We strip all HTML tags, but need to
prevent double encoding from properly
// escaped source data (such as &
becoming &amp;).
$output .= ' <description>'.
check_plain(decode_entities(strip_tags($description)))
."</description>\n";
$output .= ' <language>'.
check_plain($language) ."</language>\n";
$output .= format_xml_elements($args);
$output .= $items;
$output .= "</channel>\n";
return $output;
}
/**
* Format a single RSS item.
*
* Arbitrary elements may be added using the
$args associative array.
*/
function
format_rss_item($title, $link, $description, $args = array()) {
$output = "<item>\n";
$output .= ' <title>'.
check_plain($title) ."</title>\n";
$output .= ' <link>'. check_url($link)
."</link>\n";
$output .= ' <description>'.
check_plain($description) ."</description>\n";
$output .= format_xml_elements($args);
$output .= "</item>\n";
return $output;
}
/**
* Format XML elements.
*
* @param $array
* An
array where each item represent an element and is either a:
* -
(key => value) pair (<key>value</key>)
* -
Associative array with fields:
* -
'key': element name
* -
'value': element contents
* -
'attributes': associative array of element attributes
*
* In both cases, 'value' can be a simple
string, or it can be another array
* with the same format as $array itself for
nesting.
*/
function
format_xml_elements($array) {
foreach ($array as $key => $value) {
if (is_numeric($key)) {
if ($value['key']) {
$output .= ' <'. $value['key'];
if (isset($value['attributes'])
&& is_array($value['attributes'])) {
$output .=
drupal_attributes($value['attributes']);
}
if ($value['value'] != '') {
$output .= '>'.
(is_array($value['value']) ? format_xml_elements($value['value']) :
check_plain($value['value'])) .'</'. $value['key'] .">\n";
}
else {
$output .= " />\n";
}
}
}
else {
$output .= ' <'. $key .'>'.
(is_array($value) ? format_xml_elements($value) : check_plain($value))
."</$key>\n";
}
}
return $output;
}
/**
* Format a string containing a count of items.
*
* This function ensures that the string is
pluralized correctly. Since t() is
* called by this function, make sure not to
pass already-localized strings to it.
*
* @param $count
* The
item count to display.
* @param $singular
* The
string for the singular case. Please make sure it is clear this is
* singular, to ease translation (e.g. use
"1 new comment" instead of "1 new").
* @param $plural
* The
string for the plural case. Please make sure it is clear this is plural,
* to
ease translation. Use @count in place of the item count, as in "@count
* new
comments".
* @return
* A
translated string.
*/
function
format_plural($count, $singular, $plural) {
if ($count == 1) return t($singular,
array("@count" => $count));
// get the plural index through the gettext
formula
$index = (function_exists('locale_get_plural'))
? locale_get_plural($count) : -1;
if ($index < 0) { // backward
compatibility
return t($plural, array("@count"
=> $count));
}
else {
switch ($index) {
case "0":
return t($singular,
array("@count" => $count));
case "1":
return t($plural,
array("@count" => $count));
default:
return t(strtr($plural,
array("@count" => '@count['. $index .']')), array('@count['.
$index .']' => $count));
}
}
}
/**
* Parse a given byte count.
*
* @param $size
* The
size expressed as a number of bytes with optional SI size and unit
*
suffix (e.g. 2, 3K, 5MB, 10G).
* @return
* An
integer representation of the size.
*/
function parse_size($size) {
$suffixes = array(
'' => 1,
'k' => 1024,
'm' => 1048576, // 1024 * 1024
'g' => 1073741824, // 1024 * 1024 * 1024
);
if
(preg_match('/([0-9]+)\s*(k|m|g)?(b?(ytes?)?)/i', $size, $match)) {
return $match[1] *
$suffixes[drupal_strtolower($match[2])];
}
}
/**
* Generate a string representation for the
given byte count.
*
* @param $size
* The
size in bytes.
* @return
* A
translated string representation of the size.
*/
function format_size($size) {
if ($size < 1024) {
return format_plural($size, '1 byte',
'@count bytes');
}
else {
$size = round($size / 1024, 2);
$suffix = t('KB');
if ($size >= 1024) {
$size = round($size / 1024, 2);
$suffix = t('MB');
}
return t('@size @suffix', array('@size'
=> $size, '@suffix' => $suffix));
}
}
/**
* Format a time interval with the requested
granularity.
*
* @param $timestamp
* The
length of the interval in seconds.
* @param $granularity
* How
many different units to display in the string.
* @return
* A
translated string representation of the interval.
*/
function
format_interval($timestamp, $granularity = 2) {
$units = array('1 year|@count years' =>
31536000, '1 week|@count weeks' => 604800, '1 day|@count days' => 86400,
'1 hour|@count hours' => 3600, '1 min|@count min' => 60, '1 sec|@count
sec' => 1);
$output = '';
foreach ($units as $key => $value) {
$key = explode('|', $key);
if ($timestamp >= $value) {
$output .= ($output ? ' ' : '') .
format_plural(floor($timestamp / $value), $key[0], $key[1]);
$timestamp %= $value;
$granularity--;
}
if ($granularity == 0) {
break;
}
}
return $output ? $output : t('0 sec');
}
/**
* Format a date with the given configured
format or a custom format string.
*
* Drupal allows administrators to select
formatting strings for 'small',
* 'medium' and 'large' date formats. This
function can handle these formats,
* as well as any custom format.
*
* @param $timestamp
* The
exact date to format, as a UNIX timestamp.
* @param $type
* The
format to use. Can be "small", "medium" or
"large" for the preconfigured
* date
formats. If "custom" is specified, then $format is required as well.
* @param $format
* A
PHP date format string as required by date(). A backslash should be used
*
before a character to avoid interpreting the character as part of a date
*
format.
* @param $timezone
* Time
zone offset in seconds; if omitted, the user's time zone is used.
* @return
* A
translated date string in the requested format.
*/
function
format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL) {
if (!isset($timezone)) {
global $user;
if (variable_get('configurable_timezones',
1) && $user->uid && strlen($user->timezone)) {
$timezone = $user->timezone;
}
else {
$timezone =
variable_get('date_default_timezone', 0);
}
}
$timestamp += $timezone;
switch ($type) {
case 'small':
$format =
variable_get('date_format_short', 'm/d/Y - H:i');
break;
case 'large':
$format =
variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
// No change to format
break;
case 'medium':
default:
$format =
variable_get('date_format_medium', 'D, m/d/Y - H:i');
}
$max = strlen($format);
$date = '';
for ($i = 0; $i < $max; $i++) {
$c = $format[$i];
if (strpos('AaDFlM', $c) !== FALSE) {
$date .= t(gmdate($c, $timestamp));
}
else if (strpos('BdgGhHiIjLmnsStTUwWYyz',
$c) !== FALSE) {
$date .= gmdate($c, $timestamp);
}
else if ($c == 'r') {
$date .= format_date($timestamp -
$timezone, 'custom', 'D, d M Y H:i:s O', $timezone);
}
else if ($c == 'O') {
$date .= sprintf('%s%02d%02d', ($timezone
< 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60);
}
else if ($c == 'Z') {
$date .= $timezone;
}
else if ($c == '\\') {
$date .= $format[++$i];
}
else {
$date .= $c;
}
}
return $date;
}
/**
* @} End of "defgroup format".
*/
/**
* Generate a URL from a Drupal menu path. Will
also pass-through existing URLs.
*
* @param $path
* The
Drupal path being linked to, such as "admin/content/node", or an
existing URL
* like
"http://drupal.org/".
* @param $query
* A
query string to append to the link or URL.
* @param $fragment
* A
fragment identifier (named anchor) to append to the link. If an existing
* URL
with a fragment identifier is used, it will be replaced. Note, do not
*
include the '#'.
* @param $absolute
*
Whether to force the output to be an absolute link (beginning with
http:).
*
Useful for links that will be displayed outside the site, such as in an
* RSS
feed.
* @return
* a
string containing a URL to the given path.
*
* When creating links in modules, consider
whether l() could be a better
* alternative than url().
*/
function url($path = NULL,
$query = NULL, $fragment = NULL, $absolute = FALSE) {
if (isset($fragment)) {
$fragment = '#'. $fragment;
}
// Return an external link if $path contains
an allowed absolute URL.
// Only call the slow filter_xss_bad_protocol
if $path contains a ':' before any / ? or #.
$colonpos = strpos($path, ':');
if ($colonpos !== FALSE &&
!preg_match('![/?#]!', substr($path, 0, $colonpos)) &&
filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
// Split off the fragment
if (strpos($path, '#') !== FALSE) {
list($path, $old_fragment) = explode('#',
$path, 2);
if (isset($old_fragment) && !isset($fragment))
{
$fragment = '#'. $old_fragment;
}
}
// Append the query
if (isset($query)) {
$path .= (strpos($path, '?') !== FALSE ?
'&' : '?') . $query;
}
// Reassemble
return $path . $fragment;
}
global $base_url;
static $script;
static $clean_url;
if (empty($script)) {
// On some web servers, such as IIS, we
can't omit "index.php". So, we
// generate "index.php?q=foo"
instead of "?q=foo" on anything that is not
// Apache.
$script =
(strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : '';
}
// Cache the clean_url variable to improve
performance.
if (!isset($clean_url)) {
$clean_url =
(bool)variable_get('clean_url', '0');
}
$base = ($absolute ? $base_url . '/' :
base_path());
// The special path '<front>' links to
the default front page.
if (!empty($path) && $path !=
'<front>') {
$path = drupal_get_path_alias($path);
$path = drupal_urlencode($path);
if (!$clean_url) {
if (isset($query)) {
return $base . $script .'?q='. $path
.'&'. $query . $fragment;
}
else {
return $base . $script .'?q='. $path .
$fragment;
}
}
else {
if (isset($query)) {
return $base . $path .'?'. $query .
$fragment;
}
else {
return $base . $path . $fragment;
}
}
}
else {
if (isset($query)) {
return $base . $script .'?'. $query .
$fragment;
}
else {
return $base . $fragment;
}
}
}
/**
* Format an attribute string to insert in a
tag.
*
* @param $attributes
* An
associative array of HTML attributes.
* @return
* An
HTML string ready for insertion in a tag.
*/
function
drupal_attributes($attributes = array()) {
if (is_array($attributes)) {
$t = '';
foreach ($attributes as $key => $value)
{
$t .= " $key=".'"'.
check_plain($value) .'"';
}
return $t;
}
}
/**
* Format an internal Drupal link.
*
* This function correctly handles aliased
paths, and allows themes to highlight
* links to the current page correctly, so all
internal links output by modules
* should be generated by this function if
possible.
*
* @param $text
* The
text to be enclosed with the anchor tag.
* @param $path
* The
Drupal path being linked to, such as "admin/content/node". Can be an
external
* or
internal URL.
* -
If you provide the full URL, it will be considered an
*
external URL.
* -
If you provide only the path (e.g. "admin/content/node"), it is
considered an
*
internal link. In this case, it must be a system URL as the url()
function
* will
generate the alias.
* @param $attributes
* An
associative array of HTML attributes to apply to the anchor tag.
* @param $query
* A
query string to append to the link.
* @param $fragment
* A
fragment identifier (named anchor) to append to the link.
* @param $absolute
*
Whether to force the output to be an absolute link (beginning with
http:).
*
Useful for links that will be displayed outside the site, such as in an
RSS
*
feed.
* @param $html
*
Whether the title is HTML, or just plain-text. For example for making an
*
image a link, this must be set to TRUE, or else you will see the encoded
*
HTML.
* @return
* an
HTML string containing a link to the given path.
*/
function l($text, $path,
$attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE,
$html = FALSE) {
if ($path == $_GET['q']) {
if (isset($attributes['class'])) {
$attributes['class'] .= ' active';
}
else {
$attributes['class'] = 'active';
}
}
return '<a href="'.
check_url(url($path, $query, $fragment, $absolute)) .'"'.
drupal_attributes($attributes) .'>'. ($html ? $text : check_plain($text))
.'</a>';
}
/**
* Perform end-of-request tasks.
*
* This function sets the page cache if
appropriate, and allows modules to
* react to the closing of the page by calling
hook_exit().
*/
function drupal_page_footer()
{
if (variable_get('cache', 0)) {
page_set_cache();
}
module_invoke_all('exit');
}
/**
* Form an associative array from a linear
array.
*
* This function walks through the provided
array and constructs an associative
* array out of it. The keys of the resulting
array will be the values of the
* input array. The values will be the same as
the keys unless a function is
* specified, in which case the output of the
function is used for the values
* instead.
*
* @param $array
* A
linear array.
* @param $function
* The
name of a function to apply to all values before output.
* @result
* An
associative array.
*/
function
drupal_map_assoc($array, $function = NULL) {
if (!isset($function)) {
$result = array();
foreach ($array as $value) {
$result[$value] = $value;
}
return $result;
}
elseif (function_exists($function)) {
$result = array();
foreach ($array as $value) {
$result[$value] = $function($value);
}
return $result;
}
}
/**
* Evaluate a string of PHP code.
*
* This is a wrapper around PHP's eval(). It
uses output buffering to capture both
* returned and printed text. Unlike eval(), we
require code to be surrounded by
* <?php ?> tags; in other words, we
evaluate the code as if it were a stand-alone
* PHP file.
*
* Using this wrapper also ensures that the PHP
code which is evaluated can not
* overwrite any variables in the calling code,
unlike a regular eval() call.
*
* @param $code
* The
code to evaluate.
* @return
* A
string containing the printed output of the code, followed by the returned
*
output of the code.
*/
function drupal_eval($code) {
ob_start();
print eval('?>'. $code);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Returns the path to a system item (module,
theme, etc.).
*
* @param $type
* The
type of the item (i.e. theme, theme_engine, module).
* @param $name
* The
name of the item for which the path is requested.
*
* @return
* The
path to the requested item.
*/
function
drupal_get_path($type, $name) {
return dirname(drupal_get_filename($type,
$name));
}
/**
* Returns the base URL path of the Drupal
installation.
* At the very least, this will always default
to /.
*/
function base_path() {
return $GLOBALS['base_path'];
}
/**
* Provide a substitute clone() function for
PHP4.
*/
function
drupal_clone($object) {
return version_compare(phpversion(), '5.0')
< 0 ? $object : clone($object);
}
/**
* Add a <link> tag to the page's HEAD.
*/
function
drupal_add_link($attributes) {
drupal_set_html_head('<link'. drupal_attributes($attributes)
." />\n");
}
/**
* Adds a CSS file to the stylesheet queue.
*
* @param $path
*
(optional) The path to the CSS file relative to the base_path(), e.g.,
*
/modules/devel/devel.css.
* @param $type
*
(optional) The type of stylesheet that is being added. Types are: module
* or
theme.
* @param $media
*
(optional) The media type for the stylesheet, e.g., all, print, screen.
* @param $preprocess
*
(optional) Should this CSS file be aggregated and compressed if this
*
feature has been turned on under the performance section?
*
* What
does this actually mean?
* CSS
preprocessing is the process of aggregating a bunch of separate CSS
*
files into one file that is then compressed by removing all extraneous
*
white space.
*
* The
reason for merging the CSS files is outlined quite thoroughly here:
*
http://www.die.net/musings/page_load_time/
*
"Load fewer external objects. Due to request overhead, one bigger
file
* just
loads faster than two smaller ones half its size."
*
*
However, you should *not* preprocess every file as this can lead to
*
redundant caches. You should set $preprocess = FALSE when:
*
* -
Your styles are only used rarely on the site. This could be a special
* admin page, the homepage, or a handful of
pages that does not represent
*
the majority of the pages on your site.
*
*
Typical candidates for caching are for example styles for nodes across
* the
site, or used in the theme.
* @return
* An
array of CSS files.
*/
function drupal_add_css($path
= NULL, $type = 'module', $media = 'all', $preprocess = TRUE) {
static $css = array();
// Create an array of CSS files for each
media type first, since each type needs to be served
// to the browser differently.
if (isset($path)) {
// This check is necessary to ensure proper
cascading of styles and is faster than an asort().
if (!isset($css[$media])) {
$css[$media] = array('module' =>
array(), 'theme' => array());
}
$css[$media][$type][$path] = $preprocess;
}
return $css;
}
/**
* Returns a themed representation of all
stylesheets that should be attached to the page.
* It loads the CSS in order, with 'core' CSS
first, then 'module' CSS, then 'theme' CSS files.
* This ensures proper cascading of styles for
easy overriding in modules and themes.
*
* @param $css
*
(optional) An array of CSS files. If no array is provided, the default
stylesheets array is used instead.
* @return
* A
string of XHTML CSS tags.
*/
function drupal_get_css($css
= NULL) {
$output = '';
if (!isset($css)) {
$css = drupal_add_css();
}
$preprocess_css =
variable_get('preprocess_css', FALSE);
$directory = file_directory_path();
$is_writable = is_dir($directory) &&
is_writable($directory) && (variable_get('file_downloads',
FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
foreach ($css as $media => $types) {
// If CSS preprocessing is off, we still
need to output the styles.
// Additionally, go through any remaining
styles if CSS preprocessing is on and output the non-cached ones.
foreach ($types as $type => $files) {
foreach ($types[$type] as $file =>
$preprocess) {
if (!$preprocess || !($is_writable
&& $preprocess_css)) {
// If a CSS file is not to be
preprocessed and it's a module CSS file, it needs to *always* appear at the
*top*,
// regardless of whether
preprocessing is on or off.
if (!$preprocess && $type ==
'module') {
$no_module_preprocess .= '<style
type="text/css" media="'. $media .'">@import "'.
base_path() . $file .'";</style>' ."\n";
}
// If a CSS file is not to be
preprocessed and it's a theme CSS file, it needs to *always* appear at the
*bottom*,
// regardless of whether
preprocessing is on or off.
else if (!$preprocess &&
$type == 'theme') {
$no_theme_preprocess .= '<style
type="text/css" media="'. $media .'">@import "'.
base_path() . $file .'";</style>' ."\n";
}
else {
$output .= '<style type="text/css" media="'. $media
.'">@import "'. base_path() . $file .'";</style>'
."\n";
}
}
}
}
if ($is_writable &&
$preprocess_css) {
$filename = md5(serialize($types))
.'.css';
$preprocess_file =
drupal_build_css_cache($types, $filename);
$output .= '<style
type="text/css" media="'. $media .'">@import "'.
base_path() . $preprocess_file .'";</style>'. "\n";
}
}
return $no_module_preprocess . $output .
$no_theme_preprocess;
}
/**
* Aggregate and optimize CSS files, putting
them in the files directory.
*
* @param $types
* An
array of types of CSS files (e.g., screen, print) to aggregate and compress
into one file.
* @param $filename
* The
name of the aggregate CSS file.
* @return
* The
name of the CSS file.
*/
function
drupal_build_css_cache($types, $filename) {
$data = '';
// Create the css/ within the files folder.
$csspath = file_create_path('css');
file_check_directory($csspath, FILE_CREATE_DIRECTORY);
if (!file_exists($csspath .'/'. $filename)) {
// Build aggregate CSS file.
foreach ($types as $type) {
foreach ($type as $file => $cache) {
if ($cache) {
$contents = file_get_contents($file);
// Return the path to where this CSS
file originated from, stripping off the name of the file at the end of the
path.
$path = base_path() . substr($file,
0, strrpos($file, '/')) .'/';
// Wraps all @import arguments in
url().
$contents =
preg_replace('/@import\s+(?!url)[\'"]?(\S*)\b[\'"]?/i', '@import
url("\1")', $contents);
// Fix all paths within this CSS
file, ignoring absolute paths.
$data .=
preg_replace('/url\(([\'"]?)(?![a-z]+:)/i', 'url(\1'. $path . '\2', $contents);
}
}
}
// @import rules must proceed any other
style, so we move those to the top.
$regexp = '/@import[^;]+;/i';
preg_match_all($regexp, $data, $matches);
$data = preg_replace($regexp, '', $data);
$data = implode('', $matches[0]) . $data;
// Perform some safe CSS optimizations.
$data = preg_replace('<
\s*([@{}:;,]|\)\s|\s\()\s* | # Remove whitespace around separators, but
keep space around parentheses.
/\*([^*\\\\]|\*(?!/))+\*/ | # Remove comments that are not CSS hacks.
[\n\r] # Remove line breaks.
>x', '\1', $data);
// Create the CSS file.
file_save_data($data, $csspath .'/'.
$filename, FILE_EXISTS_REPLACE);
}
return $csspath .'/'. $filename;
}
/**
* Delete all cached CSS files.
*/
function
drupal_clear_css_cache() {
file_scan_directory(file_create_path('css'),
'.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
}
/**
* Add a JavaScript file, setting or inline
code to the page.
*
* The behavior of this function depends on the
parameters it is called with.
* Generally, it handles the addition of
JavaScript to the page, either as
* reference to an existing file or as inline
code. The following actions can be
* performed using this function:
*
* - Add a file ('core', 'module' and 'theme'):
* Adds
a reference to a JavaScript file to the page. JavaScript files
* are
placed in a certain order, from 'core' first, to 'module' and finally
*
'theme' so that files, that are added later, can override previously
added
*
files with ease.
*
* - Add inline JavaScript code ('inline'):
*
Executes a piece of JavaScript code on the current page by placing the
code
*
directly in the page. This can, for example, be useful to tell the user
that
* a
new message arrived, by opening a pop up, alert box etc.
*
* - Add settings ('setting'):
* Adds
a setting to Drupal's global storage of JavaScript settings. Per-page
*
settings are required by some modules to function properly. The settings
* will
be accessible at Drupal.settings.
*
* @param $data
*
(optional) If given, the value depends on the $type parameter:
* -
'core', 'module' or 'theme': Path to the file relative to base_path().
* -
'inline': The JavaScript code that should be placed in the given scope.
* -
'setting': An array with configuration options as associative array. The
*
array is directly placed in Drupal.settings. You might want to wrap your
*
actual configuration settings in another variable to prevent the
pollution
*
of the Drupal.settings namespace.
* @param $type
*
(optional) The type of JavaScript that should be added to the page.
Allowed
*
values are 'core', 'module', 'theme', 'inline' and 'setting'. You
* can,
however, specify any value. It is treated as a reference to a JavaScript
*
file. Defaults to 'module'.
* @param $scope
*
(optional) The location in which you want to place the script. Possible
*
values are 'header' and 'footer' by default. If your theme implements
*
different locations, however, you can also use these.
* @param $defer
*
(optional) If set to TRUE, the defer attribute is set on the
<script> tag.
*
Defaults to FALSE. This parameter is not used with $type == 'setting'.
* @param $cache
*
(optional) If set to FALSE, the JavaScript file is loaded anew on every
page
*
call, that means, it is not cached. Defaults to TRUE. Used only when
$type
*
references a JavaScript file.
* @return
* If
the first parameter is NULL, the JavaScript array that has been built so
* far
for $scope is returned.
*/
function drupal_add_js($data
= NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE) {
if (!is_null($data)) {
_drupal_add_js('misc/jquery.js', 'core',
'header', FALSE, $cache);
_drupal_add_js('misc/drupal.js', 'core',
'header', FALSE, $cache);
}
return _drupal_add_js($data, $type, $scope,
$defer, $cache);
}
/**
* Helper function for drupal_add_js().
*/
function
_drupal_add_js($data, $type, $scope, $defer, $cache) {
static $javascript = array();
if (!isset($javascript[$scope])) {
$javascript[$scope] = array('core' =>
array(), 'module' => array(), 'theme' => array(), 'setting' =>
array(), 'inline' => array());
}
if (!isset($javascript[$scope][$type])) {
$javascript[$scope][$type] = array();
}
if (!is_null($data)) {
switch ($type) {
case 'setting':
$javascript[$scope][$type][] = $data;
break;
case 'inline':
$javascript[$scope][$type][] =
array('code' => $data, 'defer' => $defer);
break;
default:
$javascript[$scope][$type][$data] =
array('cache' => $cache, 'defer' => $defer);
}
}
return $javascript[$scope];
}
/**
* Returns a themed presentation of all
JavaScript code for the current page.
* References to JavaScript files are placed in
a certain order: first, all
* 'core' files, then all 'module' and finally
all 'theme' JavaScript files
* are added to the page. Then, all settings
are output, followed by 'inline'
* JavaScript code.
*
* @parameter $scope
*
(optional) The scope for which the JavaScript rules should be returned.
*
Defaults to 'header'.
* @parameter $javascript
*
(optional) An array with all JavaScript code. Defaults to the default
*
JavaScript array for the given scope.
* @return
* All
JavaScript code segments and includes for the scope as HTML tags.
*/
function drupal_get_js($scope
= 'header', $javascript = NULL) {
$output = '';
if (is_null($javascript)) {
$javascript = drupal_add_js(NULL, NULL,
$scope);
}
foreach ($javascript as $type => $data) {
if (!$data) continue;
switch ($type) {
case 'setting':
$output .= '<script
type="text/javascript">Drupal.extend({ settings: '. drupal_to_js(call_user_func_array('array_merge_recursive',
$data)) ." });</script>\n";
break;
case 'inline':
foreach ($data as $info) {
$output .= '<script
type="text/javascript"'. ($info['defer'] ? ' defer="defer"'
: '') .'>'. $info['code'] ."</script>\n";
}
break;
default:
foreach ($data as $path => $info) {
$output .= '<script
type="text/javascript"'. ($info['defer'] ? ' defer="defer"'
: '') .' src="'. check_url(base_path() . $path) . ($info['cache'] ? '' :
'?'. time()) ."\"></script>\n";
}
}
}
return $output;
}
/**
* Converts a PHP variable into its Javascript
equivalent.
*
* We use HTML-safe strings, i.e. with <,
> and & escaped.
*/
function drupal_to_js($var) {
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false'; //
Lowercase necessary!
case 'integer':
case 'double':
return $var;
case 'resource':
case 'string':
return '"'.
str_replace(array("\r", "\n", "<",
">", "&"),
array('\r', '\n',
'\x3c', '\x3e', '\x26'),
addslashes($var))
.'"';
case 'array':
if (array_keys($var) === range(0,
sizeof($var) - 1)) {
$output = array();
foreach ($var as $v) {
$output[] = drupal_to_js($v);
}
return '[ '. implode(', ', $output) .'
]';
}
// Fall through
case 'object':
$output = array();
foreach ($var as $k => $v) {
$output[] = drupal_to_js(strval($k))
.': '. drupal_to_js($v);
}
return '{ '. implode(', ', $output) .'
}';
default:
return 'null';
}
}
/**
* Wrapper around urlencode() which avoids
Apache quirks.
*
* Should be used when placing arbitrary data
in an URL. Note that Drupal paths
* are urlencoded() when passed through url()
and do not require urlencoding()
* of individual components.
*
* Notes:
* - For esthetic reasons, we do not escape
slashes. This also avoids a 'feature'
* in
Apache where it 404s on any path containing '%2F'.
* - mod_rewrite's unescapes %-encoded
ampersands and hashes when clean URLs
* are
used, which are interpreted as delimiters by PHP. These characters are
*
double escaped so PHP will still see the encoded version.
*
* @param $text
*
String to encode
*/
function
drupal_urlencode($text) {
if (variable_get('clean_url', '0')) {
return str_replace(array('%2F', '%26',
'%23'),
array('/', '%2526',
'%2523'),
urlencode($text));
}
else {
return str_replace('%2F', '/',
urlencode($text));
}
}
/**
* Ensure the private key variable used to
generate tokens is set.
*
* @return
* The
private key
*/
function
drupal_get_private_key() {
if (!($key = variable_get('drupal_private_key',
0))) {
$key = md5(uniqid(mt_rand(), true)) .
md5(uniqid(mt_rand(), true));
variable_set('drupal_private_key', $key);
}
return $key;
}
/**
* Generate a token based on $value, the
current user session and private key.
*
* @param $value
* An
additional value to base the token on
*/
function
drupal_get_token($value = '') {
$private_key = drupal_get_private_key();
return md5(session_id() . $value .
$private_key);
}
/**
* Validate a token based on $value, the
current user session and private key.
*
* @param $token
* The
token to be validated.
* @param $value
* An
additional value to base the token on.
* @param $skip_anonymous
* Set
to true to skip token validation for anonymous users.
* @return
* True
for a valid token, false for an invalid token. When $skip_anonymous is true,
the return value will always be true for anonymous users.
*/
function
drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
global $user;
return (($skip_anonymous &&
$user->uid == 0) || ($token == md5(session_id() . $value .
variable_get('drupal_private_key', ''))));
}
/**
* Performs one or more XML-RPC request(s).
*
* @param $url
* An
absolute URL of the XML-RPC endpoint.
*
Example:
*
http://www.example.com/xmlrpc.php
* @param ...
* For
one request:
*
The method name followed by a variable number of arguments to the
method.
* For
multiple requests (system.multicall):
* An
array of call arrays. Each call array follows the pattern of the single
*
request: method name followed by the arguments to the method.
* @return
* For
one request:
*
Either the return value of the method on success, or FALSE.
* If
FALSE is returned, see xmlrpc_errno() and xmlrpc_error_msg().
* For
multiple requests:
* An
array of results. Each result will either be the result
*
returned by the method called, or an xmlrpc_error object if the call
*
failed. See xmlrpc_error().
*/
function xmlrpc($url) {
require_once './includes/xmlrpc.inc';
$args = func_get_args();
return call_user_func_array('_xmlrpc',
$args);
}
function
_drupal_bootstrap_full() {
static $called;
global $locale;
if ($called) {
return;
}
$called = 1;
require_once './includes/theme.inc';
require_once './includes/pager.inc';
require_once './includes/menu.inc';
require_once './includes/tablesort.inc';
require_once './includes/file.inc';
require_once './includes/unicode.inc';
require_once './includes/image.inc';
require_once './includes/form.inc';
// Set the Drupal custom error handler.
set_error_handler('error_handler');
// Emit the correct charset HTTP header.
drupal_set_header('Content-Type: text/html;
charset=utf-8');
// Detect string handling method
unicode_check();
// Undo magic quotes
fix_gpc_magic();
// Load all enabled modules
module_load_all();
// Initialize the localization system. Depends on i18n.module being loaded already.
$locale = locale_initialize();
// Let all modules take action before menu
system handles the reqest
module_invoke_all('init');
}
/**
* Store the current page in the cache.
*
* We try to store a gzipped version of the
cache. This requires the
* PHP zlib extension
(http://php.net/manual/en/ref.zlib.php).
* Presence of the extension is checked by
testing for the function
* gzencode. There are two compression
algorithms: gzip and deflate.
* The majority of all modern browsers support
gzip or both of them.
* We thus only deal with the gzip variant and
unzip the cache in case
* the browser does not accept gzip encoding.
*
* @see drupal_page_header
*/
function page_set_cache() {
global $user, $base_root;
if (!$user->uid &&
$_SERVER['REQUEST_METHOD'] == 'GET' && count(drupal_get_messages(NULL,
FALSE)) == 0) {
// This will fail in some cases, see
page_get_cache() for the explanation.
if ($data = ob_get_contents()) {
$cache = TRUE;
if (function_exists('gzencode')) {
// We do not store the data in case the
zlib mode is deflate.
// This should be rarely happening.
if (zlib_get_coding_type() ==
'deflate') {
$cache = FALSE;
}
else if (zlib_get_coding_type() ==
FALSE) {
$data = gzencode($data, 9,
FORCE_GZIP);
}
// The remaining case is 'gzip' which
means the data is
// already compressed and nothing left
to do but to store it.
}
ob_end_flush();
if ($cache && $data) {
cache_set($base_root . request_uri(),
'cache_page', $data, CACHE_TEMPORARY, drupal_get_headers());
}
}
}
}
/**
* Send an e-mail message, using Drupal
variables and default settings.
* More information in the <a
href="http://php.net/manual/en/function.mail.php">
* PHP function reference for mail()</a>
* @param $mailkey
* A
key to identify the mail sent, for altering.
* @param $to
* The
mail address or addresses where the message will be send to. The
*
formatting of this string must comply with RFC 2822. Some examples are:
*
user@example.com
*
user@example.com, anotheruser@example.com
*
User <user@example.com>
*
User <user@example.com>, Another User
<anotheruser@example.com>
* @param $subject
*
Subject of the e-mail to be sent. This must not contain any newline
*
characters, or the mail may not be sent properly.
* @param $body
*
Message to be sent. Drupal will format the correct line endings for you.
* @param $from
* Sets
From, Reply-To, Return-Path and Error-To to this value, if given.
* @param $headers
*
Associative array containing the headers to add. This is typically
* used
to add extra headers (From, Cc, and Bcc).
*
<em>When sending mail, the mail must contain a From
header.</em>
* @return Returns TRUE if the mail was
successfully accepted for delivery,
*
FALSE otherwise.
*/
function
drupal_mail($mailkey, $to, $subject, $body, $from = NULL, $headers = array()) {
$defaults = array(
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain;
charset=UTF-8; format=flowed',
'Content-Transfer-Encoding' => '8Bit',
'X-Mailer' => 'Drupal'
);
if (isset($from)) {
$defaults['From'] = $defaults['Reply-To'] =
$defaults['Return-Path'] = $defaults['Errors-To'] = $from;
}
$headers = array_merge($defaults, $headers);
// Custom hook traversal to allow pass by
reference
foreach (module_implements('mail_alter') AS
$module) {
$function = $module .'_mail_alter';
$function($mailkey, $to, $subject, $body,
$from, $headers);
}
// Allow for custom mail backend
if (variable_get('smtp_library', '')
&& file_exists(variable_get('smtp_library', ''))) {
include_once './' .
variable_get('smtp_library', '');
return drupal_mail_wrapper($mailkey, $to,
$subject, $body, $from, $headers);
}
else {
/*
** Note: if you are having problems with
sending mail, or mails look wrong
** when they are received you may have to
modify the str_replace to suit
** your systems.
** -
\r\n will work under dos and windows.
** -
\n will work for linux, unix and BSDs.
** -
\r will work for macs.
**
** According to RFC 2646, it's quite rude
to not wrap your e-mails:
**
** "The Text/Plain media type is the
lowest common denominator of
** Internet e-mail, with lines of no more
than 997 characters (by
** convention usually no more than 80), and
where the CRLF sequence
** represents a line break
[MIME-IMT]."
**
** CRLF === \r\n
**
**
http://www.rfc-editor.org/rfc/rfc2646.txt
**
*/
$mimeheaders = array();
foreach ($headers as $name => $value) {
$mimeheaders[] = $name .': '.
mime_header_encode($value);
}
return mail(
$to,
mime_header_encode($subject),
str_replace("\r", '', $body),
join("\n", $mimeheaders)
);
}
}
/**
* Executes a cron run when called
* @return
* Returns TRUE if ran successfully
*/
function drupal_cron_run() {
// If not in 'safe mode', increase the
maximum execution time:
if (!ini_get('safe_mode')) {
set_time_limit(240);
}
// Fetch the cron semaphore
$semaphore = variable_get('cron_semaphore',
FALSE);
if ($semaphore) {
if (time() - $semaphore > 3600) {
// Either cron has been running for more
than an hour or the semaphore
// was not reset due to a database error.
watchdog('cron', t('Cron has been running
for more than an hour and is most likely stuck.'), WATCHDOG_ERROR);
// Release cron semaphore
variable_del('cron_semaphore');
}
else {
// Cron is still running normally.
watchdog('cron', t('Attempting to re-run
cron while it is already running.'), WATCHDOG_WARNING);
}
}
else {
// Register shutdown callback
register_shutdown_function('drupal_cron_cleanup');
// Lock cron semaphore
variable_set('cron_semaphore', time());
// Iterate through the modules calling
their cron handlers (if any):
module_invoke_all('cron');
// Record cron time
variable_set('cron_last', time());
watchdog('cron', t('Cron run completed.'),
WATCHDOG_NOTICE);
// Release cron semaphore
variable_del('cron_semaphore');
// Return TRUE so other functions can check
if it did run successfully
return TRUE;
}
}
/**
* Shutdown function for cron cleanup.
*/
function
drupal_cron_cleanup() {
// See if the semaphore is still locked.
if (variable_get('cron_semaphore', FALSE)) {
watchdog('cron', t('Cron run exceeded the
time limit and was aborted.'), WATCHDOG_WARNING);
// Release cron semaphore
variable_del('cron_semaphore');
}
}
/**
* Returns an array of files objects of the given
type from the site-wide
* directory (i.e. modules/), the all-sites
directory (i.e.
* sites/all/modules/), the profiles directory,
and site-specific directory
* (i.e. sites/somesite/modules/). The returned
array will be keyed using the
* key specified (name, basename, filename).
Using name or basename will cause
* site-specific files to be prioritized over
similar files in the default
* directories. That is, if a file with the
same name appears in both the
* site-wide directory and site-specific
directory, only the site-specific
* version will be included.
*
* @param $mask
* The
regular expression of the files to find.
* @param $directory
* The
subdirectory name in which the files are found. For example,
*
'modules' will search in both modules/ and
*
sites/somesite/modules/.
* @param $key
* The
key to be passed to file_scan_directory().
* @param $min_depth
*
Minimum depth of directories to return files from.
*
* @return
* An
array of file objects of the specified type.
*/
function
drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1) {
global $profile;
$config = conf_path();
// When this function is called during
Drupal's initial installation process,
// the name of the profile that's about to be
installed is stored in the global
// $profile variable. At all other times, the
standard Drupal systems variable
// table contains the name of the current
profile, and we can call variable_get()
// to determine what one is active.
if (!isset($profile)) {
$profile = variable_get('install_profile',
'default');
}
$searchdir = array($directory);
$files = array();
// Always search sites/all/* as well as the
global directories
$searchdir[] = 'sites/all/'. $directory;
// The 'profiles' directory contains pristine
collections of modules and
// themes as organized by a
distribution. It is pristine in the same
way
// that /modules is pristine for core; users
should avoid changing anything
// there in favor of sites/all or sites/<domain>
directories.
if
(file_exists("profiles/$profile/$directory")) {
$searchdir[] =
"profiles/$profile/$directory";
}
if
(file_exists("$config/$directory")) {
$searchdir[] =
"$config/$directory";
}
// Get current list of items
foreach ($searchdir as $dir) {
$files = array_merge($files,
file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, TRUE, $key,
$min_depth));
}
return $files;
}
/**
* Renders HTML given a structured array tree.
Recursively iterates over each
* of the array elements, generating HTML code.
This function is usually
* called from within a another function, like
drupal_get_form() or node_view().
*
* @param $elements
* The
structured array describing the data to be rendered.
* @return
* The rendered
HTML.
*/
function
drupal_render(&$elements) {
if (!isset($elements) ||
(isset($elements['#access']) && !$elements['#access'])) {
return NULL;
}
$content = '';
// Either the elements did not go through
form_builder or one of the children
// has a #weight.
if (!isset($elements['#sorted'])) {
uasort($elements,
"_element_sort");
}
if (!isset($elements['#children'])) {
$children = element_children($elements);
/* Render all the children that use a theme
function */
if (isset($elements['#theme']) &&
empty($elements['#theme_used'])) {
$elements['#theme_used'] = TRUE;
$previous = array();
foreach (array('#value', '#type',
'#prefix', '#suffix') as $key) {
$previous[$key] =
isset($elements[$key]) ? $elements[$key] : NULL;
}
// If we rendered a single element, then
we will skip the renderer.
if (empty($children)) {
$elements['#printed'] = TRUE;
}
else {
$elements['#value'] = '';
}
$elements['#type'] = 'markup';
unset($elements['#prefix'],
$elements['#suffix']);
$content = theme($elements['#theme'],
$elements);
foreach (array('#value', '#type',
'#prefix', '#suffix') as $key) {
$elements[$key] = isset($previous[$key])
? $previous[$key] : NULL;
}
}
/* render each of the children using
drupal_render and concatenate them */
if (!isset($content) || $content === '') {
foreach ($children as $key) {
$content .=
drupal_render($elements[$key]);
}
}
}
if (isset($content) && $content !==
'') {
$elements['#children'] = $content;
}
// Until now, we rendered the children, here
we render the element itself
if (!isset($elements['#printed'])) {
$content = theme(!empty($elements['#type'])
? $elements['#type'] : 'markup', $elements);
$elements['#printed'] = TRUE;
}
if (isset($content) && $content !==
'') {
$prefix = isset($elements['#prefix']) ?
$elements['#prefix'] : '';
$suffix = isset($elements['#suffix']) ? $elements['#suffix']
: '';
return $prefix . $content . $suffix;
}
}
/**
* Function used by uasort in drupal_render()
to sort structured arrays
* by weight.
*/
function _element_sort($a,
$b) {
$a_weight = (is_array($a) &&
isset($a['#weight'])) ? $a['#weight'] : 0;
$b_weight = (is_array($b) &&
isset($b['#weight'])) ? $b['#weight'] : 0;
if ($a_weight == $b_weight) {
return 0;
}
return ($a_weight < $b_weight) ? -1 : 1;
}
/**
* Check if the key is a property.
*/
function element_property($key)
{
return $key[0] == '#';
}
/**
* Get properties of a structured array
element. Properties begin with '#'.
*/
function
element_properties($element) {
return array_filter(array_keys((array)
$element), 'element_property');
}
/**
* Check if the key is a child.
*/
function element_child($key)
{
return $key[0] != '#';
}
/**
* Get keys of a structured array tree element
that are not properties
* (i.e., do not begin with '#').
*/
function
element_children($element) {
return array_filter(array_keys((array)
$element), 'element_child');
}
USER.MODULE
<?php
// $Id: user.module,v
1.745.2.1 2007/01/29 19:08:46 dries Exp $
/**
* @file
* Enables the user registration and login
system.
*/
define('USERNAME_MAX_LENGTH',
60);
define('EMAIL_MAX_LENGTH',
64);
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this,
because the arguments need to
* be passed by reference.
*/
function
user_module_invoke($type, &$array, &$user, $category = NULL) {
foreach (module_list() as $module) {
$function = $module .'_user';
if (function_exists($function)) {
$function($type, $array, $user,
$category);
}
}
}
function
user_external_load($authname) {
$result = db_query("SELECT uid FROM
{authmap} WHERE authname = '%s'", $authname);
if ($user = db_fetch_array($result)) {
return user_load($user);
}
else {
return 0;
}
}
/**
* Fetch a user object.
*
* @param $array
* An
associative array of attributes to search for in selecting the
* user,
such as user name or e-mail address.
*
* @return
* A
fully-loaded $user object upon successful user load or FALSE if user cannot be
loaded.
*/
function user_load($array =
array()) {
// Dynamically compose a SQL query:
$query = array();
$params = array();
foreach ($array as $key => $value) {
if ($key == 'uid' || $key == 'status') {
$query[] = "$key = %d";
$params[] = $value;
}
else if ($key == 'pass') {
$query[] = "pass = '%s'";
$params[] = md5($value);
}
else {
$query[]= "LOWER($key) =
LOWER('%s')";
$params[] = $value;
}
}
$result = db_query('SELECT * FROM {users} u
WHERE '. implode(' AND ', $query), $params);
if (db_num_rows($result)) {
$user = db_fetch_object($result);
$user = drupal_unpack($user);
$user->roles = array();
if ($user->uid) {
$user->roles[DRUPAL_AUTHENTICATED_RID]
= 'authenticated user';
}
else {
$user->roles[DRUPAL_ANONYMOUS_RID] =
'anonymous user';
}
$result = db_query('SELECT r.rid, r.name
FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d',
$user->uid);
while ($role = db_fetch_object($result)) {
$user->roles[$role->rid] =
$role->name;
}
user_module_invoke('load', $array, $user);
}
else {
$user = FALSE;
}
return $user;
}
/**
* Save changes to a user account or add a new
user.
*
* @param $account
* The
$user object for the user to modify or add. If $user->uid is
*
omitted, a new user will be added.
*
* @param $array
* An
array of fields and values to save. For example array('name' => 'My name');
*
Setting a field to NULL deletes it from the data column.
*
* @param $category
*
(optional) The category for storing profile information in.
*/
function user_save($account,
$array = array(), $category = 'account') {
// Dynamically compose a SQL query:
$user_fields = user_fields();
if ($account->uid) {
user_module_invoke('update', $array,
$account, $category);
$data = unserialize(db_result(db_query('SELECT
data FROM {users} WHERE uid = %d', $account->uid)));
foreach ($array as $key => $value) {
if ($key == 'pass' &&
!empty($value)) {
$query .= "$key = '%s', ";
$v[] = md5($value);
}
else if ((substr($key, 0, 4) !== 'auth')
&& ($key != 'pass')) {
if (in_array($key, $user_fields)) {
// Save standard fields
$query .= "$key = '%s', ";
$v[] = $value;
}
else if ($key != 'roles') {
// Roles is a special case: it used
below.
if ($value === NULL) {
unset($data[$key]);
}
else {
/*
savprof
SAVING PROFILE HERE
*/
if($key == 'profile_full_name') {
$chuckTemp = $data[$key];
}
else if($key == 'profile_grad_year') {
$chuckTemp = $data[$key];
}
$data[$key] = $value;
}
}
}
}
$query .= "data = '%s' ";
$v[] = serialize($data);
db_query("UPDATE {users} SET $query
WHERE uid = %d", array_merge($v, array($account->uid)));
// Reload user roles if provided
if (is_array($array['roles'])) {
db_query('DELETE FROM {users_roles} WHERE
uid = %d', $account->uid);
foreach (array_keys($array['roles']) as
$rid) {
if (!in_array($rid,
array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
db_query('INSERT INTO {users_roles}
(uid, rid) VALUES (%d, %d)', $account->uid, $rid);
}
}
}
// Delete a blocked user's sessions to kick
them if they are online.
if (isset($array['status']) &&
$array['status'] == 0) {
sess_destroy_uid($account->uid);
}
// Refresh user object
$user = user_load(array('uid' =>
$account->uid));
user_module_invoke('after_update', $array,
$user, $category);
}
else {
$array['uid'] = db_next_id('{users}_uid');
if (!isset($array['created'])) { // Allow 'created' to be set by hook_auth
$array['created'] = time();
}
// Note, we wait with saving the data
column to prevent module-handled
// fields from being saved there. We cannot
invoke hook_user('insert') here
// because we don't have a fully
initialized user object yet.
foreach ($array as $key => $value) {
switch ($key) {
case 'pass':
$fields[] = $key;
$values[] = md5($value);
$s[] = "'%s'";
break;
case 'uid': case 'mode': case 'sort':
case 'threshold': case 'created': case 'access':
case 'login': case 'status':
$fields[] = $key;
$values[] = $value;
$s[] = "%d";
break;
default:
if (substr($key, 0, 4) !== 'auth'
&& in_array($key, $user_fields)) {
$fields[] = $key;
$values[] = $value;
$s[] = "'%s'";
}
break;
}
}
db_query('INSERT INTO {users} ('.
implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
// Build the initial user object.
$user = user_load(array('uid' =>
$array['uid']));
user_module_invoke('insert', $array, $user,
$category);
// Build and save the serialized data field
now
$data = array();
foreach ($array as $key => $value) {
if ((substr($key, 0, 4) !== 'auth')
&& ($key != 'roles') && (!in_array($key, $user_fields))
&& ($value !== NULL)) {
$data[$key] = $value;
}
}
db_query("UPDATE {users} SET data =
'%s' WHERE uid = %d", serialize($data), $user->uid);
// Save user roles (delete just to be
safe).
if (is_array($array['roles'])) {
db_query('DELETE FROM {users_roles} WHERE
uid = %d', $array['uid']);
foreach (array_keys($array['roles']) as
$rid) {
if (!in_array($rid,
array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
db_query('INSERT INTO {users_roles}
(uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
}
}
}
// Build the finished user object.
$user = user_load(array('uid' =>
$array['uid']));
}
// Save distributed authentication mappings
$authmaps = array();
foreach ($array as $key => $value) {
if (substr($key, 0, 4) == 'auth') {
$authmaps[$key] = $value;
}
}
if (sizeof($authmaps) > 0) {
user_set_authmaps($user, $authmaps);
}
return $user;
}
/**
* Verify the syntax of the given name.
*/
function
user_validate_name($name) {
if (!strlen($name)) return t('You must enter
a username.');
if (substr($name, 0, 1) == ' ') return t('The
username cannot begin with a space.');
if (substr($name, -1) == ' ') return t('The
username cannot end with a space.');
if (strpos($name, ' ') !== FALSE) return t('The username cannot
contain multiple spaces in a row.');
if (ereg("[^\x80-\xF7
[:alnum:]@_.-]", $name)) return t('The username contains an illegal
character.');
if (preg_match('/[\x{80}-\x{A0}'. // Non-printable ISO-8859-1 + NBSP
'\x{AD}'. // Soft-hyphen
'\x{2000}-\x{200F}'. // Various space characters
'\x{2028}-\x{202F}'. // Bidirectional text overrides
'\x{205F}-\x{206F}'. // Various text hinting characters
'\x{FEFF}'. // Byte order mark
'\x{FF01}-\x{FF60}'. // Full-width latin
'\x{FFF9}-\x{FFFD}'. // Replacement characters
'\x{0}]/u', // NULL byte
$name)) {
return t('The username contains an illegal
character.');
}
if (strpos($name, '@') !== FALSE &&
!eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return
t('The username is not a valid authentication ID.');
if (strlen($name) > USERNAME_MAX_LENGTH)
return t('The username %name is too long: it must be %max characters or less.',
array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
}
function
user_validate_mail($mail) {
if (!$mail) return t('You must enter an
e-mail address.');
if (!valid_email_address($mail)) {
return t('The e-mail address %mail is not
valid.', array('%mail' => $mail));
}
}
function
user_validate_picture($file, &$edit, $user) {
global $form_values;
// Initialize the picture:
$form_values['picture'] = $user->picture;
// Check that uploaded file is an image, with
a maximum file size
// and maximum height/width.
$info = image_get_info($file->filepath);
list($maxwidth, $maxheight) = explode('x',
variable_get('user_picture_dimensions', '85x85'));
if (!$info || !$info['extension']) {
form_set_error('picture_upload', t('The
uploaded file was not an image.'));
}
else if (image_get_toolkit()) {
image_scale($file->filepath,
$file->filepath, $maxwidth, $maxheight);
}
else if (filesize($file->filepath) >
(variable_get('user_picture_file_size', '30') * 1000)) {
form_set_error('picture_upload', t('The uploaded
image is too large; the maximum file size is %size kB.', array('%size' =>
variable_get('user_picture_file_size', '30'))));
}
else if ($info['width'] > $maxwidth ||
$info['height'] > $maxheight) {
form_set_error('picture_upload', t('The uploaded
image is too large; the maximum dimensions are %dimensions pixels.',
array('%dimensions' => variable_get('user_picture_dimensions', '85x85'))));
}
if (!form_get_errors()) {
if ($file =
file_save_upload('picture_upload', variable_get('user_picture_path',
'pictures') .'/picture-'. $user->uid .'.'. $info['extension'], 1)) {
$form_values['picture'] =
$file->filepath;
}
else {
form_set_error('picture_upload',
t("Failed to upload the picture image; the %directory directory doesn't
exist.", array('%directory' => variable_get('user_picture_path',
'pictures'))));
}
}
}
/**
* Generate a random alphanumeric password.
*/
function
user_password($length = 10) {
// This variable contains the list of
allowable characters for the
// password. Note that the number 0 and the
letter 'O' have been
// removed to avoid confusion between the
two. The same is true
// of 'I', 1, and l.
$allowable_characters =
'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
// Zero-based count of characters in the
allowable list:
$len = strlen($allowable_characters) - 1;
// Declare the password as a blank string.
$pass = '';
// Loop the number of times specified by
$length.
for ($i = 0; $i < $length; $i++) {
// Each iteration, pick a random character
from the
// allowable string and append it to the
password:
$pass .= $allowable_characters[mt_rand(0,
$len)];
}
return $pass;
}
/**
* Determine whether the user has a given
privilege.
*
* @param $string
* The
permission, such as "administer nodes", being checked for.
* @param $account
*
(optional) The account to check, if not given use currently logged in
user.
*
* @return
*
boolean TRUE if the current user has the requested permission.
*
* All permission checks in Drupal should go
through this function. This
* way, we guarantee consistent behavior, and
ensure that the superuser
* can perform all actions.
*/
function user_access($string,
$account = NULL) {
global $user;
static $perm = array();
if (is_null($account)) {
$account = $user;
}
// User #1 has all privileges:
if ($account->uid == 1) {
return TRUE;
}
// To reduce the number of SQL queries, we
cache the user's permissions
// in a static variable.
if (!isset($perm[$account->uid])) {
$result = db_query("SELECT
DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE
r.rid IN (%s)", implode(',', array_keys($account->roles)));
$perm[$account->uid] = '';
while ($row = db_fetch_object($result)) {
$perm[$account->uid] .=
"$row->perm, ";
}
}
if (isset($perm[$account->uid])) {
return strpos($perm[$account->uid],
"$string, ") !== FALSE;
}
return FALSE;
}
/**
* Checks for usernames blocked by user
administration
*
* @return boolean TRUE for blocked users,
FALSE for active
*/
function
user_is_blocked($name) {
$deny
= db_fetch_object(db_query("SELECT name FROM {users} WHERE status =
0 AND name = LOWER('%s')", $name));
return $deny;
}
function user_fields() {
static $fields;
if (!$fields) {
$result = db_query('SELECT * FROM {users}
WHERE uid = 1');
if (db_num_rows($result)) {
$fields =
array_keys(db_fetch_array($result));
}
else {
// Make sure we return the default fields
at least
$fields = array('uid', 'name', 'pass',
'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature',
'created', 'access', 'login', 'status', 'timezone', 'language', 'init',
'data');
}
}
return $fields;
}
/**
* Implementation of hook_perm().
*/
function user_perm() {
return array('administer access control',
'administer users', 'access user profiles', 'change own username');
}
/**
* Implementation of hook_file_download().
*
* Ensure that user pictures (avatars) are
always downloadable.
*/
function
user_file_download($file) {
if (strpos($file,
variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
$info =
image_get_info(file_create_path($file));
return array('Content-type: '.
$info['mime_type']);
}
}
/**
* Implementation of hook_search().
*/
/**
function user_search($op =
'search', $keys = NULL) {
switch ($op) {
case 'name':
if (user_access('access user profiles'))
{
return t('Users');
}
case 'search':
if
(user_access('access user profiles')) {
$find = array();
// Replace wildcards with
MySQL/PostgreSQL wildcards.
$keys = preg_replace('!\*+!', '%',
$keys);
$result = pager_query("SELECT *
FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
while ($account =
db_fetch_object($result)) {
$find[] = array('title' =>
$account->name, 'link' => url('user/'. $account->uid, NULL, NULL,
TRUE));
}
return $find;
}
}
}
*/
/**
* Implementation of hook_user().
*/
function user_user($type,
&$edit, &$user, $category = NULL) {
if ($type == 'view') {
$items['history'] = array('title' =>
t('Member for'),
'value' => format_interval(time() -
$user->created),
'class' => 'member',
);
return array(t('History') => $items);
}
if ($type == 'form' && $category ==
'account') {
return user_edit_form(arg(1), $edit);
}
if ($type == 'validate' && $category
== 'account') {
return _user_edit_validate(arg(1), $edit);
}
if ($type == 'submit' && $category ==
'account') {
return _user_edit_submit(arg(1), $edit);
}
if ($type == 'categories') {
return array(array('name' => 'account',
'title' => t('Account settings'), 'weight' => 1));
}
}
function user_login_block() {
$form = array(
'#action' => url($_GET['q'],
drupal_get_destination()),
'#id' => 'user-login-form',
'#base' => 'user_login',
);
$form['name'] = array('#type' =>
'textfield',
'#title' => t('Username'),
'#maxlength' => USERNAME_MAX_LENGTH,
'#size' => 15,
'#required' => TRUE,
);
$form['pass'] = array('#type' =>
'password',
'#title' => t('Password'),
'#maxlength' => 60,
'#size' => 15,
'#required' => TRUE,
);
$form['submit'] = array('#type' =>
'submit',
'#value' => t('Log in'),
);
$items = array();
if (variable_get('user_register', 1)) {
$items[] = l(t('Create new account'),
'user/register', array('title' => t('Create a new user account.')));
}
$items[] = l(t('Request new password'),
'user/password', array('title' => t('Request new password via e-mail.')));
$form['links'] = array('#value' =>
theme('item_list', $items));
return $form;
}
/**
* Implementation of hook_block().
*/
function user_block($op = 'list',
$delta = 0, $edit = array()) {
global $user;
if ($op == 'list') {
$blocks[0]['info'] = t('User login');
$blocks[1]['info'] = t('Navigation');
$blocks[2]['info'] = t('Who\'s new');
$blocks[3]['info'] = t('Who\'s online');
return $blocks;
}
else if ($op == 'configure' && $delta
== 2) {
$form['user_block_whois_new_count'] =
array(
'#type' => 'select',
'#title' => t('Number of users to
display'),
'#default_value' =>
variable_get('user_block_whois_new_count', 5),
'#options' =>
drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
);
return $form;
}
else if ($op == 'configure' && $delta
== 3) {
$period = drupal_map_assoc(array(30, 60,
120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200,
86400), 'format_interval');
$form['user_block_seconds_online'] =
array('#type' => 'select', '#title' => t('User activity'),
'#default_value' => variable_get('user_block_seconds_online', 900),
'#options' => $period, '#description' => t('A user is considered online
for this long after they have last viewed a page.'));
$form['user_block_max_list_count'] =
array('#type' => 'select', '#title' => t('User list length'),
'#default_value' => variable_get('user_block_max_list_count', 10),
'#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75,
100)), '#description' => t('Maximum number of currently online users to
display.'));
return $form;
}
else if ($op == 'save' && $delta ==
2) {
variable_set('user_block_whois_new_count',
$edit['user_block_whois_new_count']);
}
else if ($op == 'save' && $delta ==
3) {
variable_set('user_block_seconds_online',
$edit['user_block_seconds_online']);
variable_set('user_block_max_list_count',
$edit['user_block_max_list_count']);
}
else if ($op == 'view') {
$block = array();
switch ($delta) {
case 0:
// For usability's sake, avoid showing
two login forms on one page.
if (!$user->uid && !(arg(0)
== 'user' && !is_numeric(arg(1)))) {
$block['subject'] = t('User login');
$block['content'] =
drupal_get_form('user_login_block');
}
return $block;
case 1:
if ($menu = theme('menu_tree')) {
$block['subject'] = $user->uid ?
check_plain($user->name) : t('Navigation');
$block['content'] = $menu;
}
return $block;
case 2:
if (user_access('access content')) {
// Retrieve a list of new users who
have subsequently accessed the site successfully.
$result = db_query_range('SELECT uid,
name FROM {users} WHERE status != 0 AND access != 0 ORDER BY name ASC', 0,
variable_get('user_block_whois_new_count', 5));
while ($account =
db_fetch_object($result)) {
$items[] = $account;
}
$output = theme('user_list', $items);
$block['subject'] = t('Who\'s new');
$block['content'] = $output;
}
return $block;
case 3:
if (user_access('access content')) {
// Count users with activity in the
past defined period.
$interval = time() -
variable_get('user_block_seconds_online', 900);
// Perform database queries to gather
online user lists. We use s.timestamp
// rather than u.access because it is
much faster is much faster..
$anonymous_count =
sess_count($interval);
$authenticated_users =
db_query('SELECT u.uid, u.name FROM {users} u INNER JOIN {sessions} s ON u.uid
= s.uid WHERE s.timestamp >= %d AND s.uid > 0 ORDER BY s.timestamp DESC',
$interval);
$authenticated_count =
db_num_rows($authenticated_users);
// Format the output with proper
grammar.
if ($anonymous_count == 1 &&
$authenticated_count == 1) {
$output = t('There is currently
%members and %visitors online.', array('%members' =>
format_plural($authenticated_count, '1 user', '@count users'), '%visitors'
=> format_plural($anonymous_count, '1 guest', '@count guests')));
}
else {
$output = t('There are currently
%members and %visitors online.', array('%members' =>
format_plural($authenticated_count, '1 user', '@count users'), '%visitors'
=> format_plural($anonymous_count, '1 guest', '@count guests')));
}
// Display a list of currently online
users.
$max_users =
variable_get('user_block_max_list_count', 10);
if ($authenticated_count &&
$max_users) {
$items = array();
while ($max_users-- &&
$account = db_fetch_object($authenticated_users)) {
$items[] = $account;
}
$output .= theme('user_list',
$items, t('Online users'));
}
$block['subject'] = t('Who\'s
online');
$block['content'] = $output;
}
return $block;
}
}
}
function
theme_user_picture($account) {
if (variable_get('user_pictures', 0)) {
if ($account->picture &&
file_exists($account->picture)) {
$picture =
file_create_url($account->picture);
}
else if
(variable_get('user_picture_default', '')) {
$picture =
variable_get('user_picture_default', '');
}
if (isset($picture)) {
$alt = t("@user's picture",
array('@user' => $account->name ? $account->name :
variable_get('anonymous', t('Anonymous'))));
$picture = theme('image', $picture, $alt,
$alt, '', FALSE);
if (!empty($account->uid) &&
user_access('access user profiles')) {
$picture = l($picture,
"user/$account->uid", array('title' => t('View user
profile.')), NULL, NULL, FALSE, TRUE);
}
return "<div
class=\"picture\">$picture</div>";
}
}
}
/**
* Theme a user page
* @param $account the user object
* @param $fields a multidimensional array for
the fields, in the form of array (
*
'category1' => array(item_array1, item_array2), 'category2' =>
array(item_array3,
* ..
etc.). Item arrays are formatted as array(array('title' => 'item title',
* 'value' => 'item value', 'class' =>
'class-name'), ... etc.). Module names are incorporated
* into the CSS class.
*
* @ingroup themeable
*/
function
theme_user_profile($account, $fields) {
$start = '<div
class="profile">';
$count1 = 0;
$count2 = 0;
$quote = '';
foreach ($fields as $category => $items) {
$output = '';
if (strlen($category) > 0) {
if($count1 == 0)
{
$career = '<div
id="career">';
}
else if($count1 == 1)
{
$picture .=
theme('user_picture', $account);
$college = '<div
id="college">';
$count1 = $count1 + 1;
}
else if( $count1 == 2)
{
}
else if ( $count1 == 3)
{
$personal = '<div
id="personal">';
}
$output .= '<h2
class="title">'. $category .'</h2>';
}
$output .= '<dl>';
foreach ($items as $item) {
if (isset($item['title'])) {
$output .= '<dt
class="'. $item['class'] .'">'. $item['title'] .'</dt>';
}
$output .= '<dd
class="'. $item['class'] .'">'. $item['value'] .'</dd>';
if (
$_SESSION['admin'] == 1)
{
if($item['class']=='profile-profile_full_name') {
$fullname = $item['value'];
$fullname = strip_tags($fullname);
}
else
if($item['class']=='profile-profile_grad_year') {
$gradyear = $item['value'];
$gradyear = strip_tags($gradyear);
}
else
if($item['class']=='profile-profile_home_address') {
$location = $item['value'];
$location = strip_tags($location);
}
else
if($item['class']=='profile-profile_major') {
$major = $item['value'];
$major = strip_tags($major);
}
else
if($item['class']=='profile-profile_fav_class') {
$favclass = $item['value'];
$favclass = strip_tags($favclass);
}
else
if($item['class']=='profile-profile_exp') {
$exper = $item['value'];
$exper = strip_tags($exper);
$order = array("\r\n", "\n",
"\r");
$exper = str_replace($order, ' ', $exper);
$exper = str_replace("'", "\'",
$exper);
}
else
if($item['class']=='profile-profile_web_site') {
$website = $item['value'];
$website = strip_tags($website);
}
else
if($item['class']=='profile-profile_company') {
$company = $item['value'];
$company = strip_tags($company);
}
else
if($item['class']=='profile-profile_minor') {
$minor = $item['value'];
$minor = strip_tags($minor);
}
else
if($item['class']=='profile-profile_fav_teacher') {
$favteacher = $item['value'];
$favteacher = strip_tags($favteacher);
}
else
if($item['class']=='profile-profile_quote') {
$favquote = $item['value'];
$favquote = strip_tags($favquote);
$order = array("\r\n", "\n",
"\r");
$favquote = str_replace($order, ' ', $favquote);
$favquote = str_replace("'", "\'",
$favquote);
}
else
if($item['class']=='profile-profile_grad_school') {
$gradschool = $item['value'];
$gradschool = strip_tags($gradschool);
}
}
}
$output .= '</dl>';
$count1 = $count1 + 1;
if(($count1 !=2) && ($count1
<5)) {
$output .= '</div>';
}
if($count2 == 0)
{
$career .= $output;
}
else if($count2 == 1)
{
$college .= $output;
$count2 = $count2 + 1;
}
else if( $count2 == 2)
{
}
else if ( $count2 == 3)
{
$personal .= $output;
}
$count2 = $count2 + 1;
}
// Construct output the way we need it to be
$tempHold = $output;
$output = $start;
$output .= $picture;
$output .= $personal;
$output .= $college;
$output .= $career;
$output .= '</div>';
$output .= '<p
style="clear:both"> </p>';
if( $_SESSION['admin'] == 1)
{
$UserIDNum = $account->uid;
$output .= '<input
type="button" value="Spotlight User"
onClick="document.location=\'/spotlight/spotlight.php?FullName=' .
$fullname;
$output .= '&GradYear='.$gradyear .
'&Hometown=' . $location . '&Major=' . $major . '&FavClass=' .
$favclass . '&Experience=' . $exper;
$output .= '&WebSite='.$website .
'&Company=' . $company . '&Minor=' . $minor . '&FavTeacher=' .
$favteacher . '&FavQuote=' .$favquote;
$output .= '&GradSchool=' .
$gradschool;
$output .=
'&UserIDNum='.$UserIDNum.'\';">';
}
return $output;
}
/**
function
theme_user_profile($account, $fields) {
$output = '<div
class="profile">';
$output .= theme('user_picture', $account);
foreach ($fields as $category => $items) {
if (strlen($category) > 0) {
$output .= '<h2
class="title">'. $category .'</h2>';
}
$output .= '<dl>';
foreach ($items as $item) {
if (isset($item['title'])) {
$output .= '<dt class="'.
$item['class'] .'">'. $item['title'] .'</dt>';
}
$output .= '<dd class="'.
$item['class'] .'">'. $item['value'] .'</dd>';
}
$output .= '</dl>';
}
$output .= '</div>';
return $output;
}
*/
/**
* Make a list of users.
* @param $items an array with user objects.
Should contain at least the name and uid
*
* @ingroup themeable
*/
function
theme_user_list($users, $title = NULL) {
if (!empty($users)) {
foreach ($users as $user) {
$items[] = theme('username', $user);
}
}
return theme('item_list', $items, $title);
}
/**
* Implementation of hook_menu().
*/
function
user_menu($may_cache) {
global $user;
$items = array();
$admin_access = user_access('administer
users');
$access_access = user_access('administer
access control');
$view_access = user_access('access user
profiles');
if ($may_cache) {
$items[] = array('path' => 'user',
'title' => t('User account'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_login'),
'access' => !$user->uid, 'type'
=> MENU_CALLBACK);
$items[] = array('path' =>
'user/autocomplete', 'title' => t('User autocomplete'),
'callback' => 'user_autocomplete',
'access' => $view_access, 'type' => MENU_CALLBACK);
// Registration and login pages.
$items[] = array('path' => 'user/login',
'title' => t('Log in'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_login'),
'access' => !$user->uid, 'type'
=> MENU_DEFAULT_LOCAL_TASK);
$items[] = array('path' =>
'user/register', 'title' => t('Create new account'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_register'), 'access' =>
!$user->uid && variable_get('user_register', 1), 'type' =>
MENU_LOCAL_TASK);
$items[] = array('path' =>
'user/password', 'title' => t('Request new password'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_pass'), 'access' => !$user->uid,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'user/reset',
'title' => t('Reset password'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_pass_reset'), 'access' => TRUE,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'user/help',
'title' => t('Help'),
'callback' => 'user_help_page', 'type'
=> MENU_CALLBACK);
// Admin user pages
$items[] = array('path' => 'admin/user',
'title' => t('User management'),
'description' => t('Manage your
site\'s users, groups and access to site features.'),
'position' => 'left',
'callback' =>
'system_admin_menu_block_page',
'access' => user_access('administer
site configuration'),
);
$items[] = array('path' =>
'admin/user/user', 'title' => t('Users'),
'description' => t('List, add, and
edit users.'),
'callback' => 'user_admin', 'callback
arguments' => array('list'), 'access' => $admin_access);
$items[] = array('path' =>
'admin/user/user/list', 'title' => t('List'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10);
$items[] = array('path' =>
'admin/user/user/create', 'title' => t('Add user'),
'callback' => 'user_admin', 'callback
arguments' => array('create'), 'access' => $admin_access,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' =>
'admin/user/settings', 'title' => t('User settings'),
'description' => t('Configure default
behavior of users, including registration requirements, e-mails, and user
pictures.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_admin_settings'));
// Admin access pages
$items[] = array('path' =>
'admin/user/access', 'title' => t('Access control'),
'description' => t('Determine access
to features by selecting permissions for roles.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_admin_perm'), 'access' =>
$access_access);
$items[] = array('path' =>
'admin/user/roles', 'title' => t('Roles'),
'description' => t('List, edit, or add
user roles.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_admin_new_role'), 'access' =>
$access_access,
'type' => MENU_NORMAL_ITEM);
$items[] = array('path' =>
'admin/user/roles/edit', 'title' => t('Edit role'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_admin_role'), 'access' =>
$access_access,
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'admin/user/rules', 'title' => t('Access rules'),
'description' => t('List and create
rules to disallow usernames, e-mail addresses, and IP addresses.'),
'callback' => 'user_admin_access',
'access' => $access_access);
$items[] = array('path' =>
'admin/user/rules/list', 'title' => t('List'),
'access' => $access_access, 'type'
=> MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' =>
'admin/user/rules/add', 'title' => t('Add rule'),
'callback' => 'user_admin_access_add',
'access' => $access_access,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' =>
'admin/user/rules/check', 'title' => t('Check rules'),
'callback' =>
'user_admin_access_check', 'access' => $access_access,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'admin/user/rules/edit',
'title' => t('Edit rule'),
'callback' =>
'user_admin_access_edit', 'access' => $access_access,
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'admin/user/rules/delete', 'title' => t('Delete rule'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_admin_access_delete_confirm'),
'access' => $access_access, 'type'
=> MENU_CALLBACK);
if (module_exists('search')) {
$items[] = array('path' =>
'admin/user/search', 'title' => t('Search users'),
'description' => t('Search users by
name.'),
'callback' => 'user_admin',
'callback arguments' => array('search'), 'access' => $admin_access,
'type' => MENU_NORMAL_ITEM);
}
// Your personal page
if ($user->uid) {
$items[] = array('path' => 'user/'.
$user->uid, 'title' => t('My account'),
'callback' => 'user_view', 'callback
arguments' => array(arg(1)), 'access' => TRUE,
'type' => MENU_DYNAMIC_ITEM);
}
$items[] = array('path' => 'logout',
'title' => t('Log out'),
'access' => $user->uid,
'callback' => 'user_logout',
'weight' => 10);
}
else {
// Add the CSS for this module. We put this
in !$may_cache so it is only
// added once per request.
drupal_add_css(drupal_get_path('module',
'user') .'/user.css', 'module');
if ($_GET['q'] == 'user' &&
$user->uid) {
// We want to make the current user's
profile accessible without knowing
// their uid, so just linking to /user is
enough.
drupal_goto('user/'. $user->uid);
}
if (arg(0) == 'user' &&
is_numeric(arg(1)) && arg(1) > 0) {
$account = user_load(array('uid' =>
arg(1)));
if ($user !== FALSE) {
// Always let a user view their own
account
$view_access |= $user->uid ==
arg(1);
// Only admins can view blocked
accounts
$view_access &= $account->status
|| $admin_access;
$items[] = array('path' => 'user/'.
arg(1), 'title' => t('User'),
'type' => MENU_CALLBACK,
'callback' => 'user_view',
'callback arguments' =>
array(arg(1)), 'access' => $view_access);
$items[] = array('path' => 'user/'.
arg(1) .'/view', 'title' => t('View'),
'access' => $view_access, 'type'
=> MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'user/'.
arg(1) .'/edit', 'title' => t('Edit'),
'callback' => 'drupal_get_form',
'callback arguments' => array('user_edit'),
'access' => $admin_access ||
$user->uid == arg(1), 'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'user/'. arg(1) .'/delete',
'title' => t('Delete'),
'callback' => 'user_edit',
'access' => $admin_access,
'type' => MENU_CALLBACK);
if (arg(2) == 'edit') {
if (($categories =
_user_categories($account)) && (count($categories) > 1)) {
foreach ($categories as $key =>
$category) {
$items[] = array(
'path' => 'user/'. arg(1)
.'/edit/'. $category['name'],
'title' => $category['title'],
'type' => $category['name']
== 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
'weight' =>
$category['weight'],
'access' => ($admin_access
|| $user->uid == arg(1)));
}
}
}
}
}
}
return $items;
}
/**
* Accepts an user object, $account, or a DA
name and returns an associative
* array of modules and DA names. Called at
external login.
*/
function
user_get_authmaps($authname = NULL) {
$result = db_query("SELECT authname,
module FROM {authmap} WHERE authname = '%s'", $authname);
if (db_num_rows($result) > 0) {
while ($authmap = db_fetch_object($result))
{
$authmaps[$authmap->module] =
$authmap->authname;
}
return $authmaps;
}
else {
return 0;
}
}
function
user_set_authmaps($account, $authmaps) {
foreach ($authmaps as $key => $value) {
$module = explode('_', $key, 2);
if ($value) {
db_query("UPDATE {authmap} SET
authname = '%s' WHERE uid = %d AND module = '%s'", $value,
$account->uid, $module[1]);
if (!db_affected_rows()) {
db_query("INSERT INTO {authmap}
(authname, uid, module) VALUES ('%s', %d, '%s')", $value,
$account->uid, $module[1]);
}
}
else {
db_query("DELETE FROM {authmap}
WHERE uid = %d AND module = '%s'", $account->uid, $module[1]);
}
}
}
function
user_auth_help_links() {
$links = array();
foreach (module_list() as $module) {
if (module_hook($module, 'auth')) {
$links[] = l(module_invoke($module,
'info', 'name'), 'user/help', array(), NULL, $module);
}
}
return $links;
}
/*** User features
*********************************************************/
function user_login($msg =
'') {
global $user;
// If we are already logged on, go to the
user page instead.
if ($user->uid) {
drupal_goto('user/'. $user->uid);
}
// Display login form:
if ($msg) {
$form['message'] = array('#value' =>
'<p>'. check_plain($msg) .'</p>');
}
$form['name'] = array('#type' => 'textfield',
'#title' => t('Username'),
'#size' => 60,
'#maxlength' => USERNAME_MAX_LENGTH,
'#required' => TRUE,
'#attributes' => array('tabindex' =>
'1'),
);
if
(variable_get('drupal_authentication_service', FALSE) &&
count(user_auth_help_links()) > 0) {
$form['name']['#description'] = t('Enter
your @s username, or an ID from one of our affiliates: !a.', array('@s' =>
variable_get('site_name', 'Drupal'), '!a' => implode(', ',
user_auth_help_links())));
}
else {
$form['name']['#description'] = t('Enter
your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
}
$form['pass'] = array('#type' =>
'password',
'#title' => t('Password'),
'#description' => t('Enter the password
that accompanies your username.'),
'#required' => TRUE,
'#attributes' => array('tabindex' =>
'2'),
);
$form['submit'] = array('#type' =>
'submit', '#value' => t('Log in'), '#weight' => 2, '#attributes' =>
array('tabindex' => '3'));
return $form;
}
function user_login_validate($form_id,
$form_values) {
if ($form_values['name']) {
if (user_is_blocked($form_values['name']))
{
// blocked in user administration
form_set_error('login', t('The username
%name has not been activated or is blocked.', array('%name' =>
$form_values['name'])));
}
else if (drupal_is_denied('user',
$form_values['name'])) {
// denied by access controls
form_set_error('login', t('The name %name
is a reserved username.', array('%name' => $form_values['name'])));
}
else if ($form_values['pass']) {
$user =
user_authenticate($form_values['name'], trim($form_values['pass']));
if (!$user->uid) {
form_set_error('login', t('Sorry,
unrecognized username or password. <a href="@password">Have you
forgotten your password?</a>', array('@password' =>
url('user/password'))));
watchdog('user', t('Login attempt
failed for %user.', array('%user' => $form_values['name'])));
}
}
}
}
function
user_login_submit($form_id, $form_values) {
global $user;
if ($user->uid) {
// To handle the edge case where this
function is called during a
// bootstrap, check for the existence of
t().
if (function_exists('t')) {
$message = t('Session opened for %name.',
array('%name' => $user->name));
}
else {
$message = "Session opened for
". check_plain($user->name);
}
watchdog('user', $message);
// Update the user table timestamp noting
user has logged in.
db_query("UPDATE {users} SET login =
%d WHERE uid = %d", time(), $user->uid);
user_module_invoke('login', $form_values,
$user);
sess_regenerate();
$_SESSION['admin'] = $user->uid;
return 'user/'. $user->uid;
}
}
function
user_authenticate($name, $pass) {
global $user;
// Try to log in the user locally. Don't set
$user unless successful.
if ($account = user_load(array('name' =>
$name, 'pass' => $pass, 'status' => 1))) {
$user = $account;
return $user;
}
// Strip name and server from ID:
if ($server = strrchr($name, '@')) {
$name = substr($name, 0, strlen($name) -
strlen($server));
$server = substr($server, 1);
}
// When possible, determine corresponding
external auth source. Invoke
// source, and log in user if successful:
if ($server && ($result = user_get_authmaps("$name@$server")))
{
if (module_invoke(key($result), 'auth',
$name, $pass, $server)) {
$user =
user_external_load("$name@$server");
watchdog('user', t('External load by
%user using module %module.', array('%user' => $name .'@'. $server,
'%module' => key($result))));
}
}
// Try each external authentication source in
series. Register user if
// successful.
else {
foreach (module_implements('auth') as
$module) {
if (module_invoke($module, 'auth', $name,
$pass, $server)) {
if ($server) {
$name .= '@'. $server;
}
$user = user_load(array('name' =>
$name));
if (!$user->uid) { // Register this
new user.
$userinfo = array('name' => $name,
'pass' => user_password(), 'init' => $name, 'status' => 1);
if ($server) {
$userinfo["authname_$module"] = $name;
}
$user = user_save('', $userinfo);
watchdog('user', t('New external
user: %user using module %module.', array('%user' => $name, '%module' =>
$module)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
break;
}
}
}
}
return $user;
}
/**
* Menu callback; logs the current user out,
and redirects to the home page.
*/
function user_logout() {
global $user;
watchdog('user', t('Session closed for
%name.', array('%name' => $user->name)));
// Destroy the current session:
session_destroy();
module_invoke_all('user', 'logout', NULL,
$user);
// Load the anonymous user
$user = drupal_anonymous_user();
drupal_goto();
}
function user_pass() {
$string = '<p> To get
your user name/password please send an email to the admin at <a
href="mailto:ebreimer@gmail.com?subject=Siena College Alumni Spotlight
System: Lost Password">by clicking here.</a> You can also send
him an email at ebreimer@gmail.com. The admin will return you your current
password, or you may request to have it reset. Simply state what you would like
your new password to be.</p>';
drupal_set_message(t($string));
$form['submit'] = array('#type' =>
'submit',
'#value' => t('Go Back to Home'),
'#weight' => 2
);
return $form;
}
function
user_pass_validate($form_id, $form_values) {
unset($_SESSION['messages']);
drupal_goto('node/8');
/*
$name = $form_values['name'];
$account = user_load(array('mail' =>
$name, 'status' => 1));
if (!$account) {
$account = user_load(array('name' =>
$name, 'status' => 1));
}
if ($account->uid) {
form_set_value(array('#parents' =>
array('account')), $account);
}
else {
form_set_error('name', t('Sorry, %name is
not recognized as a user name or an email address.', array('%name' =>
$name)));
}
*/
}
function
user_pass_submit($form_id, $form_values) {
/*
global $base_url;
$account = $form_values['account'];
$from = variable_get('site_mail',
ini_get('sendmail_from'));
// Mail one time login URL and instructions.
$variables = array('!username' =>
$account->name, '!site' => variable_get('site_name', 'Drupal'),
'!login_url' => user_pass_reset_url($account), '!uri' => $base_url,
'!uri_brief' => substr($base_url, strlen('http://')), '!mailto' =>
$account->mail, '!date' => format_date(time()), '!login_uri' =>
url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid
.'/edit', NULL, NULL, TRUE));
$subject = _user_mail_text('pass_subject',
$variables);
$body = _user_mail_text('pass_body',
$variables);
$mail_success = drupal_mail('user-pass',
$account->mail, $subject, $body, $from);
if ($mail_success) {
watchdog('user', t('Password reset
instructions mailed to %name at %email.', array('%name' =>
$account->name, '%email' => $account->mail)));
drupal_set_message(t('Further instructions
have been sent to your e-mail address.'));
}
else {
watchdog('user', t('Error mailing password
reset instructions to %name at %email.', array('%name' => $account->name,
'%email' => $account->mail)), WATCHDOG_ERROR);
drupal_set_message(t('Unable to send mail.
Please contact the site admin.'));
}
return 'user';
*/
}
/**
* Menu callback; process one time login link
and redirects to the user page on success.
*/
function
user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) {
global $user;
// Check if the user is already logged in.
The back button is often the culprit here.
if ($user->uid) {
drupal_set_message(t('You have already used
this one-time login link. It is not necessary to use this link to login
anymore. You are already logged in.'));
drupal_goto();
}
else {
// Time out, in seconds, until login URL
expires. 24 hours = 86400 seconds.
$timeout = 86400;
$current = time();
// Some redundant checks for extra security
?
if ($timestamp < $current &&
$account = user_load(array('uid' => $uid, 'status' => 1)) ) {
// No time out for first time login.
if ($account->login &&
$current - $timestamp > $timeout) {
drupal_set_message(t('You have tried to
use a one-time login link that has expired. Please request a new one using the
form below.'));
drupal_goto('user/password');
}
else if ($account->uid &&
$timestamp > $account->login && $timestamp < $current
&& $hashed_pass == user_pass_rehash($account->pass, $timestamp,
$account->login)) {
// First stage is a confirmation form,
then login
if ($action == 'login') {
watchdog('user', t('User %name used
one-time login link at time %timestamp.', array('%name' =>
$account->name, '%timestamp' => $timestamp)));
// Update the user table noting user
has logged in.
// And this also makes this hashed
password a one-time-only login.
db_query("UPDATE {users} SET
login = %d WHERE uid = %d", time(), $account->uid);
// Now we can set the new user.
$user = $account;
// And proceed with normal login,
going to user page.
$edit = array();
user_module_invoke('login', $edit,
$user);
drupal_set_message(t('You have just
used your one-time login link. It is no longer necessary to use this link to
login. Please change your password.'));
drupal_goto('user/'. $user->uid
.'/edit');
}
else {
$form['message'] = array('#value'
=> t('<p>This is a one-time login for %user_name and will expire on
%expiration_date</p><p>Click on this button to login to the site
and change your password.</p>', array('%user_name' =>
$account->name, '%expiration_date' => format_date($timestamp +
$timeout))));
$form['help'] = array('#value' =>
'<p>'. t('This login can be used only once.') .'</p>');
$form['submit'] = array('#type' =>
'submit', '#value' => t('Log in'));
$form['#action'] =
url("user/reset/$uid/$timestamp/$hashed_pass/login");
return $form;
}
}
else {
drupal_set_message(t('You have tried to
use a one-time login link which has either been used or is no longer valid.
Please request a new one using the form below.'));
drupal_goto('user/password');
}
}
else {
// Deny access, no more clues.
// Everything will be in the watchdog's
URL for the administrator to check.
drupal_access_denied();
}
}
}
function
user_pass_reset_url($account) {
$timestamp = time();
return
url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass,
$timestamp, $account->login), NULL, NULL, TRUE);
}
function
user_pass_rehash($password, $timestamp, $login) {
return md5($timestamp . $password . $login);
}
function user_register() {
global $user;
$admin = user_access('administer users');
// If we aren't admin but already logged on,
go to the user page instead.
if (!$admin && $user->uid) {
drupal_goto('user/'. $user->uid);
}
$form = array();
// Display the registration form.
if (!$admin) {
$form['user_registration_help'] =
array('#value' => filter_xss_admin(variable_get('user_registration_help',
'')));
}
$affiliates = user_auth_help_links();
if (!$admin && count($affiliates)
> 0) {
$affiliates = implode(', ', $affiliates);
$form['affiliates'] = array('#value' =>
'<p>'. t('Note: if you have an account with one of our affiliates (!s),
you may <a href="@login_uri">login now</a> instead of
registering.', array('!s' => $affiliates, '@login_uri' => url('user')))
.'</p>');
}
// Merge in the default user edit fields.
$form = array_merge($form,
user_edit_form(NULL, NULL, TRUE));
if ($admin) {
$form['account']['notify'] = array(
'#type' => 'checkbox',
'#title' => t('Notify user of new
account')
);
// Redirect back to page which initiated
the create request; usually admin/user/user/create
$form['destination'] = array('#type' =>
'hidden', '#value' => $_GET['q']);
}
// Create a dummy variable for
pass-by-reference parameters.
$null = NULL;
$extra = _user_forms($null, NULL, NULL, 'register');
// Remove form_group around default fields if
there are no other groups.
if (!$extra) {
$form['name'] = $form['account']['name'];
$form['mail'] = $form['account']['mail'];
$form['pass'] = $form['account']['pass'];
$form['status'] =
$form['account']['status'];
$form['roles'] = $form['account']['roles'];
$form['notify'] =
$form['account']['notify'];
unset($form['account']);
}
else {
$form = array_merge($form, $extra);
}
$form['submit'] = array('#type' => 'submit',
'#value' => t('Create new account'), '#weight' => 30);
return $form;
}
function
user_register_validate($form_id, $form_values) {
user_module_invoke('validate', $form_values,
$form_values, 'account');
}
function
user_register_submit($form_id, $form_values) {
global $base_url;
$admin = user_access('administer users');
$mail = $form_values['mail'];
$name = $form_values['name'];
if (!variable_get('user_email_verification',
TRUE) || $admin) {
$pass = $form_values['pass'];
}
else {
$pass = user_password();
};
$notify = $form_values['notify'];
$from = variable_get('site_mail',
ini_get('sendmail_from'));
if (isset($form_values['roles'])) {
$roles =
array_filter($form_values['roles']);
// Remove unset roles
}
if (!$admin &&
array_intersect(array_keys($form_values), array('uid', 'roles', 'init',
'session', 'status'))) {
watchdog('security', t('Detected malicious
attempt to alter protected user fields.'), WATCHDOG_WARNING);
return 'user/register';
}
//the
unset below is needed to prevent these form values from being saved as user
data
unset($form_values['form_token'],
$form_values['submit'], $form_values['op'], $form_values['notify'],
$form_values['form_id'], $form_values['affiliates'], $form_values['destination']);
$merge_data = array('pass' => $pass,
'init' => $mail, 'roles' => $roles);
if (!$admin) {
// Set the user's status because it was not
displayed in the form.
$merge_data['status'] =
variable_get('user_register', 1) == 1;
}
$account = user_save('',
array_merge($form_values, $merge_data));
watchdog('user', t('New user: %name %email.',
array('%name' => $name, '%email' => '<'. $mail .'>')),
WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
$variables = array('!username' => $name,
'!site' => variable_get('site_name', 'Drupal'), '!password' => $pass,
'!uri' => $base_url, '!uri_brief' => substr($base_url,
strlen('http://')), '!mailto' => $mail, '!date' => format_date(time()),
'!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' =>
url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '!login_url' =>
user_pass_reset_url($account));
// The first user may login immediately, and
receives a customized welcome e-mail.
if ($account->uid == 1) {
drupal_mail('user-register-admin', $mail,
t('Drupal user account details for !s', array('!s' => $name)),
strtr(t("!username,\n\nYou may now login to !uri using the following
username and password:\n\n username:
!username\n password:
!password\n\n!edit_uri\n\n--drupal"), $variables), $from);
drupal_set_message(t('<p>Welcome to
Drupal. You are user #1, which gives you full and immediate access. All future
registrants will receive their passwords via e-mail, so please make sure your
website e-mail address is set properly under the general settings on the <a
href="@settings">site information settings
page</a>.</p><p> Your password is
<strong>%pass</strong>. You may change your password
below.</p>', array('%pass' => $pass, '@settings' =>
url('admin/settings/site-information'))));
user_authenticate($account->name,
trim($pass));
return 'user/1/edit';
}
else {
if ($admin && !$notify) {
drupal_set_message(t('Created a new user
account. No e-mail has been sent.'));
}
else if (!variable_get('user_email_verification',
TRUE) && $account->status && !$admin) {
// No e-mail verification is required,
create new user account, and login user immediately.
$subject =
_user_mail_text('welcome_subject', $variables);
$body = _user_mail_text('welcome_body',
$variables);
drupal_mail('user-register-welcome',
$mail, $subject, $body, $from);
user_authenticate($account->name,
trim($pass));
drupal_goto();
}
else if ($account->status || $notify) {
// Create new user account, no
administrator approval required.
$subject = $notify ?
_user_mail_text('admin_subject', $variables) :
_user_mail_text('welcome_subject', $variables);
$body = $notify ?
_user_mail_text('admin_body', $variables) : _user_mail_text('welcome_body',
$variables);
drupal_mail(($notify ?
'user-register-notify' : 'user-register-welcome'), $mail, $subject, $body,
$from);
if ($notify) {
drupal_set_message(t('Password and
further instructions have been e-mailed to the new user %user.', array('%user'
=> $name)));
}
else {
drupal_set_message(t('Your password and
further instructions have been sent to your e-mail address.'));
return '';
}
}
else {
// Create new user account, administrator
approval required.
$subject =
_user_mail_text('approval_subject', $variables);
$body = _user_mail_text('approval_body',
$variables);
drupal_mail('user-register-approval-user', $mail, $subject, $body,
$from);
drupal_mail('user-register-approval-admin',
$from, $subject, t("!username has applied for an
account.\n\n!edit_uri", $variables), $from);
drupal_set_message(t('Thank you for
applying for an account. Your account is currently pending approval by the site
administrator.<br />In the meantime, your password and further
instructions have been sent to your e-mail address.'));
}
}
}
function user_edit_form($uid,
$edit, $register = FALSE) {
$admin = user_access('administer users');
// Account information:
$form['account'] = array('#type' =>
'fieldset',
'#title' => t('Account information'),
);
if (user_access('change own username') ||
$admin || $register) {
$form['account']['name'] = array('#type'
=> 'textfield',
'#title' => t('Username'),
'#default_value' => $edit['name'],
'#maxlength' => USERNAME_MAX_LENGTH,
'#description' => t('Your preferred
username; punctuation is not allowed except for periods, hyphens, and
underscores.'),
'#required' => TRUE,
);
}
$form['account']['mail'] = array('#type'
=> 'textfield',
'#title' => t('E-mail address'),
'#default_value' => $edit['mail'],
'#maxlength' => EMAIL_MAX_LENGTH,
'#description' => t('A valid e-mail
address. All e-mails from the system will be sent to this address. The e-mail
address is not made public and will only be used if you wish to receive a new
password or wish to receive certain news or notifications by e-mail.'),
'#required' => TRUE,
);
if (!$register) {
$form['account']['pass'] = array('#type'
=> 'password_confirm',
'#description' => t('To change the
current user password, enter the new password in both fields.'),
'#size' => 25,
'#maxlength' => 12,
'#required' => FALSE,
);
}
elseif (!variable_get('user_email_verification',
TRUE) || $admin) {
$form['account']['pass'] = array(
'#type' => 'password_confirm',
'#description' => t('Provide a
password for the new account in both fields. This password must be 6-12
characters long, and contain at least one digit.'),
'#required' => TRUE,
'#size' => 25,
'#maxlength' => 12,
);
}
if ($admin) {
$form['account']['status'] = array('#type'
=> 'radios', '#title' => t('Status'), '#default_value' =>
isset($edit['status']) ? $edit['status'] : 1, '#options' =>
array(t('Blocked'), t('Active')));
}
if (user_access('administer access control'))
{
$roles = user_roles(1);
unset($roles[DRUPAL_AUTHENTICATED_RID]);
if ($roles) {
$form['account']['roles'] = array('#type'
=> 'checkboxes', '#title' => t('Roles'), '#default_value' =>
array_keys((array)$edit['roles']), '#options' => $roles, '#description'
=> t('The user receives the combined permissions of the %au role, and all
roles selected here.', array('%au' => t('authenticated user'))));
}
}
// Picture/avatar:
if (variable_get('user_pictures', 0)
&& !$register) {
$form['picture'] = array('#type' =>
'fieldset', '#title' => t('Picture'), '#weight' => 1);
$picture = theme('user_picture',
(object)$edit);
if ($picture) {
$form['picture']['current_picture'] =
array('#value' => $picture);
$form['picture']['picture_delete'] =
array('#type' => 'checkbox', '#title' => t('Delete picture'),
'#description' => t('Check this box to delete your current picture.'));
}
else {
$form['picture']['picture_delete'] =
array('#type' => 'hidden');
}
$form['picture']['picture_upload'] =
array('#type' => 'file', '#title' => t('Upload picture'), '#size' =>
48, '#description' => t('Your virtual face or picture. Maximum dimensions
are %dimensions and the maximum size is %size kB.', array('%dimensions' =>
variable_get('user_picture_dimensions', '85x85'), '%size' =>
variable_get('user_picture_file_size', '30'))) .' '.
variable_get('user_picture_guidelines', ''));
}
return $form;
}
function
_user_edit_validate($uid, &$edit) {
$user = user_load(array('uid' => $uid));
// Validate the username:
if (user_access('change own username') ||
user_access('administer users') || arg(1) == 'register') {
if ($error =
user_validate_name($edit['name'])) {
form_set_error('name', $error);
}
else if (db_num_rows(db_query("SELECT
uid FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid,
$edit['name'])) > 0) {
form_set_error('name', t('The name %name
is already taken.', array('%name' => $edit['name'])));
}
else if (drupal_is_denied('user',
$edit['name'])) {
form_set_error('name', t('The name %name
has been denied access.', array('%name' => $edit['name'])));
}
}
// Validate the e-mail address:
if ($error =
user_validate_mail($edit['mail'])) {
form_set_error('mail', $error);
}
else if (db_num_rows(db_query("SELECT
uid FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid,
$edit['mail'])) > 0) {
form_set_error('mail', t('The e-mail
address %email is already registered. <a href="@password">Have
you forgotten your password?</a>', array('%email' => $edit['mail'],
'@password' => url('user/password'))));
}
else if (drupal_is_denied('mail', $edit['mail']))
{
form_set_error('mail', t('The e-mail
address %email has been denied access.', array('%email' => $edit['mail'])));
}
// If required, validate the uploaded
picture.
if ($file =
file_check_upload('picture_upload')) {
user_validate_picture($file, $edit, $user);
}
}
function
_user_edit_submit($uid, &$edit) {
$user = user_load(array('uid' => $uid));
// Delete picture if requested, and if no
replacement picture was given.
if ($edit['picture_delete']) {
if ($user->picture &&
file_exists($user->picture)) {
file_delete($user->picture);
}
$edit['picture'] = '';
}
if (isset($edit['roles'])) {
$edit['roles'] =
array_filter($edit['roles']);
}
}
function user_edit($category
= 'account') {
global $user;
$account = user_load(array('uid' =>
arg(1)));
if ($account === FALSE) {
drupal_set_message(t('The account does not
exist or has already been deleted.'));
drupal_goto('admin/user/user');
}
$edit = $_POST['op'] ? $_POST :
(array)$account;
if (arg(2) == 'delete') {
if ($edit['confirm']) {
user_delete($edit, $account->uid);
drupal_goto('admin/user/user');
}
else {
return
drupal_get_form('user_confirm_delete', $account->name, $account->uid);
}
}
else if ($_POST['op'] == t('Delete')) {
if ($_REQUEST['destination']) {
$destination = drupal_get_destination();
unset($_REQUEST['destination']);
}
// Note: we redirect from user/uid/edit to
user/uid/delete to make the tabs disappear.
drupal_goto("user/$account->uid/delete",
$destination);
}
$form = _user_forms($edit, $account,
$category);
$form['_category'] = array('#type' =>
'value', '#value' => $category);
$form['_account'] = array('#type' =>
'value', '#value' => $account);
$form['submit'] = array('#type' =>
'submit', '#value' => t('Submit'), '#weight' => 30);
if (user_access('administer users')) {
$form['delete'] = array('#type' =>
'submit', '#value' => t('Delete'), '#weight' => 31);
}
$form['#attributes']['enctype'] =
'multipart/form-data';
drupal_set_title(check_plain($account->name));
return $form;
}
function
user_confirm_delete($name, $uid) {
return confirm_form(array(),
t('Are you sure you want to delete the
account %name?', array('%name' => $name)),
'user/'. $uid,
t('All submissions made by this user will
be attributed to the anonymous account. This action cannot be undone.'),
t('Delete'), t('Cancel'));
}
/**
* Delete a user.
*
* @param $edit An array of submitted form
values.
* @param $uid The user ID of the user to
delete.
*/
function user_delete($edit,
$uid) {
$account = user_load(array('uid' =>
$uid));
sess_destroy_uid($uid);
db_query('DELETE FROM {users} WHERE uid =
%d', $uid);
db_query('DELETE FROM {users_roles} WHERE uid
= %d', $uid);
db_query('DELETE FROM {authmap} WHERE uid =
%d', $uid);
$array = array('%name' =>
$account->name, '%email' => '<'. $account->mail .'>');
watchdog('user', t('Deleted user: %name
%email.', $array), WATCHDOG_NOTICE);
drupal_set_message(t('%name has been
deleted.', $array));
module_invoke_all('user', 'delete', $edit,
$account);
}
function
user_edit_validate($form_id, $form_values) {
user_module_invoke('validate', $form_values,
$form_values['_account'], $form_values['_category']);
//
Validate input to ensure that non-privileged users can't alter protected data.
if ((!user_access('administer users')
&& array_intersect(array_keys($form_values), array('uid', 'init',
'session'))) || (!user_access('administer access control') && isset($form_values['roles'])))
{
$message = t('Detected malicious attempt to
alter protected user fields.');
watchdog('security', $message,
WATCHDOG_WARNING);
// set this to a value type field
form_set_error('category', $message);
}
}
function
user_edit_submit($form_id, $form_values) {
$account = $form_values['_account'];
$category = $form_values['_category'];
unset($form_values['_account'],
$form_values['op'], $form_values['submit'], $form_values['delete'],
$form_values['form_token'], $form_values['form_id'],
$form_values['_category']);
user_module_invoke('submit', $form_values,
$account, $category);
user_save($account, $form_values, $category);
// Delete that user's menu cache:
cache_clear_all($account->uid .':',
'cache_menu', TRUE);
// Clear the page cache because pages can
contain usernames and/or profile information:
cache_clear_all();
drupal_set_message(t('The changes have been
saved.'));
return 'user/'. $account->uid;
}
function user_view($uid = 0)
{
global $user;
$account = user_load(array('uid' =>
$uid));
if ($account === FALSE ||
($account->access == 0 && !user_access('administer users'))) {
return drupal_not_found();
}
// Retrieve and merge all profile fields:
$fields = array();
foreach (module_list() as $module) {
if ($data = module_invoke($module, 'user',
'view', '', $account)) {
foreach ($data as $category => $items)
{
foreach ($items as $key => $item) {
$item['class'] =
"$module-". $item['class'];
$fields[$category][$key] = $item;
}
}
}
}
// Let modules change the returned fields -
useful for personal privacy
// controls. Since modules communicate
changes by reference, we cannot use
// module_invoke_all().
foreach (module_implements('profile_alter')
as $module) {
$function = $module .'_profile_alter';
$function($account, $fields);
}
drupal_set_title(check_plain($account->name));
return theme('user_profile', $account,
$fields);
}
/*** Administrative features
***********************************************/
function
_user_mail_text($messageid, $variables = array()) {
// Check if an admin setting overrides the
default string.
if ($admin_setting =
variable_get('user_mail_'. $messageid, FALSE)) {
return strtr($admin_setting, $variables);
}
// No override, return with default strings.
else {
switch ($messageid) {
case 'welcome_subject':
return t('Account details for !username
at !site', $variables);
case 'welcome_body':
return t("!username,\n\nThank you for
registering at !site. You may now log in to !login_uri using the following
username and password:\n\nusername: !username\npassword: !password\n\nYou may
also log in by clicking on this link or copying and pasting it in your
browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only
once.\n\nAfter logging in, you will be redirected to !edit_uri so you can
change your password.\n\n\n-- !site
team", $variables);
case 'admin_subject':
return t('An administrator created an
account for you at !site', $variables);
case 'admin_body':
return t("!username,\n\nA site
administrator at !site has created an account for you. You may now log in to
!login_uri using the following username and password:\n\nusername:
!username\npassword: !password\n\nYou may also log in by clicking on this link
or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time
login, so it can be used only once.\n\nAfter logging in, you will be redirected
to !edit_uri so you can change your password.\n\n\n-- !site team", $variables);
case 'approval_subject':
return t('Account details for !username
at !site (pending admin approval)', $variables);
case 'approval_body':
return t("!username,\n\nThank you
for registering at !site. Your application for an account is currently pending
approval. Once it has been granted, you may log in to !login_uri using the
following username and password:\n\nusername: !username\npassword: !password\n\nYou
may also log in by clicking on this link or copying and pasting it in your
browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only
once.\n\nAfter logging in, you may wish to change your password at
!edit_uri\n\n\n-- !site team",
$variables);
case 'pass_subject':
return t('Replacement login information
for !username at !site', $variables);
case 'pass_body':
return t("!username,\n\nA request
to reset the password for your account has been made at !site.\n\nYou may now
log in to !uri_brief clicking on this link or copying and pasting it in your
browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only
once. It expires after one day and nothing will happen if it's not
used.\n\nAfter logging in, you will be redirected to !edit_uri so you can
change your password.", $variables);
}
}
}
function
user_admin_check_user() {
$form['user'] = array('#type' =>
'fieldset', '#title' => t('Username'));
$form['user']['test'] = array('#type' =>
'textfield', '#title' => '', '#description' => t('Enter a username to
check if it will be denied or allowed.'), '#size' => 30, '#maxlength' =>
USERNAME_MAX_LENGTH);
$form['user']['type'] = array('#type' =>
'hidden', '#value' => 'user');
$form['user']['submit'] = array('#type' =>
'submit', '#value' => t('Check username'));
$form['#base'] = 'user_admin_access_check';
return $form;
}
function
user_admin_check_mail() {
$form['mail'] = array('#type' =>
'fieldset', '#title' => t('E-mail'));
$form['mail']['test'] = array('#type' =>
'textfield', '#title' => '', '#description' => t('Enter an e-mail address
to check if it will be denied or allowed.'), '#size' => 30, '#maxlength'
=> EMAIL_MAX_LENGTH);
$form['mail']['type'] = array('#type' =>
'hidden', '#value' => 'mail');
$form['mail']['submit'] = array('#type' =>
'submit', '#value' => t('Check e-mail'));
$form['#base'] = 'user_admin_access_check';
return $form;
}
function
user_admin_check_host() {
$form['host'] = array('#type' =>
'fieldset', '#title' => t('Hostname'));
$form['host']['test'] = array('#type' =>
'textfield', '#title' => '', '#description' => t('Enter a hostname or IP
address to check if it will be denied or allowed.'), '#size' => 30,
'#maxlength' => 64);
$form['host']['type'] = array('#type' =>
'hidden', '#value' => 'host');
$form['host']['submit'] = array('#type' =>
'submit', '#value' => t('Check hostname'));
$form['#base'] = 'user_admin_access_check';
return $form;
}
/**
* Menu callback: check an access rule
*/
function
user_admin_access_check() {
$output =
drupal_get_form('user_admin_check_user');
$output .=
drupal_get_form('user_admin_check_mail');
$output .=
drupal_get_form('user_admin_check_host');
return $output;
}
function
user_admin_access_check_validate($form_id, $form_values) {
if (empty($form_values['test'])) {
form_set_error($form_values['type'], t('No
value entered. Please enter a test string and try again.'));
}
}
function
user_admin_access_check_submit($form_id, $form_values) {
switch ($form_values['type']) {
case 'user':
if (drupal_is_denied('user',
$form_values['test'])) {
drupal_set_message(t('The username
%name is not allowed.', array('%name' => $form_values['test'])));
}
else {
drupal_set_message(t('The username
%name is allowed.', array('%name' => $form_values['test'])));
}
break;
case 'mail':
if (drupal_is_denied('mail',
$form_values['test'])) {
drupal_set_message(t('The e-mail
address %mail is not allowed.', array('%mail' => $form_values['test'])));
}
else {
drupal_set_message(t('The e-mail
address %mail is allowed.', array('%mail' => $form_values['test'])));
}
break;
case 'host':
if (drupal_is_denied('host',
$form_values['test'])) {
drupal_set_message(t('The hostname
%host is not allowed.', array('%host' => $form_values['test'])));
}
else {
drupal_set_message(t('The hostname
%host is allowed.', array('%host' => $form_values['test'])));
}
break;
default:
break;
}
}
/**
* Menu callback: add an access rule
*/
function
user_admin_access_add($mask = NULL, $type = NULL) {
if ($edit = $_POST) {
if (!$edit['mask']) {
form_set_error('mask', t('You must enter
a mask.'));
}
else {
$aid = db_next_id('{access}_aid');
db_query("INSERT INTO {access} (aid,
mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'],
$edit['type'], $edit['status']);
drupal_set_message(t('The access rule has
been added.'));
drupal_goto('admin/user/rules');
}
}
else {
$edit['mask'] = $mask;
$edit['type'] = $type;
}
return
drupal_get_form('user_admin_access_add_form', $edit, t('Add rule'));
}
/**
* Menu callback: delete an access rule
*/
function
user_admin_access_delete_confirm($aid = 0) {
$access_types = array('user' =>
t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
$edit = db_fetch_object(db_query('SELECT aid,
type, status, mask FROM {access} WHERE aid = %d', $aid));
$form = array();
$form['aid'] = array('#type' => 'hidden',
'#value' => $aid);
$output = confirm_form($form,
t('Are you sure you want to
delete the @type rule for %rule?', array('@type' =>
$access_types[$edit->type], '%rule' => $edit->mask)),
'admin/user/rules',
t('This action cannot be
undone.'),
t('Delete'),
t('Cancel'));
return $output;
}
function
user_admin_access_delete_confirm_submit($form_id, $form_values) {
db_query('DELETE FROM {access} WHERE aid =
%d', $form_values['aid']);
drupal_set_message(t('The access rule has
been deleted.'));
return 'admin/user/rules';
}
/**
* Menu callback: edit an access rule
*/
function
user_admin_access_edit($aid = 0) {
if ($edit = $_POST) {
if (!$edit['mask']) {
form_set_error('mask', t('You must enter
a mask.'));
}
else {
db_query("UPDATE {access} SET mask =
'%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'],
$edit['type'], $edit['status'], $aid);
drupal_set_message(t('The access rule has
been saved.'));
drupal_goto('admin/user/rules');
}
}
else {
$edit = db_fetch_array(db_query('SELECT
aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
}
return
drupal_get_form('user_admin_access_edit_form', $edit, t('Save rule'));
}
function
user_admin_access_form($edit, $submit) {
$form['status'] = array(
'#type' => 'radios',
'#title' => t('Access type'),
'#default_value' => $edit['status'],
'#options' => array('1' =>
t('Allow'), '0' => t('Deny')),
);
$type_options = array('user' =>
t('Username'), 'mail' => t('E-mail'), 'host' => t('Host'));
$form['type'] = array(
'#type' => 'radios',
'#title' => t('Rule type'),
'#default_value' =>
(isset($type_options[$edit['type']]) ? $edit['type'] : 'user'),
'#options' => $type_options,
);
$form['mask'] = array(
'#type' => 'textfield',
'#title' => t('Mask'),
'#size' => 30,
'#maxlength' => 64,
'#default_value' => $edit['mask'],
'#description' => '%: '. t('Matches any
number of characters, even zero characters') .'.<br />_: '. t('Matches
exactly one character.'),
'#required' => TRUE,
);
$form['submit'] = array('#type' =>
'submit', '#value' => $submit);
return $form;
}
/**
* Menu callback: list all access rules
*/
function user_admin_access()
{
$header = array(array('data' => t('Access
type'), 'field' => 'status'), array('data' => t('Rule type'), 'field'
=> 'type'), array('data' => t('Mask'), 'field' => 'mask'),
array('data' => t('Operations'), 'colspan' => 2));
$result = db_query("SELECT aid, type,
status, mask FROM {access}". tablesort_sql($header));
$access_types = array('user' =>
t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
$rows = array();
while ($rule = db_fetch_object($result)) {
$rows[] = array($rule->status ?
t('allow') : t('deny'), $access_types[$rule->type], $rule->mask,
l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), l(t('delete'),
'admin/user/rules/delete/'. $rule->aid));
}
if (count($rows) == 0) {
$rows[] = array(array('data' =>
'<em>'. t('There are currently no access rules.') .'</em>',
'colspan' => 5));
}
$output .= theme('table', $header, $rows);
return $output;
}
/**
* Retrieve an array of roles matching
specified conditions.
*
* @param $membersonly
* Set
this to TRUE to exclude the 'anonymous' role.
* @param $permission
* A
string containing a permission. If set, only roles containing that permission
are returned.
*
* @return
* An
associative array with the role id as the key and the role name as value.
*/
function
user_roles($membersonly = 0, $permission = 0) {
$roles = array();
if ($permission) {
$result = db_query("SELECT r.* FROM
{role} r INNER JOIN {permission} p ON r.rid = p.rid WHERE p.perm LIKE '%%%s%%'
ORDER BY r.name", $permission);
}
else {
$result = db_query('SELECT * FROM {role}
ORDER BY name');
}
while ($role = db_fetch_object($result)) {
if (!$membersonly || ($membersonly
&& $role->rid != DRUPAL_ANONYMOUS_RID)) {
$roles[$role->rid] = $role->name;
}
}
return $roles;
}
/**
* Menu callback: administer permissions.
*/
function user_admin_perm($rid
= NULL) {
if (is_numeric($rid)) {
$result = db_query('SELECT r.rid, p.perm
FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d',
$rid);
}
else {
$result = db_query('SELECT r.rid, p.perm
FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
}
// Compile role array:
// Add a comma at the end so when searching
for a permission, we can
// always search for "$perm," to
make sure we do not confuse
// permissions that are substrings of each
other.
while ($role = db_fetch_object($result)) {
$role_permissions[$role->rid] =
$role->perm .',';
}
if (is_numeric($rid)) {
$result = db_query('SELECT rid, name FROM
{role} r WHERE r.rid = %d ORDER BY name', $rid);
}
else {
$result = db_query('SELECT rid, name FROM
{role} ORDER BY name');
}
$role_names = array();
while ($role = db_fetch_object($result)) {
$role_names[$role->rid] =
$role->name;
}
// Render role/permission overview:
$options = array();
foreach (module_list(FALSE, FALSE, TRUE) as
$module) {
if ($permissions = module_invoke($module,
'perm')) {
$form['permission'][] = array(
'#value' => $module,
);
asort($permissions);
foreach ($permissions as $perm) {
$options[$perm] = '';
$form['permission'][$perm] =
array('#value' => t($perm));
foreach ($role_names as $rid =>
$name) {
// Builds arrays for checked boxes
for each role
if (strpos($role_permissions[$rid],
$perm .',') !== FALSE) {
$status[$rid][] = $perm;
}
}
}
}
}
// Have to build checkboxes here after
checkbox arrays are built
foreach ($role_names as $rid => $name) {
$form['checkboxes'][$rid] = array('#type'
=> 'checkboxes', '#options' => $options, '#default_value' =>
$status[$rid]);
$form['role_names'][$rid] = array('#value'
=> $name, '#tree' => TRUE);
}
$form['submit'] = array('#type' =>
'submit', '#value' => t('Save permissions'));
return $form;
}
function
theme_user_admin_perm($form) {
foreach (element_children($form['permission'])
as $key) {
// Don't take form control structures
if (is_array($form['permission'][$key])) {
$row = array();
// Module name
if (is_numeric($key)) {
$row[] = array('data' => t('@module
module', array('@module' => drupal_render($form['permission'][$key]))),
'class' => 'module', 'id' => 'module-'.
$form['permission'][$key]['#value'], 'colspan' => count($form['role_names'])
+ 1);
}
else {
$row[] = array('data' =>
drupal_render($form['permission'][$key]), 'class' => 'permission');
foreach
(element_children($form['checkboxes']) as $rid) {
if
(is_array($form['checkboxes'][$rid])) {
$row[] = array('data' =>
drupal_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title'
=> t($key));
}
}
}
$rows[] = $row;
}
}
$header[] = (t('Permission'));
foreach
(element_children($form['role_names']) as $rid) {
if (is_array($form['role_names'][$rid])) {
$header[] = drupal_render($form['role_names'][$rid]);
}
}
$output = theme('table', $header, $rows,
array('id' => 'permissions'));
$output .= drupal_render($form);
return $output;
}
function
user_admin_perm_submit($form_id, $form_values) {
// Save permissions:
$result = db_query('SELECT * FROM {role}');
while ($role = db_fetch_object($result)) {
if (isset($form_values[$role->rid])) {
// Delete, so if we clear every checkbox
we reset that role;
// otherwise permissions are active and
denied everywhere.
db_query('DELETE FROM {permission} WHERE rid
= %d', $role->rid);
$form_values[$role->rid] =
array_filter($form_values[$role->rid]);
if (count($form_values[$role->rid])) {
db_query("INSERT INTO {permission}
(rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ',
array_keys($form_values[$role->rid])));
}
}
}
drupal_set_message(t('The changes have been
saved.'));
// Clear the cached pages and menus:
menu_rebuild();
}
/**
* Menu callback: administer roles.
*/
function user_admin_role() {
$id = arg(4);
if ($id) {
if (DRUPAL_ANONYMOUS_RID == $id ||
DRUPAL_AUTHENTICATED_RID == $id) {
drupal_goto('admin/user/roles');
}
// Display the edit role form.
$role = db_fetch_object(db_query('SELECT * FROM
{role} WHERE rid = %d', $id));
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Role name'),
'#default_value' => $role->name,
'#size' => 30,
'#required' => TRUE,
'#maxlength' => 64,
'#description' => t('The name for this
role. Example: "moderator", "editorial board", "site
architect".'),
);
$form['rid'] = array(
'#type' => 'value',
'#value' => $id,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save role'),
);
$form['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete role'),
);
}
else {
$form['name'] = array(
'#type' => 'textfield',
'#size' => 32,
'#maxlength' => 64,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add role'),
);
$form['#base'] = 'user_admin_role';
}
return $form;
}
function
user_admin_role_validate($form_id, $form_values) {
if ($form_values['name']) {
if ($form_values['op'] == t('Save role')) {
if (db_result(db_query("SELECT
COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d",
$form_values['name'], $form_values['rid']))) {
form_set_error('name', t('The role name
%name already exists. Please choose another role name.', array('%name' =>
$form_values['name'])));
}
}
else if ($form_values['op'] == t('Add
role')) {
if (db_result(db_query("SELECT
COUNT(*) FROM {role} WHERE name = '%s'", $form_values['name']))) {
form_set_error('name', t('The role name
%name already exists. Please choose another role name.', array('%name' =>
$form_values['name'])));
}
}
}
else {
form_set_error('name', t('You must specify
a valid role name.'));
}
}
function user_admin_role_submit($form_id,
$form_values) {
if ($form_values['op'] == t('Save role')) {
db_query("UPDATE {role} SET name =
'%s' WHERE rid = %d", $form_values['name'], $form_values['rid']);
drupal_set_message(t('The role has been
renamed.'));
}
else if ($form_values['op'] == t('Delete
role')) {
db_query('DELETE FROM {role} WHERE rid =
%d', $form_values['rid']);
db_query('DELETE FROM {permission} WHERE
rid = %d', $form_values['rid']);
// Update the users who have this role set:
db_query('DELETE FROM {users_roles} WHERE
rid = %d', $form_values['rid']);
drupal_set_message(t('The role has been
deleted.'));
}
else if ($form_values['op'] == t('Add role'))
{
db_query("INSERT INTO {role} (name)
VALUES ('%s')", $form_values['name']);
drupal_set_message(t('The role has been
added.'));
}
return 'admin/user/roles';
}
function
theme_user_admin_new_role($form) {
$header = array(t('Name'), array('data' =>
t('Operations'), 'colspan' => 2));
foreach (user_roles() as $rid => $name) {
$edit_permissions = l(t('edit
permissions'), 'admin/user/access/'. $rid);
if (!in_array($rid,
array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
$rows[] = array($name, l(t('edit role'),
'admin/user/roles/edit/'. $rid), $edit_permissions);
}
else {
$rows[] = array($name, t('locked'),
$edit_permissions);
}
}
$rows[] = array(drupal_render($form['name']),
array('data' => drupal_render($form['submit']), colspan => 2));
$output = drupal_render($form);
$output .= theme('table', $header, $rows);
return $output;
}
function user_admin_account()
{
$filter = user_build_filter_query();
$header = array(
array(),
array('data' => t('Username'), 'field'
=> 'u.name'),
array('data' => t('Status'), 'field'
=> 'u.status'),
t('Roles'),
array('data' => t('Member for'), 'field'
=> 'u.created', 'sort' => 'desc'),
array('data' => t('Last access'),
'field' => 'u.access'),
t('Operations')
);
$sql = 'SELECT DISTINCT u.uid, u.name,
u.status, u.created, u.access FROM {users} u LEFT JOIN {users_roles} ur ON
u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50, 0, NULL,
$filter['args']);
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Update options'),
'#prefix' => '<div
class="container-inline">',
'#suffix' => '</div>',
);
$options = array();
foreach (module_invoke_all('user_operations')
as $operation => $array) {
$options[$operation] = $array['label'];
}
$form['options']['operation'] = array(
'#type' => 'select',
'#options' => $options,
'#default_value' => 'unblock',
);
$form['options']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
);
$destination = drupal_get_destination();
$status = array(t('blocked'), t('active'));
$roles = user_roles(1);
while ($account = db_fetch_object($result)) {
$accounts[$account->uid] = '';
$form['name'][$account->uid] = array('#value'
=> theme('username', $account));
$form['status'][$account->uid] = array('#value' =>
$status[$account->status]);
$users_roles = array();
$roles_result = db_query('SELECT rid FROM
{users_roles} WHERE uid = %d', $account->uid);
while ($user_role =
db_fetch_object($roles_result)) {
$users_roles[] =
$roles[$user_role->rid];
}
asort($users_roles);
$form['roles'][$account->uid][0] =
array('#value' => theme('item_list', $users_roles));
$form['member_for'][$account->uid] =
array('#value' => format_interval(time() - $account->created));
$form['last_access'][$account->uid]
= array('#value' =>
$account->access ? t('@time ago', array('@time' => format_interval(time()
- $account->access))) : t('never'));
$form['operations'][$account->uid] =
array('#value' => l(t('edit'), "user/$account->uid/edit",
array(), $destination));
}
$form['accounts'] = array(
'#type' => 'checkboxes',
'#options' => $accounts
);
$form['pager'] = array('#value' =>
theme('pager', NULL, 50, 0));
return $form;
}
/**
* Theme user administration overview.
*/
function
theme_user_admin_account($form) {
// Overview table:
$header = array(
theme('table_select_header_cell'),
array('data' => t('Username'), 'field'
=> 'u.name'),
array('data' => t('Status'), 'field'
=> 'u.status'),
t('Roles'),
array('data' => t('Member for'), 'field'
=> 'u.created', 'sort' => 'desc'),
array('data' => t('Last access'),
'field' => 'u.access'),
t('Operations')
);
$output = drupal_render($form['options']);
if (isset($form['name']) &&
is_array($form['name'])) {
foreach (element_children($form['name']) as
$key) {
$rows[] = array(
drupal_render($form['accounts'][$key]),
drupal_render($form['name'][$key]),
drupal_render($form['status'][$key]),
drupal_render($form['roles'][$key]),
drupal_render($form['member_for'][$key]),
drupal_render($form['last_access'][$key]),
drupal_render($form['operations'][$key]),
);
}
}
else {
$rows[] = array(array('data' => t('No
users available.'), 'colspan' => '7'));
}
$output .= theme('table', $header, $rows);
if ($form['pager']['#value']) {
$output .= drupal_render($form['pager']);
}
$output .= drupal_render($form);
return $output;
}
/**
* Submit the user administration update form.
*/
function
user_admin_account_submit($form_id, $form_values) {
$operations =
module_invoke_all('user_operations');
$operation =
$operations[$form_values['operation']];
// Filter out unchecked accounts.
$accounts =
array_filter($form_values['accounts']);
if ($function = $operation['callback']) {
// Add in callback arguments if present.
if (isset($operation['callback
arguments'])) {
$args = array_merge(array($accounts),
$operation['callback arguments']);
}
else {
$args = array($accounts);
}
call_user_func_array($function, $args);
cache_clear_all('*', 'cache_menu', TRUE);
drupal_set_message(t('The update has been
performed.'));
}
}
function
user_admin_account_validate($form_id, $form_values) {
$form_values['accounts'] =
array_filter($form_values['accounts']);
if (count($form_values['accounts']) == 0) {
form_set_error('', t('No users
selected.'));
}
}
/**
* Implementation of hook_user_operations().
*/
function
user_user_operations() {
global $form_values;
$operations = array(
'unblock' => array(
'label' => t('Unblock the selected
users'),
'callback' =>
'user_user_operations_unblock',
),
'block' => array(
'label' => t('Block the selected
users'),
'callback' =>
'user_user_operations_block',
),
'delete' => array(
'label' => t('Delete the selected
users'),
),
);
if (user_access('administer access control'))
{
$roles = user_roles(1);
unset($roles[DRUPAL_AUTHENTICATED_RID]);
// Can't edit authenticated role.
$add_roles = array();
foreach ($roles as $key => $value) {
$add_roles['add_role-'. $key] = $value;
}
$remove_roles = array();
foreach ($roles as $key => $value) {
$remove_roles['remove_role-'. $key] =
$value;
}
if (count($roles)) {
$role_operations = array(
t('Add a role to the selected users')
=> array(
'label' => $add_roles,
),
t('Remove a role from the selected
users') => array(
'label' => $remove_roles,
),
);
$operations += $role_operations;
}
}
// If the form has been posted, we need to
insert the proper data for role editing if necessary.
if ($form_values) {
$operation_rid = explode('-',
$form_values['operation']);
$operation = $operation_rid[0];
$rid = $operation_rid[1];
if ($operation == 'add_role' || $operation
== 'remove_role') {
if (user_access('administer access
control')) {
$operations[$form_values['operation']]
= array(
'callback' =>
'user_multiple_role_edit',
'callback arguments' =>
array($operation, $rid),
);
}
else {
watchdog('security', t('Detected
malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
return;
}
}
}
return $operations;
}
/**
* Callback function for admin mass unblocking
users.
*/
function
user_user_operations_unblock($accounts) {
foreach ($accounts as $uid) {
$account = user_load(array('uid' =>
(int)$uid));
// Skip unblocking user if they are already
unblocked.
if ($account !== FALSE &&
$account->status == 0) {
user_save($account, array('status' => 1));
}
}
}
/**
* Callback function for admin mass blocking
users.
*/
function
user_user_operations_block($accounts) {
foreach ($accounts as $uid) {
$account = user_load(array('uid' =>
(int)$uid));
// Skip blocking user if they are already
blocked.
if ($account !== FALSE &&
$account->status == 1) {
user_save($account, array('status' =>
0));
}
}
}
/**
* Callback function for admin mass
adding/deleting a user role.
*/
function
user_multiple_role_edit($accounts, $operation, $rid) {
// The role name is not necessary as
user_save() will reload the user
// object, but some modules' hook_user() may
look at this first.
$role_name = db_result(db_query('SELECT name
FROM {role} WHERE rid = %d', $rid));
switch ($operation) {
case 'add_role':
foreach ($accounts as $uid) {
$account = user_load(array('uid' =>
(int)$uid));
// Skip adding the role to the user if
they already have it.
if ($account !== FALSE &&
!isset($account->roles[$rid])) {
$roles = $account->roles + array($rid
=> $role_name);
user_save($account, array('roles'
=> $roles));
}
}
break;
case 'remove_role':
foreach ($accounts as $uid) {
$account = user_load(array('uid' =>
(int)$uid));
// Skip removing the role from the user
if they already don't have it.
if ($account !== FALSE &&
isset($account->roles[$rid])) {
$roles =
array_diff($account->roles, array($rid => $role_name));
user_save($account, array('roles'
=> $roles));
}
}
break;
}
}
function
user_multiple_delete_confirm() {
$edit = $_POST;
$form['accounts'] = array('#prefix' =>
'<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
// array_filter returns only elements with
TRUE values
foreach (array_filter($edit['accounts']) as
$uid => $value) {
$user = db_result(db_query('SELECT name
FROM {users} WHERE uid = %d', $uid));
$form['accounts'][$uid] = array('#type'
=> 'hidden', '#value' => $uid, '#prefix' => '<li>', '#suffix'
=> check_plain($user) ."</li>\n");
}
$form['operation'] = array('#type' =>
'hidden', '#value' => 'delete');
return confirm_form($form,
t('Are you sure you want
to delete these users?'),
'admin/user/user',
t('This action cannot be undone.'),
t('Delete all'),
t('Cancel'));
}
function
user_multiple_delete_confirm_submit($form_id, $form_values) {
if ($form_values['confirm']) {
foreach ($form_values['accounts'] as $uid =>
$value) {
user_delete($form_values, $uid);
}
drupal_set_message(t('The users have been
deleted.'));
}
return 'admin/user/user';
}
function
user_admin_settings() {
// User registration settings.
$form['registration'] = array('#type' =>
'fieldset', '#title' => t('User registration settings'));
$form['registration']['user_register'] =
array('#type' => 'radios', '#title' => t('Public registrations'),
'#default_value' => variable_get('user_register', 1), '#options' =>
array(t('Only site administrators can create new user accounts.'), t('Visitors
can create accounts and no administrator approval is required.'), t('Visitors
can create accounts but administrator approval is required.')));
$form['registration']['user_email_verification'] = array('#type' =>
'checkbox', '#title' => t('Require e-mail verification when a visitor
creates an account'), '#default_value' =>
variable_get('user_email_verification', TRUE), '#description' => t('If this
box is checked, new users will be required to validate their e-mail address
prior to logging into to the site, and will be assigned a system-generated
password. With it unchecked, users will be logged in immediately upon
registering, and may select their own passwords during registration.'));
$form['registration']['user_registration_help']
= array('#type' => 'textarea', '#title' => t('User registration
guidelines'), '#default_value' => variable_get('user_registration_help',
''), '#description' => t("This text is displayed at the top of the user
registration form. It's useful for helping or instructing your users."));
// User e-mail settings.
$form['email'] = array('#type' =>
'fieldset', '#title' => t('User e-mail settings'));
$form['email']['user_mail_welcome_subject'] =
array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail'),
'#default_value' => _user_mail_text('welcome_subject'), '#maxlength' =>
180, '#description' => t('Customize the subject of your welcome e-mail,
which is sent to new members upon registering.') .' '. t('Available variables
are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date,
!login_uri, !edit_uri, !login_url.');
$form['email']['user_mail_welcome_body'] =
array('#type' => 'textarea', '#title' => t('Body of welcome e-mail'),
'#default_value' => _user_mail_text('welcome_body'), '#rows' => 15,
'#description' => t('Customize the body of the welcome e-mail, which is sent
to new members upon registering.') .' '. t('Available variables are:') .'
!username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri,
!login_url.');
$form['email']['user_mail_admin_subject'] =
array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail
(user created by administrator)'), '#default_value' =>
_user_mail_text('admin_subject'), '#maxlength' => 180, '#description' =>
t('Customize the subject of your welcome e-mail, which is sent to new member
accounts created by an administrator.') .' '. t('Available variables are:') .'
!username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri,
!edit_uri, !login_url.');
$form['email']['user_mail_admin_body'] =
array('#type' => 'textarea', '#title' => t('Body of welcome e-mail (user
created by administrator)'), '#default_value' =>
_user_mail_text('admin_body'), '#rows' => 15, '#description' =>
t('Customize the body of the welcome e-mail, which is sent to new member
accounts created by an administrator.') .' '. t('Available variables are:') .'
!username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri,
!login_url.');
$form['email']['user_mail_approval_subject']
= array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail
(awaiting admin approval)'), '#default_value' =>
_user_mail_text('approval_subject'), '#maxlength' => 180, '#description'
=> t('Customize the subject of your awaiting approval welcome e-mail, which
is sent to new members upon registering.') .' '. t('Available variables are:')
.' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri,
!edit_uri, !login_url.');
$form['email']['user_mail_approval_body'] =
array('#type' => 'textarea', '#title' => t('Body of welcome e-mail
(awaiting admin approval)'), '#default_value' =>
_user_mail_text('approval_body'), '#rows' => 15, '#description' =>
t('Customize the body of the awaiting approval welcome e-mail, which is sent to
new members upon registering.') .' '. t('Available variables are:') .'
!username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri,
!login_url.');
$form['email']['user_mail_pass_subject'] =
array('#type' => 'textfield', '#title' => t('Subject of password recovery
e-mail'), '#default_value' => _user_mail_text('pass_subject'), '#maxlength'
=> 180, '#description' => t('Customize the subject of your forgotten
password e-mail.') .' '. t('Available variables are:') .' !username, !site,
!login_url, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri.');
$form['email']['user_mail_pass_body'] =
array('#type' => 'textarea', '#title' => t('Body of password recovery
e-mail'), '#default_value' => _user_mail_text('pass_body'), '#rows' =>
15, '#description' => t('Customize the body of the forgotten password
e-mail.') .' '. t('Available variables are:') .' !username, !site, !login_url,
!uri, !uri_brief, !mailto, !login_uri, !edit_uri.');
// If picture support is enabled, check
whether the picture directory exists:
if (variable_get('user_pictures', 0)) {
$picture_path =
file_create_path(variable_get('user_picture_path', 'pictures'));
file_check_directory($picture_path, 1,
'user_picture_path');
}
$form['pictures'] = array('#type' =>
'fieldset', '#title' => t('Pictures'));
$form['pictures']['user_pictures'] =
array('#type' => 'radios', '#title' => t('Picture support'),
'#default_value' => variable_get('user_pictures', 0), '#options' =>
array(t('Disabled'), t('Enabled')), '#description' => t('Enable picture
support.'));
$form['pictures']['user_picture_path'] =
array('#type' => 'textfield', '#title' => t('Picture image path'),
'#default_value' => variable_get('user_picture_path', 'pictures'), '#size'
=> 30, '#maxlength' => 255, '#description' => t('Subdirectory in the
directory %dir where pictures will be stored.', array('%dir' =>
file_directory_path() .'/')));
$form['pictures']['user_picture_default'] =
array('#type' => 'textfield', '#title' => t('Default picture'),
'#default_value' => variable_get('user_picture_default', ''), '#size' =>
30, '#maxlength' => 255, '#description' => t('URL of picture to display
for users with no custom picture selected. Leave blank for none.'));
$form['pictures']['user_picture_dimensions']
= array('#type' => 'textfield', '#title' => t('Picture maximum
dimensions'), '#default_value' => variable_get('user_picture_dimensions',
'85x85'), '#size' => 15, '#maxlength' => 10, '#description' =>
t('Maximum dimensions for pictures, in pixels.'));
$form['pictures']['user_picture_file_size'] =
array('#type' => 'textfield', '#title' => t('Picture maximum file size'),
'#default_value' => variable_get('user_picture_file_size', '30'), '#size'
=> 15, '#maxlength' => 10, '#description' => t('Maximum file size for
pictures, in kB.'));
$form['pictures']['user_picture_guidelines']
= array('#type' => 'textarea', '#title' => t('Picture guidelines'),
'#default_value' => variable_get('user_picture_guidelines', ''),
'#description' => t("This text is displayed at the picture upload form
in addition to the default guidelines. It's useful for helping or instructing
your users."));
return system_settings_form($form);
}
function
user_admin($callback_arg = '') {
$op = isset($_POST['op']) ? $_POST['op'] :
$callback_arg;
switch ($op) {
case 'search':
case t('Search'):
$output = drupal_get_form('search_form',
url('admin/user/search'), $_POST['keys'], 'user') . search_data($_POST['keys'],
'user');
break;
case t('Create new account'):
case 'create':
$output =
drupal_get_form('user_register');
break;
default:
if ($_POST['accounts'] &&
$_POST['operation'] == 'delete') {
$output =
drupal_get_form('user_multiple_delete_confirm');
}
else {
$output =
drupal_get_form('user_filter_form');
$output .=
drupal_get_form('user_admin_account');
}
}
return $output;
}
/**
* Implementation of hook_help().
*/
function user_help($section)
{
global $user;
switch ($section) {
case 'admin/help#user':
$output = '<p>'. t('The user module
allows users to register, login, and log out. Users benefit from being able to
sign on because it associates content they create with their account and allows
various permissions to be set for their roles. The user module supports user
roles which can setup fine grained permissions allowing each role to do only
what the administrator wants them to. Each user is assigned to one or more
roles. By default there are two roles <em>anonymous</em> - a user
who has not logged in, and <em>authenticated</em> a user who has
signed up and who has been authorized.') .'</p>';
$output .= '<p>'. t('Users can use
their own name or handle and can fine tune some personal configuration settings
through their individual my account page. Registered users need to authenticate
by supplying either a local username and password, or a remote username and
password such as DelphiForums ID, or one from a Drupal powered website. A
visitor accessing your website is assigned an unique ID, the so-called session
ID, which is stored in a cookie. For security\'s sake, the cookie does not
contain personal information but acts as a key to retrieve the information
stored on your server.') .'</p>';
$output .= '<p>'. t('For more
information please read the configuration and customization handbook <a
href="@user">User page</a>.', array('@user' =>
'http://drupal.org/handbook/modules/user/')) .'</p>';
return $output;
case 'admin/user/user':
return '<p>'. t('Drupal allows
users to register, login, log out, maintain user profiles, etc. Users of the
site may not use their own names to post content until they have signed up for
a user account.') .'</p>';
case 'admin/user/user/create':
case 'admin/user/user/account/create':
return '<p>'. t('This web page
allows the administrators to register a new users by hand. Note that you cannot
have a user where either the e-mail address or the username match another user
in the system.') .'</p>';
case 'admin/user/rules':
return '<p>'. t('Set up username
and e-mail address access rules for new <em>and</em> existing
accounts (currently logged in accounts will not be logged out). If a username
or e-mail address for an account matches any deny rule, but not an allow rule,
then the account will not be allowed to be created or to log in. A host rule is
effective for every page view, not just registrations.') .'</p>';
case 'admin/user/access':
return '<p>'. t('Permissions let
you control what users can do on your site. Each user role (defined on the
<a href="@role">user roles page</a>) has its own set of
permissions. For example, you could give users classified as
"Administrators" permission to "administer nodes" but deny
this power to ordinary, "authenticated" users. You can use
permissions to reveal new features to privileged users (those with
subscriptions, for example). Permissions also allow trusted users to share the
administrative burden of running a busy site.', array('@role' => url('admin/user/roles')))
.'</p>';
case 'admin/user/roles':
return t('<p>Roles allow you to
fine tune the security and administration of Drupal. A role defines a group of
users that have certain privileges as defined in <a
href="@permissions">user permissions</a>. Examples of roles
include: anonymous user, authenticated user, moderator, administrator and so
on. In this area you will define the <em>role names</em> of the
various roles. To delete a role choose "edit".</p><p>By
default, Drupal comes with two user roles:</p>
<ul>
<li>Anonymous user: this role is
used for users that don\'t have a user account or that are not
authenticated.</li>
<li>Authenticated user: this role
is automatically granted to all logged in users.</li>
</ul>', array('@permissions' =>
url('admin/user/access')));
case 'admin/user/search':
return '<p>'. t('Enter a simple
pattern ("*" may be used as a wildcard match) to search for a
username. For example, one may search for "br" and Drupal might
return "brian", "brad", and "brenda".')
.'</p>';
case 'user/help#user':
$site = variable_get('site_name',
'Drupal');
$affiliates = user_auth_help_links();
if (count($affiliates)) {
$affiliate_info = implode(', ',
user_auth_help_links());
}
else {
$affiliate_info = t('one of our
affiliates');
}
$output = t('
<h3>Distributed authentication<a
id="da"></a></h3>
<p>One of the more tedious moments
in visiting a new website is filling out the registration form. Here at @site,
you do not have to fill out a registration form if you are already a member of
!affiliate-info. This capability is called <em>distributed
authentication</em>, and <a href="@drupal">Drupal</a>,
the software which powers @site, fully supports it.</p>
<p>Distributed authentication
enables a new user to input a username and password into the login box, and
immediately be recognized, even if that user never registered at @site. This
works because Drupal knows how to communicate with external registration
databases. For example, lets say that new user \'Joe\' is already a registered
member of <a href="@delphi-forums">Delphi Forums</a>.
Drupal informs Joe on registration and login screens that he may login with his
Delphi ID instead of registering with @site. Joe likes that idea, and logs in
with a username of joe@remote.delphiforums.com and his usual Delphi password.
Drupal then contacts the <em>remote.delphiforums.com</em> server
behind the scenes (usually using <a href="@xml">XML-RPC</a>,
<a href="@http-post">HTTP POST</a>, or <a
href="@soap">SOAP</a>) and asks: "Is the password for
user Joe correct?". If Delphi replies yes, then we create a new @site
account for Joe and log him into it. Joe may keep on logging into @site in the
same manner, and he will always be logged into the same account.</p>',
array('!affiliate-info' => $affiliate_info, '@site' => $site, '@drupal'
=> 'http://drupal.org', '@delphi-forums' =>
'http://www.delphiforums.com', '@xml' => 'http://www.xmlrpc.com', '@http-post'
=> 'http://www.w3.org/Protocols/', '@soap' =>
'http://www.soapware.org'));
foreach (module_list() as $module) {
if (module_hook($module, 'auth')) {
$output .= "<h4><a
id=\"$module\"></a>". module_invoke($module, 'info',
'name') .'</h4>';
$output .= module_invoke($module,
'help', "user/help#$module");
}
}
return $output;
}
}
/**
* Menu callback; Prints user-specific help
information.
*/
function user_help_page() {
return user_help('user/help#user');
}
/**
* Retrieve a list of all user
setting/information categories and sort them by weight.
*/
function
_user_categories($account) {
$categories = array();
foreach (module_list() as $module) {
if ($data = module_invoke($module, 'user',
'categories', NULL, $account, '')) {
$categories = array_merge($data,
$categories);
}
}
usort($categories, '_user_sort');
return $categories;
}
function _user_sort($a, $b) {
return $a['weight'] < $b['weight'] ? -1 :
($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
}
/**
* Retrieve a list of all form elements for the
specified category.
*/
function
_user_forms(&$edit, $account, $category, $hook = 'form') {
$groups = array();
foreach (module_list() as $module) {
if ($data = module_invoke($module, 'user',
$hook, $edit, $account, $category)) {
$groups = array_merge_recursive($data,
$groups);
}
}
uasort($groups, '_user_sort');
return empty($groups) ? FALSE : $groups;
}
/**
* Retrieve a pipe delimited string of
autocomplete suggestions for existing users
*/
function
user_autocomplete($string = '') {
$matches = array();
if ($string) {
$result = db_query_range("SELECT name
FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string, 0, 10);
while ($user = db_fetch_object($result)) {
$matches[$user->name] =
check_plain($user->name);
}
}
print drupal_to_js($matches);
exit();
}
/**
* List user administration filters that can be
applied.
*/
function user_filters() {
// Regular filters
$filters = array();
$roles = user_roles(1);
unset($roles[DRUPAL_AUTHENTICATED_RID]); //
Don't list authorized role.
if (count($roles)) {
$filters['role'] = array('title' =>
t('role'),
'where' => "ur.rid =
%d",
'options' =>
$roles,
);
}
$options = array();
$t_module = t('module');
foreach (module_list() as $module) {
if ($permissions = module_invoke($module,
'perm')) {
asort($permissions);
foreach ($permissions as $permission) {
$options["$module
$t_module"][$permission] = t($permission);
}
}
}
ksort($options);
$filters['permission'] = array('title' =>
t('permission'),
'join' => 'LEFT JOIN
{permission} p ON ur.rid = p.rid',
'where' =>
" ((p.perm IS NOT NULL AND p.perm LIKE '%%%s%%') OR u.uid = 1) ",
'options' =>
$options,
);
$filters['status'] = array('title' =>
t('status'),
'where' =>
'u.status = %d',
'options' =>
array(1 => t('active'), 0 => t('blocked')),
);
return $filters;
}
/**
* Build query for user administration filters
based on session.
*/
function
user_build_filter_query() {
$filters = user_filters();
// Build query
$where = $args = $join = array();
foreach ($_SESSION['user_overview_filter'] as
$filter) {
list($key, $value) = $filter;
// This checks to see if this permission
filter is an enabled permission for the authenticated role.
// If so, then all users would be listed,
and we can skip adding it to the filter query.
if ($key == 'permission') {
$account = new stdClass();
$account->uid = 'user_filter';
$account->roles =
array(DRUPAL_AUTHENTICATED_RID => 1);
if (user_access($value, $account)) {
continue;
}
}
$where[] = $filters[$key]['where'];
$args[] = $value;
$join[] = $filters[$key]['join'];
}
$where = count($where) ? 'AND '. implode('
AND ', $where) : '';
$join = count($join) ? ' '. implode(' ',
array_unique($join)) : '';
return array('where' => $where,
'join' => $join,
'args' => $args,
);
}
/**
* Return form for user administration filters.
*/
function user_filter_form() {
$session =
&$_SESSION['user_overview_filter'];
$session = is_array($session) ? $session :
array();
$filters = user_filters();
$i = 0;
$form['filters'] = array('#type' =>
'fieldset',
'#title' => t('Show
only users where'),
'#theme' =>
'user_filters',
);
foreach ($session as $filter) {
list($type, $value) = $filter;
$string = ($i++ ? '<em>and</em>
where <strong>%a</strong> is <strong>%b</strong>' :
'<strong>%a</strong> is <strong>%b</strong>');
// Merge an array of arrays into one if
necessary.
$options = $type == 'permission' ?
call_user_func_array('array_merge', $filters[$type]['options']) :
$filters[$type]['options'];
$form['filters']['current'][] =
array('#value' => t($string, array('%a' => $filters[$type]['title'] ,
'%b' => $options[$value])));
}
foreach ($filters as $key => $filter) {
$names[$key] = $filter['title'];
$form['filters']['status'][$key] =
array('#type' => 'select',
'#options' => $filter['options'],
);
}
$form['filters']['filter'] = array('#type'
=> 'radios',
'#options'
=> $names,
);
$form['filters']['buttons']['submit'] =
array('#type' => 'submit',
'#value' => (count($session) ? t('Refine') : t('Filter'))
);
if (count($session)) {
$form['filters']['buttons']['undo'] =
array('#type' => 'submit',
'#value' => t('Undo')
);
$form['filters']['buttons']['reset'] =
array('#type' => 'submit',
'#value' => t('Reset')
);
}
return $form;
}
/**
* Theme user administration filter form.
*/
function
theme_user_filter_form($form) {
$output = '<div
id="user-admin-filter">';
$output .= drupal_render($form['filters']);
$output .= '</div>';
$output .= drupal_render($form);
return $output;
}
/**
* Theme user administration filter selector.
*/
function
theme_user_filters($form) {
$output = '<ul
class="clear-block">';
if (sizeof($form['current'])) {
foreach (element_children($form['current'])
as $key) {
$output .= '<li>'.
drupal_render($form['current'][$key]) .'</li>';
}
}
$output .= '<li><dl
class="multiselect">'. (sizeof($form['current']) ?
'<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' :
'') .'<dd class="a">';
foreach (element_children($form['filter']) as
$key) {
$output .= drupal_render($form['filter'][$key]);
}
$output .= '</dd>';
$output .= '<dt>'. t('is')
.'</dt><dd class="b">';
foreach (element_children($form['status']) as
$key) {
$output .=
drupal_render($form['status'][$key]);
}
$output .= '</dd>';
$output .= '</dl>';
$output .= '<div
class="container-inline" id="user-admin-buttons">'.
drupal_render($form['buttons']) .'</div>';
$output .= '</li></ul>';
return $output;
}
/**
* Process result from user administration
filter form.
*/
function user_filter_form_submit($form_id,
$form_values) {
$op = $form_values['op'];
$filters = user_filters();
switch ($op) {
case t('Filter'): case t('Refine'):
if (isset($form_values['filter'])) {
$filter = $form_values['filter'];
// Merge an array of arrays into one if
necessary.
$options = $filter == 'permission' ?
call_user_func_array('array_merge', $filters[$filter]['options']) :
$filters[$filter]['options'];
if
(isset($options[$form_values[$filter]])) {
$_SESSION['user_overview_filter'][] =
array($filter, $form_values[$filter]);
}
}
break;
case t('Undo'):
array_pop($_SESSION['user_overview_filter']);
break;
case t('Reset'):
$_SESSION['user_overview_filter'] = array();
break;
case t('Update'):
return;
}
return 'admin/user/user';
}
function user_forms() {
$forms['user_admin_access_add_form']['callback'] =
'user_admin_access_form';
$forms['user_admin_access_edit_form']['callback'] = 'user_admin_access_form';
$forms['user_admin_new_role']['callback'] =
'user_admin_role';
return $forms;
}
USER.CSS
/* $Id: user.css,v 1.4
2006/12/30 07:45:31 dries Exp $ */
#permissions td.module {
font-weight: bold;
}
#permissions td.permission {
padding-left: 1.5em;
}
#access-rules .access-type,
#access-rules .rule-type {
margin-right: 1em;
float: left;
}
#access-rules .access-type
.form-item, #access-rules .rule-type .form-item {
margin-top: 0;
}
#access-rules .mask {
clear: both;
}
#user-login-form {
text-align: center;
}
#user-admin-filter ul {
list-style-type: none;
padding: 0;
margin: 0;
width: 100%;
}
#user-admin-buttons {
float: left;
margin-left: 0.5em;
clear: right;
}
/* Generated by user.module
but used by profile.module: */
.profile {
clear: both;
margin: 1em 0;
}
/*
.profile .picture {
float: center;
margin: 1em 1em 1em 1em;
}
*/
.profile dt {
margin: 1em 0 0.2em 0;
font-weight: bold;
}
.profile dd {
margin:0;
}
#career{
width: 300px;
/*width: 400px;*/
margin: 5px;
padding-left: 5px;
float: left;
}
#personal{
width: 300px;
/*width: 400px;*/
margin: 5px;
float: left;
}
.profile .picture{
width: 300px;
margin: 5px;
padding: 5px;
float: left;
}
#college{
width: 300px;
/*width: 400px;*/
/*padding-left: 300px;
padding-right: 300px;*/
margin: 5px;
float: left;
}
PROFILE.MODULE
<?php
// $Id: profile.module,v
1.189.2.1 2007/01/23 19:09:58 dries Exp $
/**
* @file
* Support for configurable user profiles.
*/
/**
* Private field, content only available to
privileged users.
*/
define('PROFILE_PRIVATE',
1);
/**
* Public field, content shown on profile page
but not used on member list pages.
*/
define('PROFILE_PUBLIC', 2);
/**
* Public field, content shown on profile page
and on member list pages.
*/
define('PROFILE_PUBLIC_LISTINGS',
3);
/**
* Hidden profile field, only accessible by
administrators, modules and themes.
*/
define('PROFILE_HIDDEN', 4);
/**
* Implementation of hook_help().
*/
function
profile_help($section) {
switch ($section) {
case 'admin/help#profile':
$output = '<p>'. t('The profile
module allows you to define custom fields (such as country, real name, age,
...) in the user profile. This permits users of a site to share more
information about themselves, and can help community-based sites to organize
users around profile fields.') .'</p>';
$output .= t('<p>The following
types of fields can be added to the user profile:</p>
<ul>
<li>single-line
textfield</li>
<li>multi-line
textfield</li>
<li>checkbox</li>
<li>list
selection</li>
<li>freeform
list</li>
<li>URL</li>
<li>date</li>
</ul>
');
$output .= '<p>'. t('For more
information please read the configuration and customization handbook <a
href="@profile">Profile page</a>.', array('@profile' =>
'http://drupal.org/handbook/modules/profile/')) .'</p>';
return $output;
case 'admin/user/profile':
return '<p>'. t('Here you can
define custom fields that users can fill in in their user profile (such as
<em>country</em>, <em>real name</em>,
<em>age</em>, ...).') .'</p>';
}
}
/**
* Implementation of hook_menu().
*/
function
profile_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array('path' => 'profile',
'title' => t('User list'),
'callback' => 'profile_browse',
'access' => user_access('access user
profiles'),
'type' => MENU_SUGGESTED_ITEM);
$items[] = array('path' =>
'admin/user/profile',
'title' => t('Profiles'),
'description' => t('Create
customizable fields for your users.'),
'callback' => 'profile_admin_overview');
$items[] = array('path' =>
'admin/user/profile/add',
'title' => t('Add field'),
'callback' => 'drupal_get_form',
'callback arguments' =>
array('profile_field_form'),
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'admin/user/profile/autocomplete',
'title' => t('Profile category
autocomplete'),
'callback' =>
'profile_admin_settings_autocomplete',
'access' => user_access('administer
users'),
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'admin/user/profile/edit',
'title' => t('Edit field'),
'callback' => 'drupal_get_form',
'callback arguments' =>
array('profile_field_form'),
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'admin/user/profile/delete',
'title' => t('Delete field'),
'callback' => 'drupal_get_form',
'callback arguments' =>
array('profile_field_delete'),
'type' => MENU_CALLBACK);
$items[] = array('path' =>
'profile/autocomplete', 'title' => t('Profile autocomplete'),
'callback' => 'profile_autocomplete',
'access' => 1,
'type' => MENU_CALLBACK);
}
return $items;
}
/**
* Implementation of hook_block().
*/
function profile_block($op =
'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$blocks[0]['info'] = t('Author
information');
return $blocks;
}
else if ($op == 'configure' && $delta
== 0) {
// Compile a list of fields to show
$fields = array();
$result = db_query('SELECT name, title,
weight, visibility FROM {profile_fields} WHERE visibility IN (%d, %d) ORDER BY
weight', PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result))
{
$fields[$record->name] =
$record->title;
}
$fields['user_profile'] = t('Link to full user
profile');
$form['profile_block_author_fields'] =
array('#type' => 'checkboxes',
'#title' => t('Profile fields to
display'),
'#default_value' =>
variable_get('profile_block_author_fields', NULL),
'#options' => $fields,
'#description' => t('Select which
profile fields you wish to display in the block. Only fields designated as
public in the <a href="@profile-admin">profile field
configuration</a> are available.', array('@profile-admin' =>
url('admin/user/profile'))),
);
return $form;
}
else if ($op == 'save' && $delta ==
0) {
variable_set('profile_block_author_fields',
$edit['profile_block_author_fields']);
}
else if ($op == 'view') {
if (user_access('access user profiles')) {
if ((arg(0) == 'node') &&
is_numeric(arg(1)) && (arg(2) == NULL)) {
$node = node_load(arg(1));
$account = user_load(array('uid' =>
$node->uid));
if ($use_fields =
variable_get('profile_block_author_fields', array())) {
// Compile a list of fields to show.
$fields = array();
$result = db_query('SELECT name,
title, type, visibility, weight FROM {profile_fields} WHERE visibility IN (%d,
%d) ORDER BY weight', PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS);
while ($record =
db_fetch_object($result)) {
// Ensure that field is displayed
only if it is among the defined block fields and, if it is private, the user
has appropriate permissions.
if (isset($use_fields[$record->name])
&& $use_fields[$record->name]) {
$fields[] = $record;
}
}
}
if ($fields) {
$profile =
_profile_update_user_fields($fields, $account);
$output .= theme('profile_block',
$account, $profile, TRUE);
}
if (isset($use_fields['user_profile'])
&& $use_fields['user_profile']) {
$output .= '<div>'. l(t('View
full user profile'), 'user/'. $account->uid) .'</div>';
}
}
if ($output) {
$block['subject'] = t('About %name',
array('%name' => $account->name));
$block['content'] = $output;
return $block;
}
}
}
}
/**
* Implementation of hook_user().
*/
function profile_user($type,
&$edit, &$user, $category = NULL) {
switch ($type) {
case 'load':
return profile_load_profile($user);
case 'register':
return profile_form_profile($edit, $user,
$category, TRUE);
case 'update':
case 'insert':
return profile_save_profile($edit, $user,
$category);
case 'view':
return profile_view_profile($user);
case 'form':
return profile_form_profile($edit, $user,
$category);
case 'validate':
return profile_validate_profile($edit,
$category);
case 'categories':
return profile_categories();
case 'delete':
db_query('DELETE FROM {profile_values}
WHERE uid = %d', $user->uid);
}
}
/**
* Menu callback: Generate a form to add/edit a
user profile field.
*/
function
profile_field_form($arg = NULL) {
if (arg(3) == 'edit') {
if (is_numeric($arg)) {
$fid = $arg;
$edit = db_fetch_array(db_query('SELECT *
FROM {profile_fields} WHERE fid = %d', $fid));
if (!$edit) {
drupal_not_found();
return;
}
drupal_set_title(t('edit %title',
array('%title' => $edit['title'])));
$form['fid'] = array('#type' =>
'value',
'#value' => $fid,
);
$type = $edit['type'];
}
else {
drupal_not_found();
return;
}
}
else {
$types = _profile_field_types();
if (!isset($types[$arg])) {
drupal_not_found();
return;
}
$type = $arg;
drupal_set_title(t('add new %type',
array('%type' => $types[$type])));
$edit = array('name' => 'profile_');
$form['type'] = array('#type' =>
'value', '#value' => $type);
}
$form['fields'] = array('#type' =>
'fieldset',
'#title' => t('Field settings'),
);
$form['fields']['category'] = array('#type'
=> 'textfield',
'#title' => t('Category'),
'#default_value' => $edit['category'],
'#autocomplete_path' =>
'admin/user/profile/autocomplete',
'#description' => t('The category the
new field should be part of. Categories are used to group fields logically. An
example category is "Personal information".'),
'#required' => TRUE,
);
$form['fields']['title'] = array('#type'
=> 'textfield',
'#title' => t('Title'),
'#default_value' => $edit['title'],
'#description' => t('The title of the
new field. The title will be shown to the user. An example title is
"Favorite color".'),
'#required' => TRUE,
);
$form['fields']['name'] = array('#type' =>
'textfield',
'#title' => t('Form name'),
'#default_value' => $edit['name'],
'#description' => t('The name of the
field. The form name is not shown to the user but used internally in the HTML
code and URLs.
Unless you know what you are
doing, it is highly recommended that you prefix the form name with
<code>profile_</code> to avoid name clashes with other fields.
Spaces or any other special characters except dash (-) and underscore (_) are
not allowed. An example name is "profile_favorite_color" or perhaps
just "profile_color".'),
'#required' => TRUE,
);
$form['fields']['explanation'] =
array('#type' => 'textarea',
'#title' => t('Explanation'),
'#default_value' =>
$edit['explanation'],
'#description' => t('An optional
explanation to go with the new field. The explanation will be shown to the
user.'),
);
if ($type == 'selection') {
$form['fields']['options'] = array('#type'
=> 'textarea',
'#title' => t('Selection options'),
'#default_value' => $edit['options'],
'#description' => t('A list of all
options. Put each option on a separate line. Example options are
"red", "blue", "green", etc.'),
);
}
$form['fields']['weight'] = array('#type'
=> 'weight',
'#title' => t('Weight'),
'#default_value' => $edit['weight'],
'#delta' => 5,
'#description' => t('The weights define
the order in which the form fields are shown. Lighter fields "float
up" towards the top of the category.'),
);
$form['fields']['visibility'] = array('#type'
=> 'radios',
'#title' => t('Visibility'),
'#default_value' =>
isset($edit['visibility']) ? $edit['visibility'] : PROFILE_PUBLIC,
'#options' => array(PROFILE_HIDDEN =>
t('Hidden profile field, only accessible by administrators, modules and
themes.'), PROFILE_PRIVATE => t('Private field, content only available to
privileged users.'), PROFILE_PUBLIC => t('Public field, content shown on
profile page but not used on member list pages.'), PROFILE_PUBLIC_LISTINGS
=> t('Public field, content shown on profile page and on member list
pages.')),
);
if ($type == 'selection' || $type == 'list'
|| $type == 'textfield') {
$form['fields']['page'] = array('#type'
=> 'textfield',
'#title' => t('Page title'),
'#default_value' => $edit['page'],
'#description' => t('To enable
browsing this field by value, enter a title for the resulting page. The word
<code>%value</code> will be substituted with the corresponding
value. An example page title is "People whose favorite color is
%value". This is only applicable for a public field.'),
);
}
else if ($type == 'checkbox') {
$form['fields']['page'] = array('#type'
=> 'textfield',
'#title' => t('Page title'),
'#default_value' => $edit['page'],
'#description' => t('To enable
browsing this field by value, enter a title for the resulting page. An example
page title is "People who are employed". This is only applicable for
a public field.'),
);
}
$form['fields']['autocomplete'] =
array('#type' => 'checkbox',
'#title' => t('Form will auto-complete
while user is typing.'),
'#default_value' =>
$edit['autocomplete'],
);
$form['fields']['required'] = array('#type'
=> 'checkbox',
'#title' => t('The user must enter a
value.'),
'#default_value' => $edit['required'],
);
$form['fields']['register'] = array('#type'
=> 'checkbox',
'#title' => t('Visible in user
registration form.'),
'#default_value' => $edit['register'],
);
$form['submit'] = array('#type' =>
'submit',
'#value' => t('Save field'),
);
return $form;
}
/**
* Validate profile_field_form submissions.
*/
function
profile_field_form_validate($form_id, $form_values) {
// Validate the 'field name':
if (preg_match('/[^a-zA-Z0-9_-]/',
$form_values['name'])) {
form_set_error('name', t('The specified
form name contains one or more illegal characters. Spaces or any other special
characters except dash (-) and underscore (_) are not allowed.'));
}
if (in_array($form_values['name'],
user_fields())) {
form_set_error('name', t('The specified
form name is reserved for use by Drupal.'));
}
// Validate the category:
if (!$form_values['category']) {
form_set_error('category', t('You must
enter a category.'));
}
if ($form_values['category'] == 'account') {
form_set_error('category', t('The specified
category name is reserved for use by Drupal.'));
}
$args1 = array($form_values['title'],
$form_values['category']);
$args2 = array($form_values['name']);
$query_suffix = '';
if (isset($form_values['fid'])) {
$args1[] = $args2[] = $form_values['fid'];
$query_suffix = ' AND fid != %d';
}
if (db_result(db_query("SELECT fid FROM
{profile_fields} WHERE title = '%s' AND category = '%s'". $query_suffix,
$args1))) {
form_set_error('title', t('The specified
title is already in use.'));
}
if (db_result(db_query("SELECT fid FROM
{profile_fields} WHERE name = '%s'". $query_suffix, $args2))) {
form_set_error('name', t('The specified
name is already in use.'));
}
}
/**
* Process profile_field_form submissions.
*/
function
profile_field_form_submit($form_id, $form_values) {
if (!isset($form_values['fid'])) {
db_query("INSERT INTO {profile_fields}
(title, name, explanation, category, type, weight, required, register,
visibility, autocomplete, options, page) VALUES ('%s', '%s', '%s', '%s', '%s',
%d, %d, %d, %d, %d, '%s', '%s')", $form_values['title'],
$form_values['name'], $form_values['explanation'], $form_values['category'],
$form_values['type'], $form_values['weight'], $form_values['required'],
$form_values['register'], $form_values['visibility'],
$form_values['autocomplete'], $form_values['options'], $form_values['page']);
drupal_set_message(t('The field has been
created.'));
watchdog('profile', t('Profile field %field
added under category %category.', array('%field' => $form_values['title'],
'%category' => $form_values['category'])), WATCHDOG_NOTICE, l(t('view'),
'admin/user/profile'));
}
else {
db_query("UPDATE {profile_fields} SET
title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d,
required = %d, register = %d, visibility = %d, autocomplete = %d, options =
'%s', page = '%s' WHERE fid = %d", $form_values['title'],
$form_values['name'], $form_values['explanation'], $form_values['category'],
$form_values['weight'], $form_values['required'], $form_values['register'],
$form_values['visibility'], $form_values['autocomplete'],
$form_values['options'], $form_values['page'], $form_values['fid']);
drupal_set_message(t('The field has been
updated.'));
}
cache_clear_all();
return 'admin/user/profile';
}
/**
* Menu callback; deletes a field from all user
profiles.
*/
function
profile_field_delete($fid) {
$field =
db_fetch_object(db_query("SELECT title FROM {profile_fields} WHERE fid =
%d", $fid));
if (!$field) {
drupal_not_found();
return;
}
$form['fid'] = array('#type' => 'value',
'#value' => $fid);
$form['title'] = array('#type' => 'value',
'#value' => $field->title);
return confirm_form($form,
t('Are you sure you want to delete the
field %field?', array('%field' => $field->title)), 'admin/user/profile',
t('This action cannot be undone. If users
have entered values into this field in their profile, these entries will also
be deleted. If you want to keep the user-entered data, instead of deleting the
field you may wish to <a href="@edit-field">edit this
field</a> and change it to a hidden profile field so that it may only be
accessed by administrators.', array('@edit-field' =>
url('admin/user/profile/edit/'. $fid))),
t('Delete'), t('Cancel'));
}
/**
* Process a field delete form submission.
*/
function
profile_field_delete_submit($form_id, $form_values) {
db_query('DELETE FROM {profile_fields} WHERE
fid = %d', $form_values['fid']);
db_query('DELETE FROM {profile_values} WHERE
fid = %d', $form_values['fid']);
cache_clear_all();
drupal_set_message(t('The field %field has
been deleted.', array('%field' => $form_values['title'])));
watchdog('profile', t('Profile field %field
deleted.', array('%field' => $form_values['title'])), WATCHDOG_NOTICE,
l(t('view'), 'admin/user/profile'));
return 'admin/user/profile';
}
/**
* Menu callback; display a listing of all
editable profile fields.
*/
function
profile_admin_overview() {
$result = db_query('SELECT * FROM
{profile_fields} ORDER BY category, weight');
$rows = array();
while ($field = db_fetch_object($result)) {
$rows[] = array(check_plain($field->title),
$field->name, _profile_field_types($field->type), $field->category,
l(t('edit'), "admin/user/profile/edit/$field->fid"),
l(t('delete'), "admin/user/profile/delete/$field->fid"));
}
if (count($rows) == 0) {
$rows[] = array(array('data' => t('No
fields defined.'), 'colspan' => '6'));
}
$header = array(t('Title'), t('Name'),
t('Type'), t('Category'), array('data' => t('Operations'), 'colspan' =>
'2'));
$output
= theme('table', $header, $rows);
$output .= '<h2>'. t('Add new field') .'</h2>';
$output .= '<ul>';
foreach (_profile_field_types() as $key =>
$value) {
$output .= '<li>'. l($value,
"admin/user/profile/add/$key") .'</li>';
}
$output .= '</ul>';
return $output;
}
/**
* Menu callback; display a list of user information.
*/
function profile_browse() {
$name = arg(1);
list(, , $value) = explode('/', $_GET['q'],
3);
$field =
db_fetch_object(db_query("SELECT DISTINCT(fid), type, title, page,
visibility FROM {profile_fields} WHERE name = '%s'", $name));
if ($name && $field->fid) {
// Only allow browsing of fields that have
a page title set.
if (empty($field->page)) {
drupal_not_found();
return;
}
// Do not allow browsing of private fields
by non-admins.
if (!user_access('administer users')
&& $field->visibility == PROFILE_PRIVATE) {
drupal_access_denied();
return;
}
// Compile a list of fields to show.
$fields = array();
$result = db_query('SELECT name, title,
type, weight, page FROM {profile_fields} WHERE fid != %d AND visibility = %d
ORDER BY weight', $field->fid, PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result))
{
$fields[] = $record;
}
// Determine what query to use:
$arguments = array($field->fid);
switch ($field->type) {
case 'checkbox':
$query = 'v.value = 1';
break;
case 'textfield':
case 'selection':
$query = "v.value = '%s'";
$arguments[] = $value;
break;
case 'list':
$query = "v.value LIKE
'%%%s%%'";
$arguments[] = $value;
break;
default:
drupal_not_found();
return;
}
// Extract the affected users:
$result = pager_query("SELECT u.uid,
u.access FROM {users} u INNER JOIN {profile_values} v ON u.uid = v.uid WHERE
v.fid = %d AND $query AND u.access != 0 AND u.status != 0 ORDER BY u.name
ASC", 20, 0, NULL, $arguments);
$output = '<div
id="profile">';
while ($account = db_fetch_object($result))
{
$account = user_load(array('uid' =>
$account->uid));
$profile =
_profile_update_user_fields($fields, $account);
$output .= theme('profile_listing',
$account, $profile);
}
$output .= theme('pager', NULL, 20);
if ($field->type == 'selection' ||
$field->type == 'list' || $field->type == 'textfield') {
$title =
strtr(check_plain($field->page), array('%value' => theme('placeholder',
$value)));
}
else {
$title = check_plain($field->page);
}
$output .= '</div>';
drupal_set_title($title);
return $output;
}
else if ($name && !$field->fid) {
drupal_not_found();
}
else {
// Compile a list of fields to show.
$fields = array();
$result = db_query('SELECT name, title,
type, weight, page FROM {profile_fields} WHERE visibility = %d ORDER BY
category, weight', PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result))
{
$fields[] = $record;
}
// Extract the affected users:
//$result = pager_query('SELECT uid, access
FROM {users} WHERE uid > 0 AND status != 0 AND access != 0 ORDER BY access
DESC', 20, 0, NULL);
$result = pager_query('SELECT uid, access FROM {users} WHERE
uid > 0 AND status != 0 AND access != 0 ORDER BY name ASC', 20, 0, NULL);
$output = '<div
id="profile">';
while ($account = db_fetch_object($result))
{
if( $account->uid != 1 ) {
$account = user_load(array('uid' =>
$account->uid));
$profile =
_profile_update_user_fields($fields, $account);
$output .= theme('profile_listing',
$account, $profile);
}
}
$output .= '</div>';
$output .= theme('pager', NULL, 20);
drupal_set_title(t('user list'));
return $output;
}
}
function
profile_load_profile(&$user) {
$result = db_query('SELECT f.name, f.type,
v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid
WHERE uid = %d', $user->uid);
while ($field = db_fetch_object($result)) {
if (empty($user->{$field->name})) {
$user->{$field->name} =
_profile_field_serialize($field->type) ? unserialize($field->value) :
$field->value;
}
}
}
function
profile_save_profile(&$edit, &$user, $category) {
$result = _profile_get_fields($category);
while ($field = db_fetch_object($result)) {
if
(_profile_field_serialize($field->type)) {
$edit[$field->name] =
serialize($edit[$field->name]);
}
/**
brokenInsert
db_query("DELETE FROM {profile_values}
WHERE fid = %d AND uid = %d", $field->fid, $user->uid);
db_query("INSERT INTO {profile_values}
(fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid,
$edit[$field->name]);
// Mark field as handled (prevents saving
to user->data).
$edit[$field->name] = NULL;
*/
}
}
function
profile_view_field($user, $field) {
// Only allow browsing of private fields for
admins, if browsing is enabled,
// and if a user has permission to view
profiles. Note that this check is
// necessary because a user may always see
their own profile.
$browse = user_access('access user profiles')
&& (user_access('administer users')
|| $field->visibility != PROFILE_PRIVATE)
&& !empty($field->page);
if ($value = $user->{$field->name}) {
switch ($field->type) {
case 'textarea':
return check_markup($value);
case 'textfield':
case 'selection':
return $browse ?
l($value, 'search/profile/'. $value) : check_plain($value);
// return $browse ? l($value, 'profile/'.
$field->name .'/'. $value) : check_plain($value);
case 'checkbox':
return $browse ? l($field->title,
'profile/'. $field->name) : check_plain($field->title);
case 'url':
return '<a href="'.
check_url($value) .'">'. check_plain($value) .'</a>';
case 'date':
$format =
substr(variable_get('date_format_short', 'm/d/Y - H:i'), 0, 5);
// Note: Avoid PHP's date() because it does
not handle dates before
// 1970 on Windows. This would make the
date field useless for e.g.
// birthdays.
$replace = array('d' =>
sprintf('%02d', $value['day']),
'j' => $value['day'],
'm' =>
sprintf('%02d', $value['month']),
'M' =>
map_month($value['month']),
'Y' =>
$value['year'],
'H:i' => NULL,
'g:ia' => NULL);
return strtr($format, $replace);
case 'list':
$values = split("[,\n\r]",
$value);
$fields = array();
foreach ($values as $value) {
if ($value = trim($value)) {
$fields[] = $browse ? l($value,
'profile/'. $field->name .'/'. $value) : check_plain($value);
}
}
return implode(', ', $fields);
}
}
}
function
profile_view_profile($user) {
profile_load_profile($user);
// Show private fields to administrators and
people viewing their own account.
if (user_access('administer users') ||
$GLOBALS['user']->uid == $user->uid) {
$result = db_query('SELECT * FROM
{profile_fields} WHERE visibility != %d ORDER BY category, weight',
PROFILE_HIDDEN);
}
else {
$result = db_query('SELECT * FROM
{profile_fields} WHERE visibility != %d AND visibility != %d ORDER BY category,
weight', PROFILE_PRIVATE, PROFILE_HIDDEN);
}
while ($field = db_fetch_object($result)) {
if ($value = profile_view_field($user,
$field)) {
$title = ($field->type != 'checkbox')
? check_plain($field->title) : NULL;
$item = array('title' => $title,
'value' => $value,
'class' => $field->name,
);
$fields[$field->category][$field->name] = $item;
}
}
return $fields;
}
function
_profile_form_explanation($field) {
$output = $field->explanation;
if ($field->type == 'list') {
$output .= ' '. t('Put each item on a
separate line or separate them by commas. No HTML allowed.');
}
if ($field->visibility == PROFILE_PRIVATE)
{
$output .= ' '. t('The content of this
field is kept private and will not be shown publicly.');
}
return $output;
}
function
profile_form_profile($edit, $user, $category, $register = FALSE) {
$result = _profile_get_fields($category,
$register);
$w = 0;
while ($field = db_fetch_object($result)) {
$category = $field->category;
if (!isset($fields[$category])) {
$fields[$category] = array('#type' =>
'fieldset', '#title' => $category, '#weight' => $w++);
}
switch ($field->type) {
case 'textfield':
case 'url':
$fields[$category][$field->name] =
array('#type' => 'textfield',
'#title' =>
check_plain($field->title),
'#default_value' => $edit[$field->name],
'#maxlength' => 255,
'#description' =>
_profile_form_explanation($field),
'#required' =>
$field->required,
);
if ($field->autocomplete) {
$fields[$category][$field->name]['#autocomplete_path'] =
"profile/autocomplete/". $field->fid;
}
break;
case 'textarea':
$fields[$category][$field->name] =
array('#type' => 'textarea',
'#title' =>
check_plain($field->title),
'#default_value' => $edit[$field->name],
'#description' =>
_profile_form_explanation($field),
'#required' =>
$field->required,
);
break;
case 'list':
$fields[$category][$field->name] =
array('#type' => 'textarea',
'#title' =>
check_plain($field->title),
'#default_value' =>
$edit[$field->name],
'#description' =>
_profile_form_explanation($field),
'#required' =>
$field->required,
);
break;
case 'checkbox':
$fields[$category][$field->name] =
array('#type' => 'checkbox',
'#title' =>
check_plain($field->title),
'#default_value' =>
$edit[$field->name],
'#description' =>
_profile_form_explanation($field),
'#required' => $field->required,
);
break;
case 'selection':
$options = $field->required ?
array() : array('--');
$lines = split("[,\n\r]",
$field->options);
foreach ($lines as $line) {
if ($line = trim($line)) {
$options[$line] = $line;
}
}
$fields[$category][$field->name] =
array('#type' => 'select',
'#title' =>
check_plain($field->title),
'#default_value' =>
$edit[$field->name],
'#options' => $options,
'#description' =>
_profile_form_explanation($field),
'#required' =>
$field->required,
);
break;
case 'date':
$fields[$category][$field->name] =
array('#type' => 'date',
'#title' =>
check_plain($field->title),
'#default_value' =>
$edit[$field->name],
'#description' =>
_profile_form_explanation($field),
'#required' =>
$field->required,
);
break;
}
}
return $fields;
}
/**
* Callback to allow autocomplete of profile
text fields.
*/
function
profile_autocomplete($field, $string) {
if (db_result(db_query("SELECT COUNT(*)
FROM {profile_fields} WHERE fid = %d AND autocomplete = 1", $field))) {
$matches = array();
$result = db_query_range("SELECT value
FROM {profile_values} WHERE fid = %d AND LOWER(value) LIKE LOWER('%s%%') GROUP
BY value ORDER BY value ASC", $field, $string, 0, 10);
while ($data = db_fetch_object($result)) {
$matches[$data->value] =
check_plain($data->value);
}
print drupal_to_js($matches);
}
exit();
}
/**
* Helper function: update an array of user
fields by calling profile_view_field
*/
function
_profile_update_user_fields($fields, $account) {
foreach ($fields as $key => $field) {
$fields[$key]->value =
profile_view_field($account, $field);
}
return $fields;
}
function
profile_validate_profile($edit, $category) {
$result = _profile_get_fields($category);
while ($field = db_fetch_object($result)) {
if ($edit[$field->name]) {
if ($field->type == 'url') {
if (!valid_url($edit[$field->name],
TRUE)) {
form_set_error($field->name,
t('The value provided for %field is not a valid URL.', array('%field' =>
$field->title)));
}
}
}
else if ($field->required &&
!user_access('administer users')) {
form_set_error($field->name, t('The
field %field is required.', array('%field' => $field->title)));
}
}
return $edit;
}
function
profile_categories() {
$result = db_query("SELECT
DISTINCT(category) FROM {profile_fields}");
while ($category = db_fetch_object($result))
{
$data[] = array('name' =>
$category->category, 'title' => $category->category, 'weight' =>
3);
}
return $data;
}
function
theme_profile_block($account, $fields = array()) {
$output .= theme('user_picture', $account);
foreach ($fields as $field) {
if ($field->value) {
if ($field->type == 'checkbox') {
$output .=
"<p>$field->value</p>\n";
}
else {
$output .=
"<p><strong>$field->title</strong><br
/>$field->value</p>\n";
}
}
}
return $output;
}
function
theme_profile_listing($account, $fields = array()) {
$output
= "<div class=\"profile\">\n";
$output .= ' <div
class="name">'. theme('username', $account) ."</div>\n";
foreach ($fields as $field) {
if ($field->value) {
$output .= " <div
class=\"field\">$field->value</div>\n";
}
}
$output .= theme('user_picture', $account);
$output .= '</div><p
style="clear:both"> </p><hr />';
$output .= "\n";
return $output;
}
/*
function
theme_profile_listing($account, $fields = array()) {
$output
= "<div class=\"profile\">\n";
$output .= theme('user_picture', $account);
$output .= ' <div
class="name">'. theme('username', $account) ."</div>\n";
foreach ($fields as $field) {
if ($field->value) {
$output .= " <div
class=\"field\">$field->value</div>\n";
}
}
$output .= "</div>\n";
return $output;
}
*/
function
_profile_field_types($type = NULL) {
$types = array('textfield' =>
t('single-line textfield'),
'textarea' => t('multi-line
textfield'),
'checkbox' =>
t('checkbox'),
'selection' => t('list
selection'),
'list' => t('freeform
list'),
'url' => t('URL'),
'date' => t('date'));
return isset($type) ? $types[$type] : $types;
}
function
_profile_field_serialize($type = NULL) {
return $type == 'date';
}
function
_profile_get_fields($category, $register = FALSE) {
$args = array();
$sql = 'SELECT * FROM {profile_fields} WHERE
';
$filters = array();
if ($register) {
$filters[] = 'register = 1';
}
else {
// Use LOWER('%s') instead of PHP's
strtolower() to avoid UTF-8 conversion issues.
$filters[] = "LOWER(category) =
LOWER('%s')";
$args[] = $category;
}
if (!user_access('administer users')) {
$filters[] = 'visibility != %d';
$args[] = PROFILE_HIDDEN;
}
$sql .= implode(' AND ', $filters);
$sql .= ' ORDER BY category, weight';
return db_query($sql, $args);
}
/**
* Retrieve a pipe delimited string of
autocomplete suggestions for profile categories
*/
function
profile_admin_settings_autocomplete($string) {
$matches = array();
$result = db_query_range("SELECT
category FROM {profile_fields} WHERE LOWER(category) LIKE LOWER('%s%%')",
$string, 0, 10);
while ($data = db_fetch_object($result)) {
$matches[$data->category] =
check_plain($data->category);
}
print drupal_to_js($matches);
exit();
}
/**
* Implementation of hook_search().
* Programmed by: Chuck Feltes
*/
function profile_search($op
= 'search', $keys = NULL) {
switch ($op) {
case 'name':
return t('Profiles');
case 'search':
$find = array();
// Replace wildcards with MySQL / PostgreSQL wildcards
(from user_search)
$keys = preg_replace('!\*+!', '%', $keys);
// Build query - check against full_name and grad_year
// grad_year stored as a string
$query = "SELECT * FROM (users) WHERE LOWER(data)
LIKE LOWER('%%%s%%')";
$result = pager_query($query, 15, 0, NULL, $keys);
while($info = db_fetch_object($result) )
{
$unserialized_data = unserialize($info->data);
$snippet_info = '';
if(is_array($unserialized_data)) {
if(
$unserialized_data['profile_full_name']!=NULL) {
$name = $unserialized_data['profile_full_name'];
}
if(
$unserialized_data['profile_major']!=NULL) {
$snippet_info .= 'Major: '.
$unserialized_data['profile_major']. '<br />';
}
if(
$unserialized_data['profile_grad_year']!=NULL) {
$snippet_info .= 'Graduation Year: '.
$unserialized_data['profile_grad_year']. '<br />';
}
}
// if the data didn't come out as an array,
something went wrong
// so do a default link
else {
$name = $info->name;
}
if($info->picture != NULL ) {
$snippet_info
.= '<img src="'. $info->picture. '" />';
}
$find[] = array('title' => $name, 'link' =>
url('user/'. $info->uid, NULL, NULL, TRUE), 'snippet'=>$snippet_info);
/**
if($item->picture != NULL ) {
$picture = array('<img src="'. $info->picture.
'" />' );
}
$find[] = array( 'title' => $info->name,
'link' => url('user/'.
$info->uid, NULL, NULL, TRUE),
'snippet' => '<img
src="'. $info->picture. '" />' );*/
// 'snippet' => 'Graduation Year:
'. $account->profile_grad_year. '<br />Major: '.
$account->profile_major);
}
return $find;
}
}