/** 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();
 }
 /** create a new subdirectory
  *
  * This routine either shows a dialog where the user can specify the name of a new
  * directory to add OR processes the dialog.
  *
  * In case of directory name too short, already exists, etc. the user is
  * returned to the dialog to try again. If all goes well the new directory
  * is created and at the same time the empty file 'index.html' is created
  * to "protect" the directory from prying eyes.
  *
  * @return void output returned via $this->output
  */
 function task_add_directory()
 {
     global $WAS_SCRIPT_NAME, $CFG;
     // 1A -- bail out if user pressed cancel button
     if (isset($_POST['button_cancel'])) {
         $this->output->add_message(t('cancelled', 'admin'));
         $this->task_list_directory();
         return;
     }
     // 1B -- Check validity of working directory, maybe bail out
     $newdir = get_parameter_string(PARAM_PATH, $this->current_directory);
     if (($path = $this->valid_path($newdir)) === FALSE) {
         $this->output->add_message(t('invalid_path', 'admin', array('{PATH}' => htmlspecialchars($newdir))));
         $this->task_list_directory();
         return;
     }
     $this->current_directory = $path;
     // this is where we will create the new subdirectory
     // 2 -- prepare dialog (either to show it or to validate it)
     $dialogdef = array('subdirectory' => array('type' => F_ALPHANUMERIC, 'name' => 'subdirectory', 'minlength' => 1, 'maxlength' => 240, 'columns' => 30, 'label' => t('filemanager_add_subdirectory_label', 'admin'), 'title' => t('filemanager_add_subdirectory_title', 'admin'), 'value' => ''), 'button_save' => dialog_buttondef(BUTTON_SAVE), 'button_cancel' => dialog_buttondef(BUTTON_CANCEL));
     $a_params = array('job' => $this->job, 'task' => TASK_ADD_DIRECTORY, PARAM_PATH => $path);
     $href = href($WAS_SCRIPT_NAME, $a_params);
     // 3 -- show dialog or validate + process?
     if (!isset($_POST['subdirectory'])) {
         $this->output->add_content('<h2>' . t('filemanager_add_subdirectory_header', 'admin') . '</h2>');
         $this->output->add_content(t('filemanager_add_subdirectory_explanation', 'admin'));
         $this->output->add_content(dialog_quickform($href, $dialogdef));
         $this->show_breadcrumbs($path);
         $this->show_menu($path);
         return;
     }
     // 4 -- validate user input and maybe create directory
     // 4A -- check for generic errors
     $invalid = FALSE;
     if (!dialog_validate($dialogdef)) {
         $invalid = TRUE;
     }
     // 4B -- check for additional errors: sane filename
     $subdirectory = $dialogdef['subdirectory']['value'];
     $sanitised_subdirectory = sanitise_filename($subdirectory);
     if ($subdirectory != $sanitised_subdirectory || substr($sanitised_subdirectory, 0, strlen(THUMBNAIL_PREFIX)) == THUMBNAIL_PREFIX) {
         ++$dialogdef['subdirectory']['errors'];
         $params = array('{FIELD}' => str_replace('~', '', $dialogdef['subdirectory']['label']), '{VALUE}' => htmlspecialchars($subdirectory));
         $dialogdef['subdirectory']['error_messages'][] = t('validate_bad_filename', '', $params);
         $invalid = TRUE;
     }
     // 4C -- check for additional errors: directory should not exist already
     $subdirectory_full_path = $CFG->datadir . $path . '/' . $sanitised_subdirectory;
     if (file_exists($subdirectory_full_path)) {
         ++$dialogdef['subdirectory']['errors'];
         $params = array('{FIELD}' => str_replace('~', '', $dialogdef['subdirectory']['label']), '{VALUE}' => $this->vpath($path) . '/' . $sanitised_subdirectory);
         $dialogdef['subdirectory']['error_messages'][] = t('validate_already_exists', '', $params);
         $invalid = TRUE;
     }
     // 4D -- redo dialog if there were errors
     if ($invalid) {
         // shortcut: only the subdirectory field can (and does) yield errors
         $this->output->add_message($dialogdef['subdirectory']['error_messages']);
         $dialogdef['subdirectory']['value'] = $sanitised_subdirectory;
         $this->output->add_content('<h2>' . t('filemanager_add_subdirectory_header', 'admin') . '</h2>');
         $this->output->add_content(t('filemanager_add_subdirectory_explanation', 'admin'));
         $this->output->add_content(dialog_quickform($href, $dialogdef));
         $this->show_breadcrumbs($path);
         // note that we do NOT display the menu here; let the user concentrate (or press Cancel) this time
         return;
     }
     // 5 -- all set, go create subdir
     $params = array('{PATH}' => htmlspecialchars($this->vpath($path)), '{DIRECTORY}' => htmlspecialchars($sanitised_subdirectory));
     if (@mkdir($subdirectory_full_path, 0700)) {
         @touch($subdirectory_full_path . '/index.html');
         // "protect" the newly created directory from prying eyes
         $this->output->add_message(t('filemanager_add_subdirectory_success', 'admin', $params));
         logger(sprintf('%s.%s(): success with mkdir %s', __CLASS__, __FUNCTION__, $path . '/' . $subdirectory), WLOG_DEBUG);
     } else {
         $this->output->add_message(t('filemanager_add_subdirectory_failure', 'admin', $params));
         logger(sprintf('%s.%s(): cannot mkdir %s', __CLASS__, __FUNCTION__, $path . '/' . $subdirectory));
     }
     $this->task_list_directory();
 }
