/** install an additional theme * * this routine attempts to insert the information from the * manifest of theme $theme_key into the database. * The routine displays the result (error or success) in a * message in $output. Details can be found in the logs. * * The theme_key is validated by reading all existing module manifests. * This is quite expensive, but that is not important because we * do not use this routine very often anyway. * * Note that we assume that the actual thenes are already * unpacked into the correct directories. * The corresponding manifest should exist in the directory * /program/themes/$theme_key. * * @param object &$output collects the html output * @param string $theme_key primary key for theme record in database AND name of the /program/themes subdirectory * @return void results are returned as output in $output * @uses $CFG * @todo we should refactor and combine install_theme() and install_module() */ function install_theme(&$output, $theme_key) { global $CFG; $retval = TRUE; // assume success $theme_key = strval($theme_key); $progdir_themes = $CFG->progdir . '/themes'; $manifests = get_manifests($progdir_themes); $params = array('{THEME}' => $theme_key); // 0 -- sanity check if (!isset($manifests[$theme_key])) { logger(sprintf('%s(): manifest for theme \'%s\' not found; nothing installed', __FUNCTION__, $theme_key)); $retval = FALSE; } else { // 1 -- preliminary creation of a new theme record (we need the pkey in the installer) $manifest = $manifests[$theme_key]; $table = 'themes'; $fields = array('name' => $theme_key, 'version' => 0, 'manifest' => $manifest['manifest'], 'is_core' => isset($manifest['is_core']) && $manifest['is_core'] ? TRUE : FALSE, 'is_active' => FALSE, 'class' => isset($manifest['class']) ? $manifest['class'] : NULL, 'class_file' => isset($manifest['class_file']) ? $manifest['class_file'] : NULL); $key_field = 'theme_id'; if (($theme_id = db_insert_into_and_get_id($table, $fields, $key_field)) === FALSE) { logger(sprintf('%s(): cannot install theme \'%s\': %s', __FUNCTION__, $theme_key, db_errormessage())); $retval = FALSE; } else { // 2A -- maybe insert tables for theme if (isset($manifest['tabledefs']) && !empty($manifest['tabledefs'])) { $filename = sprintf('%s/%s/%s', $progdir_themes, $theme_key, $manifest['tabledefs']); if (file_exists($filename)) { if (!update_create_tables($filename)) { $retval = FALSE; } } } // 2B -- call the installation routine $messages = array(); // collects error messages from call-back routine if (isset($manifest['install_script']) && !empty($manifest['install_script'])) { $filename = sprintf('%s/%s/%s', $progdir_themes, $theme_key, $manifest['install_script']); if (file_exists($filename)) { @(include_once $filename); $theme_install = $theme_key . '_install'; if (function_exists($theme_install)) { if ($theme_install($messages, $theme_id)) { logger(sprintf('%s(): %s(): success installing theme \'%s\' (version is %d)', __FUNCTION__, $theme_install, $theme_key, $manifest['version'])); } else { $retval = FALSE; logger(sprintf('%s(): %s() returned an error', __FUNCTION__, $theme_install)); } foreach ($messages as $message) { // remember messages, either good or bad logger($message); } } else { $retval = FALSE; logger(sprintf('%s(): function %s() does not exist?', __FUNCTION__, $theme_install)); } } else { $retval = FALSE; logger(sprintf('%s(): file %s does not exist?', __FUNCTION__, $filename)); } } else { $retval = FALSE; logger(sprintf('%s(): no install script in manifest for theme \'%s\'', __FUNCTION__, $theme_key)); } // 2C -- if all went well, we make the theme active if ($retval) { $where = array($key_field => $theme_id); $fields = array('is_active' => TRUE, 'version' => intval($manifest['version'])); if (db_update($table, $fields, $where) === FALSE) { logger(sprintf('%s(): cannot activate theme \'%s\': %s', __FUNCTION__, $theme_key, db_errormessage())); $retval = FALSE; } } } } if ($retval) { logger(sprintf('%s(): success installing theme \'%s\'', __FUNCTION__, $theme_key)); $output->add_message(t('update_subsystem_theme_success', 'admin', $params)); } else { $output->add_message(t('update_subsystem_theme_error', 'admin', $params)); } }
/** perform the actual initialisation of the cms * * this routine initialises the database: creates tables, * inserts essential data (first user account, other defaults) * and optional demonstration data. * * The strategy is as follows. * * - (1) manufacture a database object in the global $DB * - (2A) create the main tables (from /program/install/tabledefs.php) * - (2B) insert essential data (from /program/install/tabledata.php) * - (2C) store the collected data (website title, etc.), * - (3) if necessary, create the data directory * - (4) record the currently available languages in the database * - (5) create the first useraccount, * * Once the main part is done, install modules and themes based on the * relevant information that is stored in the corresponding manifest-file * by performing the following steps for each module and theme: * * - (6A) insert a record in the appropriate table with active = FALSE * - (6B) create the tables (if any tables are necessary according to the manifest) * - (6C) install the item by including a file and executing function <item>_install() * - (6D) flip the active flag in the record from step 5A to indicate success * * Subsequently the optional demodata is installed. * * - (7A) a foundation is created via the function demodata() from /program/install/demodata.php * - (7B) all modules + themes can add to the demo data via the appropriate subroutines * * If all goes well, this routine ends with an attempt to * * - (8) save the config.php file at the correct location. * (it is not an error if that does not work; it only * means that the user has to upload the config.php * file manually. * * @return bool TRUE on success, FALSE otherwise + messages in $this->messages[] * @todo should we save the config.php to the datadir if the main dir fails? Mmmm.... security implications? * @todo this routine badly needs refactoring */ function perform_installation() { global $DB; $retval = TRUE; // assume success // 0 -- do we have sane values at this point? If not, send user back to correct data if (!$this->check_validation()) { return FALSE; } // 1 -- try to create $DB /** Manufacture an object of the database class corresponding with requested db_type */ include_once dirname(__FILE__) . '/lib/database/databaselib.php'; $DB = database_factory($_SESSION['INSTALL']['db_prefix'], $_SESSION['INSTALL']['db_type']); if ($DB === FALSE) { // internal error, shouldn't happen (we already checked the database access a few dialogs ago) $this->messages[] = 'Internal error: cannot create database object'; return FALSE; } if (!@$DB->connect($_SESSION['INSTALL']['db_server'], $_SESSION['INSTALL']['db_username'], $_SESSION['INSTALL']['db_password'], $_SESSION['INSTALL']['db_name'])) { $this->messages[] = $this->t('error_db_cannot_connect') . ' (' . $DB->errno . '/\'' . $DB->error . '\')'; return FALSE; } // At this point we have a working database in our hands in the global $DB. // 2A -- create the main tables if (!$this->create_tables(dirname(__FILE__) . '/install/tabledefs.php')) { $retval = FALSE; } // 2B -- enter essential data in main tables (defaults etc.) if (!$this->insert_tabledata(dirname(__FILE__) . '/install/tabledata.php')) { $retval = FALSE; } // 2C -- enter additional configuration data to tables $config_updates = array('version' => $_SESSION['INSTALL']['WAS_VERSION'], 'salt' => $this->quasi_random_string(rand(22, 42), 62), 'title' => $_SESSION['INSTALL']['cms_title'], 'website_from_address' => $_SESSION['INSTALL']['cms_website_from_address'], 'website_replyto_address' => $_SESSION['INSTALL']['cms_website_replyto_address'], 'language_key' => $_SESSION['INSTALL']['language_key'], 'friendly_url' => $_SESSION['INSTALL']['friendly_url'] ? '1' : '0', 'clamscan_path' => $_SESSION['INSTALL']['clamscan_path'], 'clamscan_mandatory' => $_SESSION['INSTALL']['clamscan_mandatory'] ? '1' : '0'); foreach ($config_updates as $name => $value) { $where = array('name' => $name); $fields = array('value' => strval($value)); if (db_update('config', $fields, $where) === FALSE) { $params = array('{CONFIG}' => $name, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_update_config', $params); $retval = FALSE; } } // 3A -- maybe create dataroot $dataroot = $_SESSION['INSTALL']['cms_dataroot']; if (!is_dir($dataroot)) { // dataroot does not exist, try to create it if (!@mkdir($dataroot, 0700)) { $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($dataroot)); $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } // else { success creating $dataroot } } // else { nothing to do; we already tested for directory writability // 3B -- "protect" the datadirectory with a blank index.html @touch($dataroot . '/index.html'); // 3C -- setup our REAL datadirectory $subdirectory = $_SESSION['INSTALL']['cms_datasubdir']; if (empty($subdirectory)) { $subdirectory = md5($_SESSION['INSTALL']['cms_dir'] . $_SESSION['INSTALL']['cms_www'] . $this->quasi_random_string(13, 62) . $_SESSION['INSTALL']['cms_progdir'] . $_SESSION['INSTALL']['cms_progwww'] . $_SESSION['INSTALL']['cms_title'] . strval(time())); $datadir = $dataroot . '/' . $subdirectory; $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($datadir)); if (is_dir($datadir)) { $this->messages[] = $this->t('error_directory_exists', $params); $retval = FALSE; } elseif (!@mkdir($datadir, 0700)) { $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } else { $_SESSION['INSTALL']['cms_datasubdir'] = $subdirectory; } } // If the user changed $dataroot after a 1st failed attempt, // $subdirectory may not yet exist, we doublecheck and maybe mkdir $datadir = $dataroot . '/' . $subdirectory; if (!is_dir($datadir)) { if (!@mkdir($datadir, 0700)) { $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($datadir)); $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } } $_SESSION['INSTALL']['cms_datadir'] = $datadir; // construct_config_php() needs this @touch($datadir . '/index.html'); // "protect" directory // 3D -- setup essential subdirectories under our REAL datadirectory $datadir_subdirectories = array($datadir . '/areas', $datadir . '/users', $datadir . '/groups', $datadir . '/languages'); foreach ($datadir_subdirectories as $datadir_subdirectory) { if (!is_dir($datadir_subdirectory) && !@mkdir($datadir_subdirectory, 0700)) { $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($datadir_subdirectory)); $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } @touch($datadir_subdirectory . '/index.html'); // "protect" directory } // 4 -- languages: only add entry to table, no tabledefs or installer here $datadir_languages = $datadir . '/languages'; $languages = $this->get_manifests(dirname(__FILE__) . '/languages'); foreach ($languages as $language_key => $manifest) { $language_key = strval($language_key); if (!is_dir($datadir_languages . '/' . $language_key) && !@mkdir($datadir_languages . '/' . $language_key, 0700)) { $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($datadir_languages . '/' . $language_key)); $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } @touch($datadir_languages . '/' . $language_key . '/index.html'); // "protect" directory $table = 'languages'; $fields = array('language_key' => $language_key, 'language_name' => isset($manifest['language_name']) ? strval($manifest['language_name']) : '(' . $language_key . ')', 'parent_language_key' => isset($manifest['parent_language_key']) ? strval($manifest['parent_language_key']) : '', 'version' => intval($manifest['version']), 'manifest' => $manifest['manifest'], 'is_core' => isset($manifest['is_core']) && $manifest['is_core'] ? TRUE : FALSE, 'is_active' => TRUE, 'dialect_in_database' => FALSE, 'dialect_in_file' => FALSE); if (db_insert_into($table, $fields) === FALSE) { // This shouldn't happen in a freshly created database. However, try to continue with the next $params = array('{TABLENAME}' => $DB->prefix . $table, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_insert_into_table', $params); $retval = FALSE; continue; } } // 5 -- insert the first user account // 5A -- construct acl with all privileges for this main (root) user $table = 'acls'; $key_field = 'acl_id'; $fields = array('permissions_jobs' => -1, 'permissions_intranet' => -1, 'permissions_modules' => -1, 'permissions_nodes' => -1); $acl_id = db_insert_into_and_get_id($table, $fields, $key_field); if ($acl_id === FALSE) { // This shouldn't happen in a freshly created database. $params = array('{TABLENAME}' => $DB->prefix . $table, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_insert_into_table', $params); return FALSE; } // 5B -- create a personal datadirectory (based on the specified username) $username = $_SESSION['INSTALL']['user_username']; $userdata_directory = utf8_strtolower($this->sanitise_filename($username)); // If the username consists of only non-mappable UTF-8 chars, we end up with '_'; make that more readable... if ($userdata_directory == '_') { $userdata_directory = '_webmaster'; } $datadir_subdirectory = $datadir . '/users/' . $userdata_directory; if (!is_dir($datadir_subdirectory) && !@mkdir($datadir_subdirectory, 0700)) { $params = array('{FIELD}' => $this->t('cms_datadir_label'), '{DIRECTORY}' => htmlspecialchars($datadir_subdirectory)); $this->messages[] = $this->t('error_not_create_dir', $params); $retval = FALSE; } @touch($datadir_subdirectory . '/index.html'); // "protect" directory // 5C -- actually create the record in the users table $salt = $this->quasi_random_string(12, 62); // pick 12 characters from [0-9][A-Z][a-z] $table = 'users'; $key_field = 'user_id'; $fields = array('username' => $username, 'salt' => $salt, 'password_hash' => md5($salt . $_SESSION['INSTALL']['user_password']), 'full_name' => $_SESSION['INSTALL']['user_full_name'], 'email' => $_SESSION['INSTALL']['user_email'], 'is_active' => TRUE, 'redirect' => '', 'language_key' => $_SESSION['INSTALL']['language_key'], 'path' => $userdata_directory, 'acl_id' => intval($acl_id), 'editor' => 'ckeditor', 'skin' => $_SESSION['INSTALL']['high_visibility'] ? 'textonly' : 'base'); $user_id = db_insert_into_and_get_id($table, $fields, $key_field); if ($user_id === FALSE) { $params = array('{TABLENAME}' => $DB->prefix . $table, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_insert_into_table', $params); $retval = FALSE; } // 6 -- install modules and themes $subsystems = array('modules' => $this->get_manifests(dirname(__FILE__) . '/modules'), 'themes' => $this->get_manifests(dirname(__FILE__) . '/themes')); foreach ($subsystems as $subsystem => $manifests) { foreach ($manifests as $item => $manifest) { if (empty($manifest)) { $this->messages[] = $this->t('warning_no_manifest', array('{ITEM}' => $item)); continue; } // 6A -- prepare entry in the corresponding table switch ($subsystem) { case 'modules': $fields = array('name' => strval($item), 'version' => intval($manifest['version']), 'manifest' => $manifest['manifest'], 'is_core' => isset($manifest['is_core']) && $manifest['is_core'] ? TRUE : FALSE, 'is_active' => FALSE, 'has_acls' => isset($manifest['has_acls']) && $manifest['has_acls'] ? TRUE : FALSE, 'view_script' => isset($manifest['view_script']) ? $manifest['view_script'] : NULL, 'admin_script' => isset($manifest['admin_script']) ? $manifest['admin_script'] : NULL, 'search_script' => isset($manifest['search_script']) ? $manifest['search_script'] : NULL, 'cron_script' => isset($manifest['cron_script']) ? $manifest['cron_script'] : NULL, 'cron_interval' => isset($manifest['cron_interval']) ? intval($manifest['cron_interval']) : NULL, 'cron_next' => NULL); $key_field = 'module_id'; $table = 'modules'; break; case 'themes': $fields = array('name' => strval($item), 'version' => intval($manifest['version']), 'manifest' => $manifest['manifest'], 'is_core' => isset($manifest['is_core']) && $manifest['is_core'] ? TRUE : FALSE, 'is_active' => FALSE, 'class' => isset($manifest['class']) ? $manifest['class'] : NULL, 'class_file' => isset($manifest['class_file']) ? $manifest['class_file'] : NULL); $key_field = 'theme_id'; $table = 'themes'; break; default: $this->messages[] = 'Internal error: unknown subsystem ' . htmlspecialchars($subsystem); continue; break; } if (($item_id = db_insert_into_and_get_id($table, $fields, $key_field)) === FALSE) { // This shouldn't happen in a freshly created database. However, try to continue with the next $params = array('{TABLENAME}' => $DB->prefix . $table, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_insert_into_table', $params); $retval = FALSE; continue; } $is_active = TRUE; // assume we can successfully install the item // 6B -- maybe insert tables for item if (isset($manifest['tabledefs']) && !empty($manifest['tabledefs'])) { $filename = dirname(__FILE__) . '/' . $subsystem . '/' . $item . '/' . $manifest['tabledefs']; if (file_exists($filename)) { if (!$this->create_tables($filename)) { $retval = FALSE; $is_active = FALSE; } } } // 6C -- maybe install this module or theme if (isset($manifest['install_script']) && !empty($manifest['install_script'])) { $filename = dirname(__FILE__) . '/' . $subsystem . '/' . $item . '/' . $manifest['install_script']; if (file_exists($filename)) { @(include_once $filename); $item_install = $item . '_install'; if (function_exists($item_install)) { if (!$item_install($this->messages, $item_id)) { $retval = FALSE; $is_active = FALSE; } } } } // 6D -- indicate everything went well if ($is_active) { $where = array($key_field => $item_id); $fields = array('is_active' => $is_active); if (db_update($table, $fields, $where) === FALSE) { $params = array('{CONFIG}' => $item, '{ERRNO}' => $DB->errno, '{ERROR}' => $DB->error); $this->messages[] = $this->t('error_update_config', $params); $retval = FALSE; $is_active = FALSE; // this should not happen (famous last words...) } } $subsystems[$subsystem][$item]['is_active'] = $is_active; $subsystems[$subsystem][$item]['key_field'] = $key_field; $subsystems[$subsystem][$item]['item_id'] = $item_id; } // foreach item } // foreach subsystem // 7 -- Demodata if ($_SESSION['INSTALL']['cms_demodata']) { // 7A -- prepare essential information for demodata installation $demodata_config = array('language_key' => $_SESSION['INSTALL']['language_key'], 'dir' => $_SESSION['INSTALL']['cms_dir'], 'www' => $_SESSION['INSTALL']['cms_www'], 'progdir' => $_SESSION['INSTALL']['cms_progdir'], 'progwww' => $_SESSION['INSTALL']['cms_progwww'], 'datadir' => $_SESSION['INSTALL']['cms_datadir'], 'title' => $_SESSION['INSTALL']['cms_title'], 'replyto' => $_SESSION['INSTALL']['cms_website_replyto_address'], 'user_username' => $_SESSION['INSTALL']['user_username'], 'user_full_name' => $_SESSION['INSTALL']['user_full_name'], 'user_email' => $_SESSION['INSTALL']['user_email'], 'user_id' => $user_id, 'demo_salt' => $_SESSION['INSTALL']['cms_demodata_salt'], 'demo_password' => $_SESSION['INSTALL']['cms_demodata_password'], 'friendly_url' => $_SESSION['INSTALL']['friendly_url'], 'demo_areas' => array(), 'demo_groups' => array(), 'demo_users' => array(), 'demo_nodes' => array()); $filename = dirname(__FILE__) . '/install/demodata.php'; include_once $filename; if (!demodata($this->messages, $demodata_config)) { $this->messages[] = $this->t('error_install_demodata'); $retval = FALSE; } // 7B -- insert demodata for all modules and themes foreach ($subsystems as $subsystem => $manifests) { foreach ($manifests as $item => $manifest) { $item_demodata = $item . '_demodata'; if (function_exists($item_demodata)) { if (!$item_demodata($this->messages, intval($manifest['item_id']), $demodata_config, $manifest)) { $this->messages[] = $this->t('error_install_demodata'); $retval = FALSE; } } } } } // 8 -- Finish with attempt to write config.php if ($retval) { $_SESSION['INSTALL']['config_php_written'] = $this->write_config_php(); } return $retval; }
/** save the newly added area to the database * * This saves the essential information of a new area to the database, * using sensible defaults for the other fields. Also, a data directory * is created and the relative path is stored in the new area record. * * If something goes wrong, the user can redo the dialog, otherwise we * return to the area overview. * * @return void results are returned as output in $this->output * @uses $WAS_SCRIPT_NAME * @uses $CFG * @uses $USER */ function area_savenew() { global $WAS_SCRIPT_NAME, $USER, $CFG; // 1 -- bail out if user pressed cancel button if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->area_overview(); return; } // 2 -- dow we have permission to add an area? if (!$USER->has_site_permissions(PERMISSION_SITE_ADD_AREA)) { logger("areamanager: user attempted to add an area without permission"); $msg = t('task_area_add_access_denied', 'admin'); $this->output->add_message($msg); $this->output->add_popup_bottom($msg); $this->area_overview(); return; } // 3 -- validate the data $invalid = FALSE; $dialogdef = $this->get_dialogdef_add_area(); // 3A -- check for generic errors (string too short, number too small, etc) if (!dialog_validate($dialogdef)) { $invalid = TRUE; } // 3B -- additional check: valid datadirectory name entered $path = $dialogdef['area_path']['value']; $fname = isset($dialogdef['area_path']['label']) ? $dialogdef['area_path']['label'] : 'area_path'; $params = array('{FIELD}' => str_replace('~', '', $fname)); $areadata_directory = sanitise_filename($path); if ($path != $areadata_directory) { // User probably entered a few 'illegal' characters. This is no good $dialogdef['area_path']['value'] = $areadata_directory; // 'Help' user with a better proposition ++$dialogdef['area_path']['errors']; $params['{VALUE}'] = htmlspecialchars($path); $dialogdef['area_path']['error_messages'][] = t('validate_bad_filename', '', $params); $invalid = TRUE; } // 3C -- additional check: unique datadirectory name entered $areadata_directory = strtolower($areadata_directory); $where = array('path' => $areadata_directory); if (db_select_single_record('areas', 'area_id', $where) !== FALSE) { // Oops, a record with that path already exists. Go flag error ++$dialogdef['area_path']['errors']; $params['{VALUE}'] = $areadata_directory; $dialogdef['area_path']['error_messages'][] = t('validate_not_unique', '', $params); $invalid = TRUE; } // 3D -- additional check: can we create said directory? $areadata_full_path = $CFG->datadir . '/areas/' . $areadata_directory; $areadata_directory_created = @mkdir($areadata_full_path, 0700); if ($areadata_directory_created) { @touch($areadata_full_path . '/index.html'); // "protect" the newly created directory from prying eyes } else { // Mmmm, failed; probably already exists then. Oh well. Go flag error. ++$dialogdef['area_path']['errors']; $params['{VALUE}'] = '/areas/' . $areadata_directory; $dialogdef['area_path']['error_messages'][] = t('validate_already_exists', '', $params); $invalid = TRUE; } // 3E -- if there were any errors go redo dialog while keeping data already entered if ($invalid) { if ($areadata_directory_created) { // Only get rid of the directory _we_ created @unlink($areadata_full_path . '/index.html'); @rmdir($areadata_full_path); } // there were errors, show them to the user and do it again foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $this->output->add_message($item['error_messages']); } } $this->output->add_content('<h2>' . t('areamanager_add_area_header', 'admin') . '</h2>'); $this->output->add_content(t('areamanager_add_area_explanation', 'admin')); $href = href($WAS_SCRIPT_NAME, $this->a_param(AREAMANAGER_CHORE_SAVE_NEW)); $this->output->add_content(dialog_quickform($href, $dialogdef)); return; } // 4 -- go save the new area $sort_order = $this->sort_order_new_area(); $now = strftime('%Y-%m-%d %T'); $theme_id = intval($dialogdef['area_theme_id']['value']); $area_title = $dialogdef['area_title']['value']; $fields = array('title' => $area_title, 'is_private' => $dialogdef['area_is_private']['value'] == 1 ? TRUE : FALSE, 'is_active' => TRUE, 'is_default' => FALSE, 'path' => $areadata_directory, 'metadata' => '', 'sort_order' => $sort_order, 'theme_id' => $theme_id, 'ctime' => $now, 'cuser_id' => $USER->user_id, 'mtime' => $now, 'muser_id' => $USER->user_id); // 4A -- store area data $success = TRUE; $new_area_id = db_insert_into_and_get_id('areas', $fields, 'area_id'); if ($new_area_id === FALSE) { if ($areadata_directory_created) { // Only get rid of the directory _we_ created @unlink($areadata_full_path . '/index.html'); @rmdir($areadata_full_path); } logger("areamanager: saving new area failed: " . db_errormessage()); $success = FALSE; } // 4B -- handle theme settings for this area if ($success) { if (!$this->reset_theme_defaults($new_area_id, $theme_id)) { logger("areamanager: saving new area-theme properties failed: " . db_errormessage()); $success = FALSE; } } // 5 -- tell user about results of the operation if ($success) { $params = array('{AREA}' => $new_area_id, '{AREA_FULL_NAME}' => $area_title); $this->output->add_message(t('areamanager_savenew_area_success', 'admin', $params)); logger(sprintf("areamanager: success saving new area '%d' %s with data directory /areas/%s", $new_area_id, $area_title, $areadata_directory)); } else { $this->output->add_message(t('areamanager_savenew_area_failure', 'admin')); } $this->area_overview(); }
/** save a newly added node to the database * * this validate and save the (minimal) data for a new node (section or page). * First we check which button press brought us here; Cancel means we're done, * else we need to validate the user input. This is done by setting up the same * dialog structure as we did when presenting the user with a dialog in the first * place. This ensures that WE determine which fields we need to look for in the * _POST data. (If we simply were to look for fieldnames in the _POST array, we * might be tricked in accepting random fieldnames. By starting from the dialog * structure we make sure that we only look at fields that are part of the dialog; * any other fields are ignored, minimising the risks of the user trying to trick * us.) * * The dialog structure is filled with the data POST'ed by the user and subsequently * the data is validated against the rules in the dialog structure (eg. min length, * min/max numerical values, etc). If one or more fields fail the tests, we redo * the dialog, using the data from _POST as a new starting point. This makes that * the user doesn't lose all other field contents if she makes a minor mistake in * entering data for one field. * * If all data from the dialog appears to be valid, it is copied to an array that * will be used to actually insert a new record into the nodes table. This array * also holds various other fields (not part of the dialog) with sensible default * values. Interesting 'special' fields are 'sort_order' and 'is_hidden' and 'embargo'. * * 'sort_order' is calculated automatically from other sort orders in the same * parent section. There are two ways to do it: always add a node at the end or * the exact opposite: always add a node at the beginning. The jury is still out * on which of the two is the best choice (see comments in the code below). * * 'is_hidden' and 'embargo' are calculated from the dialog field 'node_visibility'. * The latter gives the user three options: 'visible', 'hidden' and 'embargo'. * This translates to the following values for 'is_hidden' and 'embargo' (note * that $now is the current time in the form 'yyyy-mm-dd hh:mm:ss'): * * visible: is_hidden = FALSE, 'embargo' = $now * hidden: is_hidden = TRUE, 'embargo' = $now * embargo: is_hidden = TRUE, 'embargo' = '9999-12-31 23:59:59' * * This makes sure that IF the user wants to create a 'secret' node, ie. under embargo * until some time in the future, the new node is never visible until the user edits * the node to make it visible. However, there is no need to manually add a date/time: * we simply plug in the maximum value for a date/time, which effectively means 'forever'. * * Finally, if the new node is saved, a message about this event is recorded in the logfile (even * for new nodes under embargo). Also, if the node is NOT under embargo, an alert message * is queued. Note that we do NOT send alerts on a page that is created under embargo. * (There is a slight problem with this: once a user edits the node and sets the embargo * to a more realistic value, e.g. next week, there is no practical way to inform the * 'alert-watchers' about that fact: we cannot send an alert at the time that the * embargo date is changed to 'next week' because the node is still under embargo. We don't * have a handy opportunity to send alerts because the embargo date will eventually come * around and the node will become visible automatically, without anyone being alerted to the * fact. Mmmm.... * * @param string $task disinguishes between saving a page or a section * @return void results are returned as output in $this->output * @todo about 'sort_order': do we insert nodes at the end or the beginning of a parent section? * @todo how do we alert users that an embargo date has come around? Do we schedule alerts via cron? * */ function task_save_newnode($task) { global $WAS_SCRIPT_NAME, $USER; $is_page = $task == TASK_SAVE_NEWPAGE ? TRUE : FALSE; // 1 -- do they want to bail out? if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->show_tree(); $this->show_area_menu($this->area_id); return; } // 2 -- validate input $dialogdef = $this->get_dialogdef_add_node($is_page); if (!dialog_validate($dialogdef)) { // there were errors, show them to the user and do it again foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $this->output->add_message($item['error_messages']); } } $href = href($WAS_SCRIPT_NAME, array('job' => JOB_PAGEMANAGER, 'task' => $task)); $this->output->add_content('<h2>' . t($is_page ? 'add_a_page_header' : 'add_a_section_header', 'admin') . '</h2>'); $this->output->add_content(t($is_page ? 'add_page_explanation' : 'add_section_explanation', 'admin')); $this->output->add_content(dialog_quickform($href, $dialogdef)); return; } // 3A -- prepare for storing data into database $now = strftime('%Y-%m-%d %T'); $parent_id = intval($dialogdef['node_parent_id']['value']); switch (intval($dialogdef['node_visibility']['value'])) { case NODE_VISIBILIY_VISIBLE: $embargo = FALSE; $hidden = FALSE; break; case NODE_VISIBILIY_HIDDEN: $embargo = FALSE; $hidden = TRUE; break; case NODE_VISIBILIY_EMBARGO: $embargo = TRUE; $hidden = TRUE; break; default: $embargo = FALSE; $hidden = FALSE; break; // same as visible } $fields = array('area_id' => $this->area_id, 'parent_id' => $parent_id, 'is_page' => $is_page, 'title' => $dialogdef['node_title']['value'], 'link_text' => $dialogdef['node_link_text']['value'], 'is_hidden' => $hidden, 'embargo' => $embargo ? '9999-12-31 23:59:59' : $now, 'sort_order' => $this->calculate_new_sort_order($this->tree, $this->area_id, $parent_id), 'module_id' => $is_page ? intval($dialogdef['node_module_id']['value']) : NULL, 'owner_id' => $USER->user_id, 'ctime' => $now, 'atime' => $now, 'mtime' => $now); // 3B -- actually insert the new node $errors = 0; if (($new_node_id = db_insert_into_and_get_id('nodes', $fields, 'node_id')) === FALSE) { ++$errors; // error retrieving the new node_id, shouldn't happen } if ($errors == 0 && $parent_id == 0) { if (db_update('nodes', array('parent_id' => $new_node_id), array('node_id' => $new_node_id)) === FALSE) { ++$errors; } } if ($errors == 0 && $is_page) { if ($this->module_connect($this->area_id, $new_node_id, $fields['module_id']) === FALSE) { ++$errors; } } // 3C -- maybe do alerts, too if ($errors > 0) { // something went wrong, tell user $message = t('error_adding_node', 'admin'); $this->output->add_message($message); } else { // success! tell the world via an alert if not under embargo $nodes = $this->get_node_id_and_ancestors($parent_id); $nodes[] = $new_node_id; $message = t($is_page ? 'page_added' : 'section_added', 'admin', array('{NODE}' => $new_node_id, '{AREA}' => $this->area_id, '{LINK}' => $fields['link_text'], '{TITLE}' => $fields['title'])); $this->output->add_message($message); $embargo |= is_under_embargo($this->tree, $parent_id); // no alerts if new node or ancestors are embargo'ed logger(sprintf(__CLASS__ . ': area %d: added new %s %d %s (%s)%s', $this->area_id, $is_page ? 'page' : 'section', $new_node_id, $fields['link_text'], $fields['title'], $embargo ? ' (embargo)' : '')); if (!$embargo) { $this->queue_area_node_alert($this->area_id, $nodes, $message, $USER->full_name); } $this->build_cached_tree($this->area_id, TRUE); // TRUE means: force reread of tree // Finally a dirty trick: close the tree and re-open the path to the new node $_SESSION['tree_mode'] = TREE_VIEW_CUSTOM; $_SESSION['expanded_nodes'] = array(); foreach ($nodes as $id) { $_SESSION['expanded_nodes'][$id] = TRUE; } } // 4 -- show tree again (maybe freshly read from database) $this->show_tree(); $this->show_area_menu($this->area_id); }
/** create a few alerts * * * @param array &$messages used to return (error) messages to caller * @param array &$config pertinent information about the site * @param array &$tr translations of demodata texts * @return bool TRUE on success + data entered into database, FALSE on error */ function demodata_alerts(&$messages, &$config, &$tr) { $retval = TRUE; $now = strftime("%Y-%m-%d %T"); $email = $config['user_email']; $alerts = array('webmaster' => array('full_name' => $config['user_full_name'], 'email' => $email, 'cron_interval' => 1440, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_1440_minutes'] . "\n" . $tr['alerts_all_areas'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (" . $config['user_full_name'] . ")\n", 'is_active' => TRUE), 'acackl' => array('full_name' => 'Amelia Cackle', 'email' => $email, 'cron_interval' => 60, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_60_minutes'] . "\n" . $tr['alerts_private_area'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (Amelia Cackle)\n", 'is_active' => TRUE)); foreach ($alerts as $alert => $fields) { if (($alert_id = db_insert_into_and_get_id('alerts', $fields, 'alert_id')) === FALSE) { $messages[] = $tr['error'] . ' ' . db_errormessage(); $retval = FALSE; } $alerts[$alert]['alert_id'] = intval($alert_id); } $alerts_areas_nodes = array('webmaster' => array('alert_id' => $alerts['webmaster']['alert_id'], 'area_id' => 0, 'node_id' => 0, 'flag' => TRUE), 'acackl' => array('alert_id' => $alerts['acackl']['alert_id'], 'area_id' => $config['demo_areas']['private']['area_id'], 'node_id' => 0, 'flag' => TRUE)); foreach ($alerts_areas_nodes as $fields) { if (db_insert_into('alerts_areas_nodes', $fields) === FALSE) { $messages[] = $tr['error'] . ' ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** add a group/capacity and corresponding acl to the database * * @param int $group_id group of interest * @param int $capacity_code the capacity * @param int $sort_order * @return bool TRUE on success, FALSE otherwise */ function add_group_capacity($group_id, $capacity_code, $sort_order) { static $fields_acl = array('permissions_intranet' => ACL_ROLE_NONE, 'permissions_modules' => ACL_ROLE_NONE, 'permissions_jobs' => ACL_ROLE_NONE, 'permissions_nodes' => ACL_ROLE_NONE); // // 1 -- create an acl (with no permissions whatsoever) and remember the new acl_id // $new_acl_id = db_insert_into_and_get_id('acls', $fields_acl, 'acl_id'); if ($new_acl_id === FALSE) { logger(sprintf("%s.%s(): adding new acl for group/capacity '%d/%d' failed: %s", __CLASS__, __FUNCTION__, $group_id, $capacity_code, db_errormessage())); return FALSE; } // // 2 -- subsequently add a new group-capacity record pointing to this new acl // $fields = array('group_id' => intval($group_id), 'capacity_code' => intval($capacity_code), 'sort_order' => intval($sort_order), 'acl_id' => $new_acl_id); if (db_insert_into('groups_capacities', $fields) === FALSE) { logger(sprintf("%s.%s(): adding new record for group/capacity '%d/%d' failed: %s", __CLASS__, __FUNCTION__, $group_id, $capacity_code, db_errormessage())); $retval = db_delete('acls', array('acl_id' => $new_acl_id)); logger(sprintf("%s.%s(): removing freshly created acl '%d': %s", __CLASS__, __FUNCTION__, $new_acl_id, $retval !== FALSE ? 'success' : 'failure: ' . db_errormessage())); return FALSE; } logger(sprintf("%s.%s(): success adding group/capacity '%d/%d' with acl_id='%d'", __CLASS__, __FUNCTION__, $group_id, $capacity_code, $new_acl_id), WLOG_DEBUG); return TRUE; }
/** add demonstration data to the system * * this routine adds to the existing set of demonstration data as specified * in $config. Here we add a few nodes as follows: * * 'snapshots0': a section containing one page connected to the snapshots_module * 'snapshots1': a page in section 'snapshots0' acting as an example set of snapshots * * The section 'snapshots0' is added at the bottom of the demo-section 'news' * Maybe not the best place, but at least we don't add yet another top level * menu item. * * Note * If the module is installed via the Install Wizard, this routine is * called. However, if a module is installed as an additional module * after installation, the {$module}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * $config['demo_string'] => array with demo strings from /program/install/languages/LL/demodata.php * $config['demo_replace'] => array with search/replace pairs to 'jazz up' the demo strings * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. Note that we add our own additions to the array * $config so other modules and themes can determine the correct status quo w.r.t. the * demodata nodes etc. * * @param array &$messages collects the (error) messages * @param int $module_id the key for this module in the modules table * @param array $configuration pertinent data for the new website + demodata foundation * @param array $manifest a copy of the manifest for this module * @return bool TRUE on success + output via $messages, FALSE otherwise */ function snapshots_demodata(&$messages, $module_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 0 -- get hold of the module-specific translations in $string[] $string = array(); $language_key = $config['language_key']; $filename = dirname(__FILE__) . '/languages/' . $language_key . '/snapshots.php'; if (!file_exists($filename)) { $filename = dirname(__FILE__) . '/languages/en/snapshots.php'; } @(include $filename); if (empty($string)) { $messages[] = 'Internal error: no translations in ' . $filename; return FALSE; } // 1A -- prepare for addition of a few nodes $sort_order = 0; $parent_id = $config['demo_nodes']['news']['node_id']; foreach ($config['demo_nodes'] as $node => $fields) { if ($fields['parent_id'] == $parent_id && $fields['node_id'] != $parent_id) { $sort_order = max($sort_order, $fields['sort_order']); } } $sort_order += 10; // place the snapshots-section at the end of the parent section $nodes = array('snapshots0' => array('parent_id' => $parent_id, 'is_page' => FALSE, 'title' => strtr($string['snapshots0_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots0_link_text'], $config['demo_replace']), 'sort_order' => $sort_order), 'snapshots1' => array('parent_id' => 0, 'is_page' => TRUE, 'is_default' => TRUE, 'title' => strtr($string['snapshots1_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots1_link_text'], $config['demo_replace']), 'sort_order' => 10, 'module_id' => $module_id, 'style' => "div.thumbnail_image a:hover img { border: 5px solid #00FF00; }\n")); // 1B -- actually add the necessary nodes $now = strftime('%Y-%m-%d %T'); $user_id = $config['user_id']; $area_id = $config['demo_areas']['public']['area_id']; foreach ($nodes as $node => $fields) { $fields['area_id'] = $area_id; $fields['ctime'] = $now; $fields['mtime'] = $now; $fields['atime'] = $now; $fields['owner_id'] = $user_id; if ($fields['parent_id'] == 0) { $fields['parent_id'] = $config['demo_nodes']['snapshots0']['node_id']; // plug in real node_id of 'our' section } if (($node_id = db_insert_into_and_get_id('nodes', $fields, 'node_id')) === FALSE) { $messages[] = $config['demo_string']['error'] . db_errormessage(); $retval = FALSE; } $node_id = intval($node_id); $fields['node_id'] = $node_id; $config['demo_nodes'][$node] = $fields; } // 2 -- Simulate a series of snapshots in the exemplum area data storage // 2A -- copy from module demodata directory to exemplum path $pictures = array("allium.jpg", "calendula.jpg", "cynara.jpg", "lagos.jpg", "lavandula.jpg", "mentha.jpg", "nepeta.jpg", "ocimum.jpg", "origanum.jpg", "petroselinum.jpg", "salvia.jpg", "thymus.jpg"); $thumb_prefix = 'zz_thumb_'; $path_snapshots = '/areas/' . $config['demo_areas']['public']['path'] . '/snapshots'; // relative to $datadir $fullpath_source = dirname(__FILE__) . '/install/demodata'; $fullpath_target = $config['datadir'] . $path_snapshots; if (@mkdir($fullpath_target, 0700) === FALSE) { $messages[] = $config['demo_string']['error'] . "mkdir('{$fullpath_target}')"; $retval = FALSE; } else { @touch($fullpath_target . '/index.html'); // try to "protect" directory foreach ($pictures as $picture) { $filenames = array($picture, $thumb_prefix . $picture); foreach ($filenames as $filename) { if (!@copy($fullpath_source . '/' . $filename, $fullpath_target . '/' . $filename)) { $messages[] = $config['demo_string']['error'] . "copy('{$path_snapshots}/{$filename}')"; $retval = FALSE; } } } } $fields = array('node_id' => $config['demo_nodes']['snapshots1']['node_id'], 'header' => strtr($string['snapshots1_header'], $config['demo_replace']), 'introduction' => strtr($string['snapshots1_introduction'], $config['demo_replace']), 'snapshots_path' => $path_snapshots, 'variant' => 1, 'dimension' => 512, 'ctime' => $now, 'cuser_id' => $user_id, 'mtime' => $now, 'muser_id' => $user_id); if (db_insert_into('snapshots', $fields) === FALSE) { $messages[] = $config['demo_string']['error'] . db_errormessage(); $retval = FALSE; } return $retval; }
/** save a new user to the database * * this saves a new user to the database. This involves at least two tables: * a record in the users table with basic information and also a record with * access control in the acls table. * * @todo maybe we should find a more elegant way to check a field for uniqueness * @todo shouldn't we end with the edit-user dialog rather than the users overview? * that might make more sense... * @return data saved to the database, directory created, output created via users_overview() * @uses $CFG * @uses $WAS_SCRIPT_NAME */ function user_savenew() { global $WAS_SCRIPT_NAME, $CFG; // // 1 -- bail out if the user pressed cancel button // if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->users_overview(); return; } // // 2 -- validate the data // $invalid = FALSE; $dialogdef = $this->get_dialogdef_add_user(); // // 2A -- check for generic errors (string too short, number too small, etc) if (!dialog_validate($dialogdef)) { $invalid = TRUE; } // 2B -- additional check: unique username $fname = $this->get_fname($dialogdef['username']); $params = array('{FIELD}' => $fname); $username = $dialogdef['username']['value']; $record = db_select_single_record('users', 'user_id', array('username' => $username)); if ($record !== FALSE) { // Oops, a record with that username already exists. Go flag error ++$dialogdef['username']['errors']; $dialogdef['username']['error_messages'][] = t('validate_not_unique', '', $params); $invalid = TRUE; } // 2C -- additional check: unique userdata subdirectory relative to {$CFG->datadir}/users/ $userdata_directory = strtolower(sanitise_filename($username)); $userdata_full_path = $CFG->datadir . '/users/' . $userdata_directory; $userdata_directory_created = @mkdir($userdata_full_path, 0700); if ($userdata_directory_created) { @touch($userdata_full_path . '/index.html'); // "protect" the newly created directory from prying eyes } else { // Mmmm, failed; probably already exists then. Oh well. Go flag error. ++$dialogdef['username']['errors']; $params['{VALUE}'] = '/users/' . $userdata_directory; $dialogdef['username']['error_messages'][] = t('validate_already_exists', '', $params); $invalid = TRUE; } // 2D -- additional check: valid password $password1 = $dialogdef['user_password1']['value']; $password2 = $dialogdef['user_password2']['value']; if (!empty($password1) || !empty($password2)) { if ($password1 != $password2) { $params = array('{FIELD1}' => $this->get_fname($dialogdef['user_password1']), '{FIELD2}' => $this->get_fname($dialogdef['user_password2'])); ++$dialogdef['user_password1']['errors']; ++$dialogdef['user_password2']['errors']; $dialogdef['user_password1']['error_messages'][] = t('validate_different_passwords', '', $params); $dialogdef['user_password1']['value'] = ''; $dialogdef['user_password2']['value'] = ''; $invalid = TRUE; } elseif (!acceptable_new_password($password1, $password2)) { $params = array('{MIN_LENGTH}' => MINIMUM_PASSWORD_LENGTH, '{MIN_LOWER}' => MINIMUM_PASSWORD_LOWERCASE, '{MIN_UPPER}' => MINIMUM_PASSWORD_UPPERCASE, '{MIN_DIGIT}' => MINIMUM_PASSWORD_DIGITS, '{FIELD}' => $this->get_fname($dialogdef['user_password1'])); ++$dialogdef['user_password1']['errors']; $dialogdef['user_password1']['error_messages'][] = t('validate_bad_password', '', $params); ++$dialogdef['user_password2']['errors']; $dialogdef['user_password1']['value'] = ''; $dialogdef['user_password2']['value'] = ''; $invalid = TRUE; } } // 2E -- if there were any errors go redo dialog while keeping data already entered if ($invalid) { if ($userdata_directory_created) { // Get rid of the directory _we_ created @unlink($userdata_full_path . '/index.html'); @rmdir($userdata_full_path); } // show errors messages foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $this->output->add_message($item['error_messages']); } } $this->output->add_content('<h2>' . t('usermanager_add_user_header', 'admin') . '</h2>'); $this->output->add_content(t('usermanager_add_user_explanation', 'admin')); $href = href($WAS_SCRIPT_NAME, $this->a_params(TASK_USER_SAVE_NEW)); $this->output->add_content(dialog_quickform($href, $dialogdef)); return; } // // 3 -- store the data // // At this point we have a validated new user dialog in our hands // We now need to convert the data from the dialog to sensible // values for the database fields and store the data. // Note that the userdata directory already exists at this point $fields_acl = array('permissions_intranet' => ACL_ROLE_NONE, 'permissions_modules' => ACL_ROLE_NONE, 'permissions_jobs' => ACL_ROLE_NONE, 'permissions_nodes' => ACL_ROLE_NONE); // // 3A -- create an acl (with no permissions whatsoever) and remember the new acl_id // $errors = 0; $new_acl_id = db_insert_into_and_get_id('acls', $fields_acl, 'acl_id'); if ($new_acl_id === FALSE) { logger(sprintf("user_savenew(): adding new acl for new user failed: %s", db_errormessage())); ++$errors; } else { // // 3B -- subsequently add a new user and remember the new user_id // $new_username = $dialogdef['username']['value']; $new_user_fullname = $dialogdef['user_fullname']['value']; $new_salt = password_salt(); $fields = array('username' => $new_username, 'salt' => $new_salt, 'password_hash' => password_hash($new_salt, $dialogdef['user_password1']['value']), 'bypass_mode' => FALSE, 'bypass_hash' => NULL, 'bypass_expiry' => NULL, 'full_name' => $new_user_fullname, 'email' => $dialogdef['user_email']['value'], 'is_active' => $dialogdef['user_is_active']['value'] == 1 ? TRUE : FALSE, 'redirect' => '', 'language_key' => $CFG->language_key, 'path' => $userdata_directory, 'acl_id' => $new_acl_id, 'editor' => $CFG->editor, 'skin' => 'base'); $new_user_id = db_insert_into_and_get_id('users', $fields, 'user_id'); if ($new_user_id === FALSE) { logger(sprintf("usermanager: saving new user %s (%s) failed: %s" . $new_username, $new_user_fullname, db_errormessage())); ++$errors; } } if ($errors > 0) { if ($userdata_directory_created) { // Get rid of the directory _we_ created @unlink($userdata_full_path . '/index.html'); @rmdir($userdata_full_path); } $this->output->add_message(t('usermanager_savenew_user_failure', 'admin')); } else { $params = array('{USERNAME}' => $new_username, '{FULL_NAME}' => $new_user_fullname); $this->output->add_message(t('usermanager_savenew_user_success', 'admin', $params)); logger(sprintf("usermanager: success saving new user '%d' %s (%s) and datadir /users/%s", $new_user_id, $new_username, $new_user_fullname, $userdata_directory)); } $this->users_overview(); }