Exemplo n.º 3
0
function make_serialize_filename($token_or_settings_filename)
{
    return FUPS_DATADIR . sanitise_filename($token_or_settings_filename) . '.serialize.txt';
}
 /** save a new group to the database
  *
  * this saves a new group to the database. This quite a complex task because of
  * the number of tables involved.
  *
  * First we have the table 'groups' which stores the basic group information.
  * Then there is the table 'groups_capacities'. For every combination of group
  * and capacity requested by the user a record must be added to this table.
  * Then there is also a separate acl for every group_capacity, so there.
  * 
  * The strategy should be something like this.
  * new_group_id = insert_new_group_into_groups()
  * for all GROUPMANAGER_MAX_CAPACITIES do
  *     if capacity != CAPACITY_NONE && capacity_not_added_yet()
  *         prepare_new_acl_record();
  *         new_acl_id = insert_new_acl_in_acls();
  *         prepare_new_groups_capacities_record();
  *         insert_new_group_capacity_in_table()
  *   
  * @todo maybe we should find a more elegant way to check a field for uniqueness
  * @todo should we delete the datadirectory if something goes wrong?
  * @return data saved to the database, output created via groups_overview()
  */
 function group_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->groups_overview();
         return;
     }
     //
     // 2 -- validate the data
     //
     $invalid = FALSE;
     $dialogdef = $this->get_dialogdef_add_group();
     // 2A -- check for generic errors (string too short, number too small, etc)
     if (!dialog_validate($dialogdef)) {
         $invalid = TRUE;
     }
     // 2B -- check out the groupname: this field should be unique
     $groupname = $dialogdef['group_name']['value'];
     $fname = isset($dialogdef['group_name']['label']) ? $dialogdef['group_name']['label'] : 'group_name';
     $params = array('{FIELD}' => str_replace('~', '', $fname));
     if (db_select_single_record('groups', 'group_id', array('groupname' => $groupname)) !== FALSE) {
         // Oops, a record with that groupname already exists. Go flag error
         ++$dialogdef['group_name']['errors'];
         $dialogdef['group_name']['error_messages'][] = t('validate_not_unique', '', $params);
         $invalid = TRUE;
     }
     // 2C -- additional check: unique groupdata subdirectory relative to {$CFG->datadir}/groups/
     $groupdata_directory = strtolower(sanitise_filename($groupname));
     $groupdata_full_path = $CFG->datadir . '/groups/' . $groupdata_directory;
     $groupdata_directory_created = @mkdir($groupdata_full_path, 0700);
     if ($groupdata_directory_created) {
         @touch($groupdata_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['group_name']['errors'];
         $params['{VALUE}'] = '/groups/' . $groupdata_directory;
         $dialogdef['group_name']['error_messages'][] = t('validate_already_exists', '', $params);
         $invalid = TRUE;
     }
     // 2D -- if there were any errors go redo dialog while keeping data already entered
     if ($invalid) {
         if ($groupdata_directory_created) {
             // Only get rid of the directory _we_ created
             @unlink($groupdata_full_path . '/index.html');
             @rmdir($groupdata_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('groupmanager_add_group_header', 'admin') . '</h2>');
         $this->output->add_content(t('groupmanager_add_group_explanation', 'admin'));
         $href = href($WAS_SCRIPT_NAME, $this->a_params(TASK_GROUP_SAVE_NEW));
         // $dialogdef = $this->get_dialogdef_add_group();
         $this->output->add_content(dialog_quickform($href, $dialogdef));
         return;
     }
     //
     // 3 -- store the data
     //
     // At this point we have a validated new group dialog in our hands
     // We now need to convert the data from the dialog to sensible
     // fields and store the data.
     //
     // 3A -- insert new group record and remember the new group_id
     $group_fullname = $dialogdef['group_fullname']['value'];
     $fields = array('groupname' => $groupname, 'full_name' => $group_fullname, 'is_active' => $dialogdef['group_is_active']['value'] == 1 ? TRUE : FALSE, 'path' => $groupdata_directory);
     if (($new_group_id = db_insert_into_and_get_id('groups', $fields, 'group_id')) === FALSE) {
         logger(sprintf("%s.%s(): saving new group '%s' failed: %s", __CLASS__, __FUNCTION__, $groupname, db_errormessage()));
         if ($groupdata_directory_created) {
             // Only get rid of the directory _we_ created
             @unlink($groupdata_full_path . '/index.html');
             @rmdir($groupdata_full_path);
         }
         $this->output->add_message(t('groupmanager_savenew_group_failure', 'admin'));
         $this->groups_overview();
         return;
     }
     // 3B -- create 0, 1 or more group/capacities
     $capacity_sort_order = 0;
     for ($i = 1; $i <= GROUPMANAGER_MAX_CAPACITIES; ++$i) {
         $k = 'group_capacity_' . $i;
         if (($capacity_code = intval($dialogdef[$k]['value'])) != CAPACITY_NONE) {
             if ($this->add_group_capacity($new_group_id, $capacity_code, ++$capacity_sort_order) === FALSE) {
                 if ($groupdata_directory_created) {
                     // Only get rid of the directory _we_ created
                     @unlink($groupdata_full_path . '/index.html');
                     @rmdir($groupdata_full_path);
                 }
                 $this->output->add_message(t('groupmanager_savenew_group_failure', 'admin'));
                 $this->groups_overview();
                 return;
             }
         }
     }
     // 4 -- tell user about success
     $params = array('{GROUP}' => $groupname, '{GROUP_FULL_NAME}' => $group_fullname);
     $this->output->add_message(t('groupmanager_savenew_group_success', 'admin', $params));
     logger(sprintf("%s.%s(): success saving new group '%d' %s (%s) and datadir /groups/%s", __CLASS__, __FUNCTION__, $new_group_id, $groupname, $group_fullname, $groupdata_directory));
     $this->groups_overview();
 }
 /** 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();
 }
 /** save the newly added language to the database
  *
  * This saves the essential information of a new language to the database,
  * using sensible defaults for the other fields. Also, a data directory
  * is created in $CFG->datadir
  *
  * If something goes wrong, the user can redo the dialog, otherwise we
  * return to the languages overview, with the newly added language in the
  * list, too.
  *
  * Apart from the standard checks the following checks are done:
  *  - the language key should be an acceptable directory name
  *  - the language key should be lowercase
  *  - the language key should not exist already (in $this->languages)
  *  - the directory should not yet exist
  *  - the directory must be created here and now
  *
  * @return void results are returned as output in $this->output
  * @uses $WAS_SCRIPT_NAME
  * @uses $CFG
  * @uses $USER
  * @uses $LANGUAGE
  */
 function language_savenew()
 {
     global $WAS_SCRIPT_NAME, $USER, $CFG, $LANGUAGE;
     // 1 -- bail out if user pressed cancel button
     if (isset($_POST['button_cancel'])) {
         $this->output->add_message(t('cancelled', 'admin'));
         $this->languages_overview();
         return;
     }
     // 2 -- validate the data; check for generic errors (string too short, number too small, etc)
     $dialogdef = $this->get_dialogdef_language();
     $invalid = dialog_validate($dialogdef) ? FALSE : TRUE;
     // 3 -- additional validation & massaging of the language key
     $fname = isset($dialogdef['language_key']['label']) ? $dialogdef['language_key']['label'] : 'language_key';
     $params = array('{FIELD}' => str_replace('~', '', $fname));
     // 3A -- additional check: the language key doubles as a directory name AND should be lowercase
     $path = $dialogdef['language_key']['value'];
     $languagedata_directory = strtolower(sanitise_filename($path));
     if ($path != $languagedata_directory) {
         // User probably entered a few 'illegal' characters. This is no good
         $dialogdef['language_key']['value'] = $languagedata_directory;
         // 'Help' user with a better proposition?
         ++$dialogdef['language_key']['errors'];
         $params['{VALUE}'] = htmlspecialchars($path);
         $dialogdef['language_key']['error_messages'][] = t('validate_bad_filename', '', $params);
         $invalid = TRUE;
     }
     // 3B -- additional check: unique language key name entered
     if (isset($this->languages[$languagedata_directory])) {
         // Oops, already exists
         ++$dialogdef['language_key']['errors'];
         $params['{VALUE}'] = $languagedata_directory;
         $dialogdef['language_key']['error_messages'][] = t('validate_not_unique', '', $params);
         $invalid = TRUE;
     }
     // 3C -- additional check: can we create said directory?
     $languagedata_full_path = $CFG->datadir . '/languages/' . $languagedata_directory;
     $languagedata_directory_created = @mkdir($languagedata_full_path, 0700);
     if ($languagedata_directory_created) {
         @touch($languagedata_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['language_key']['errors'];
         $params['{VALUE}'] = '/languages/' . $languagedata_directory;
         $dialogdef['language_key']['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 ($languagedata_directory_created) {
             // Only get rid of the directory _we_ created
             @unlink($languagedata_full_path . '/index.html');
             @rmdir($languagedata_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('translatetool_add_language_header', 'admin') . '</h2>');
         $this->output->add_content(t('translatetool_add_language_explanation', 'admin'));
         $href = href($WAS_SCRIPT_NAME, $this->a_param(TRANSLATETOOL_CHORE_LANGUAGE_SAVE_NEW));
         $this->output->add_content(dialog_quickform($href, $dialogdef));
         return;
     }
     // 4 -- go save the new language
     $language_key = $dialogdef['language_key']['value'];
     $language_name = $dialogdef['language_name']['value'];
     $parent_key = $dialogdef['parent_language_key']['value'] == '--' ? NULL : $dialogdef['parent_language_key']['value'];
     $is_active = $dialogdef['language_is_active']['value'] == '1' ? TRUE : FALSE;
     $fields = array('language_key' => $language_key, 'parent_language_key' => $parent_key, 'language_name' => $language_name, 'version' => 0, 'manifest' => '', 'is_core' => FALSE, 'is_active' => $is_active, 'dialect_in_database' => FALSE, 'dialect_in_file' => FALSE);
     if (db_insert_into('languages', $fields) === FALSE) {
         if ($languagedata_directory_created) {
             // Only get rid of the file/directory _we_ created
             @unlink($languagedata_full_path . '/index.html');
             @rmdir($languagedata_full_path);
         }
         logger(sprintf('%s.%s(): saving new language \'%s\' failed: %s', __CLASS__, __FUNCTION__, htmlspecialchars($language_key), db_errormessage()));
         $this->output->add_message(t('translatetool_language_savenew_failure', 'admin'));
     } else {
         $params = array('{LANGUAGE_KEY}' => $language_key, '{LANGUAGE_NAME}' => $language_name);
         $this->output->add_message(t('translatetool_language_savenew_success', 'admin', $params));
         logger(sprintf("%s.%s(): success saving new language '%s' (%s) with data directory /languages/%s", __CLASS__, __FUNCTION__, $language_name, $language_key, $languagedata_directory));
         $this->languages = $LANGUAGE->retrieve_languages(TRUE);
         // TRUE means force reread from database after add
     }
     $this->languages_overview();
 }