/** * Updates the (single) administration menu. * * @param array $info */ function ft_update_admin_menu($info) { global $g_table_prefix, $g_pages, $g_root_url, $LANG; $menu_id = $info["menu_id"]; $account_id = $info["account_id"]; $sortable_id = $info["sortable_id"]; $sortable_rows = explode(",", $info["{$sortable_id}_sortable__rows"]); $sortable_new_groups = explode(",", $info["{$sortable_id}_sortable__new_groups"]); $menu_items = array(); foreach ($sortable_rows as $i) { // if this row doesn't have a page identifier, just ignore it if (!isset($info["page_identifier_{$i}"]) || empty($info["page_identifier_{$i}"])) { continue; } $page_identifier = $info["page_identifier_{$i}"]; $display_text = ft_sanitize($info["display_text_{$i}"]); $custom_options = isset($info["custom_options_{$i}"]) ? ft_sanitize($info["custom_options_{$i}"]) : ""; $is_submenu = isset($info["submenu_{$i}"]) ? "yes" : "no"; // construct the URL for this menu item $url = ft_construct_page_url($page_identifier, $custom_options); $menu_items[] = array("url" => $url, "page_identifier" => $page_identifier, "display_text" => $display_text, "custom_options" => $custom_options, "is_submenu" => $is_submenu, "is_new_sort_group" => in_array($i, $sortable_new_groups) ? "yes" : "no"); } mysql_query("DELETE FROM {$g_table_prefix}menu_items WHERE menu_id = {$menu_id}"); $order = 1; foreach ($menu_items as $hash) { $url = $hash["url"]; $page_identifier = $hash["page_identifier"]; $display_text = $hash["display_text"]; $custom_options = $hash["custom_options"]; $is_submenu = $hash["is_submenu"]; $is_new_sort_group = $hash["is_new_sort_group"]; mysql_query("\r\n INSERT INTO {$g_table_prefix}menu_items (menu_id, display_text, page_identifier, custom_options, url,\r\n is_submenu, list_order, is_new_sort_group)\r\n VALUES ({$menu_id}, '{$display_text}', '{$page_identifier}', '{$custom_options}', '{$url}', '{$is_submenu}',\r\n {$order}, '{$is_new_sort_group}')\r\n "); $order++; } // update the administrator's cache, so the menu automatically updates ft_cache_account_menu($account_id); $success = true; $message = $LANG["notify_admin_menu_updated"]; extract(ft_process_hook_calls("end", compact("success", "message", "info"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }
/** * The login procedure for both administrators and clients in. If successful, redirects them to the * appropriate page, otherwise returns an error. * * @param array $infohash This parameter should be a hash (e.g. $_POST or $_GET) containing both * "username" and "password" keys, containing that information for the user trying * to log in. * @param boolean $login_as_client [optional] This optional parameter is used by administrators * to log in as a particular client, allowing them to view how the account looks, * even if it is disabled. * @return string error message string (if error occurs). Otherwise it redirects the user to the * appropriate page, based on account type. */ function ft_login($infohash, $login_as_client = false) { global $g_root_url, $g_table_prefix, $LANG; $settings = ft_get_settings("", "core"); $username = strip_tags($infohash["username"]); $username = ft_sanitize($username); $password = isset($infohash["password"]) ? ft_sanitize($infohash["password"]) : ""; $password = strip_tags($password); // extract info about this user's account $query = mysql_query("\r\n SELECT account_id, account_type, account_status, password, temp_reset_password, login_page\r\n FROM {$g_table_prefix}accounts\r\n WHERE username = '******'\r\n "); $account_info = mysql_fetch_assoc($query); $has_temp_reset_password = empty($account_info["temp_reset_password"]) ? false : true; // error check user login info if (!$login_as_client) { if (empty($password)) { return $LANG["validation_no_password"]; } if ($account_info["account_status"] == "disabled") { return $LANG["validation_account_disabled"]; } if ($account_info["account_status"] == "pending") { return $LANG["validation_account_pending"]; } if (empty($username)) { return $LANG["validation_account_not_recognized"]; } $password_correct = md5(md5($password)) == $account_info["password"]; $temp_password_correct = md5(md5($password)) == $account_info["temp_reset_password"]; if (!$password_correct && !$temp_password_correct) { // if this is a client account and the administrator has enabled the maximum failed login attempts feature, // keep track of the count $account_settings = ft_get_account_settings($account_info["account_id"]); // stores the MAXIMUM number of failed attempts permitted, before the account gets disabled. If the value // is empty in either the user account or for the default value, that means the administrator doesn't want // to track the failed login attempts $max_failed_login_attempts = isset($account_settings["max_failed_login_attempts"]) ? $account_settings["max_failed_login_attempts"] : $settings["default_max_failed_login_attempts"]; if ($account_info["account_type"] == "client" && !empty($max_failed_login_attempts)) { $num_failed_login_attempts = isset($account_settings["num_failed_login_attempts"]) && !empty($account_settings["num_failed_login_attempts"]) ? $account_settings["num_failed_login_attempts"] : 0; $num_failed_login_attempts++; if ($num_failed_login_attempts >= $max_failed_login_attempts) { ft_disable_client($account_info["account_id"]); ft_set_account_settings($account_info["account_id"], array("num_failed_login_attempts" => 0)); return $LANG["validation_account_disabled"]; } else { ft_set_account_settings($account_info["account_id"], array("num_failed_login_attempts" => $num_failed_login_attempts)); } } return $LANG["validation_wrong_password"]; } } extract(ft_process_hook_calls("main", compact("account_info"), array("account_info")), EXTR_OVERWRITE); // all checks out. Log them in, after populating sessions $_SESSION["ft"]["settings"] = $settings; $_SESSION["ft"]["account"] = ft_get_account_info($account_info["account_id"]); $_SESSION["ft"]["account"]["is_logged_in"] = true; // this is deliberate. $_SESSION["ft"]["account"]["password"] = md5(md5($password)); ft_cache_account_menu($account_info["account_id"]); // if this is an administrator, ensure the API version is up to date if ($account_info["account_type"] == "admin") { ft_update_api_version(); } else { ft_set_account_settings($account_info["account_id"], array("num_failed_login_attempts" => 0)); } // for clients, store the forms & form Views that they are allowed to access if ($account_info["account_type"] == "client") { $_SESSION["ft"]["permissions"] = ft_get_client_form_views($account_info["account_id"]); } // if the user just logged in with a temporary password, append some args to pass to the login page // so that they will be prompted to changing it upon login $reset_password_args = array(); if (md5(md5($password)) == $account_info["temp_reset_password"]) { $reset_password_args["message"] = "change_temp_password"; } // redirect the user to whatever login page they specified in their settings $login_url = ft_construct_page_url($account_info["login_page"], "", $reset_password_args); $login_url = "{$g_root_url}{$login_url}"; if (!$login_as_client) { ft_update_last_logged_in($account_info["account_id"]); } session_write_close(); header("Location: {$login_url}"); exit; }
/** * The uninstallation script for the Pages module. This basically does a little clean up * on the database to ensure it doesn't leave any footprints. Namely: * - the module_pages table is removed * - any references in client or admin menus to any Pages are removed * - if the default login page for any user account was a Page, it attempts to reset it to * a likely login page (the Forms page for both). * * The message returned by the script informs the user the module has been uninstalled, and warns them * that any references to any of the Pages in the user accounts has been removed. * * @return array [0] T/F, [1] success message */ function pages__uninstall($module_id) { global $g_table_prefix, $LANG; $pages = mysql_query("SELECT page_id FROM {$g_table_prefix}module_pages"); while ($row = mysql_fetch_assoc($pages)) { $page_id = $row["page_id"]; mysql_query("DELETE FROM {$g_table_prefix}menu_items WHERE page_identifier = 'page_{$page_id}"); } // delete the Pages module tables @mysql_query("DROP TABLE {$g_table_prefix}module_pages"); @mysql_query("DROP TABLE {$g_table_prefix}module_pages_clients"); // update sessions in case a Page was in the administrator's account menu ft_cache_account_menu($account_id = $_SESSION["ft"]["account"]["account_id"]); mysql_query("DELETE FROM {$g_table_prefix}settings WHERE module = 'pages'"); return array(true, $LANG["pages"]["notify_module_uninstalled"]); }
/** * This function lets you log a client or administrator in programmatically. By default, it logs the user in * and redirects them to whatever login page they specified in their user account. However, you can override * this in two ways: either specify a custom URL where they should be directed to, or avoid redirecting at * all. If you choose the latter, make sure you've initiated SESSIONS on the calling page - otherwise the * login account information (needed to be stored in sessions) is lost. * * @param array $info a hash with the following possible parameters: * "username" - the username * "password" - the password * "auto_redirect_after_login" - (boolean, defaulted to false) determines whether or not the user should * be automatically redirected to a URL after a successful login. * "login_url" - the URL to redirect to (if desired). If this isn't set, but auto_redirect_after_login IS, * it will log the user in normally, to whatever login page they've specified in their account. */ function ft_api_login($info) { global $g_root_url, $g_table_prefix, $LANG, $g_api_debug; $username = ft_sanitize($info["username"]); $password = isset($info["password"]) ? ft_sanitize($info["password"]) : ""; // extract info about this user's account $query = mysql_query("\n SELECT account_id, account_type, account_status, password, login_page\n FROM {$g_table_prefix}accounts\n WHERE username = '******'\n "); $account_info = mysql_fetch_assoc($query); if (empty($password)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 1000, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 1000); } } if (empty($account_info)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 1004, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 1004); } } if ($account_info["account_status"] == "disabled") { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 1001, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 1001); } } if ($account_info["account_status"] == "pending") { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 1002, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 1002); } } if (md5(md5($password)) != $account_info["password"]) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 1003, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 1003); } } // all checks out. Log them in, after populating sessions $_SESSION["ft"]["settings"] = ft_get_settings("", "core"); // only load the core settings $_SESSION["ft"]["account"] = ft_get_account_info($account_info["account_id"]); $_SESSION["ft"]["account"]["is_logged_in"] = true; $_SESSION["ft"]["account"]["password"] = md5(md5($password)); ft_cache_account_menu($account_info["account_id"]); // if this is an administrator, build and cache the upgrade link and ensure the API version is up to date if ($account_info["account_type"] == "admin") { ft_update_api_version(); ft_build_and_cache_upgrade_info(); } // for clients, store the forms & form Views that they are allowed to access if ($account_info["account_type"] == "client") { $_SESSION["ft"]["permissions"] = ft_get_client_form_views($account_info["account_id"]); } // redirect the user to whatever login page they specified in their settings if (isset($info["auto_redirect_after_login"]) && $info["auto_redirect_after_login"]) { if (isset($info["login_url"]) && !empty($info["login_url"])) { session_write_close(); header("Location: {$login_url}"); exit; } else { $login_url = ft_construct_page_url($account_info["login_page"]); $login_url = "{$g_root_url}{$login_url}"; session_write_close(); header("Location: {$login_url}"); exit; } } return array(true, ""); }
/** * Uninstalls a module from the database. * * @param integer $module_id */ function ft_uninstall_module($module_id) { global $g_table_prefix, $LANG, $g_root_dir, $g_delete_module_folder_on_uninstallation; $module_info = ft_get_module($module_id); $module_folder = $module_info["module_folder"]; if (empty($module_info)) { return false; } $success = true; $has_custom_uninstall_script = false; if (is_file("{$g_root_dir}/modules/{$module_folder}/library.php")) { @(include_once "{$g_root_dir}/modules/{$module_folder}/library.php"); $uninstall_function_name = "{$module_folder}__uninstall"; if (function_exists($uninstall_function_name)) { $has_custom_uninstall_script = true; // get the module language file contents and store the info in the $LANG global for // so it can be accessed by the uninstallation script $LANG[$module_folder] = ft_get_module_lang_file_contents($module_folder); list($success, $custom_message) = $uninstall_function_name($module_id); // if there was a custom message returned (error or notification), overwrite the default // message if (!empty($custom_message)) { $message = $custom_message; } } } // finally, if there wasn't a custom uninstallation script, or there WAS and it was successfully // run, remove the module record and any old database references if (!$has_custom_uninstall_script || $has_custom_uninstall_script && $success) { // delete the module tables mysql_query("DELETE FROM {$g_table_prefix}modules WHERE module_id = {$module_id}"); mysql_query("DELETE FROM {$g_table_prefix}module_menu_items WHERE module_id = {$module_id}"); // if this module was used in any menus, update them $query = mysql_query("\n SELECT DISTINCT menu_id\n FROM {$g_table_prefix}menu_items\n WHERE page_identifier = 'module_{$module_id}'\n "); $affected_menu_ids = array(); while ($row = mysql_fetch_assoc($query)) { $affected_menu_ids[] = $row["menu_id"]; } if (!empty($affected_menu_ids)) { mysql_query("\n DELETE FROM {$g_table_prefix}menu_items\n WHERE page_identifier = 'module_{$module_id}'\n "); // now update the orders of all affected menus foreach ($affected_menu_ids as $menu_id) { ft_update_menu_order($menu_id); } // if rows were deleted, re-cache the admin menu and update the ordering of the admin account. // ASSUMPTION: only administrator accounts can have modules as items (will need to update at some // point soon, no doubt). ft_cache_account_menu($_SESSION["ft"]["account"]["account_id"]); ft_update_menu_order($_SESSION["ft"]["account"]["menu_id"]); } // delete any hooks registered by this module ft_unregister_module_hooks($module_folder); } // now delete the entire module folder $deleted = false; if ($g_delete_module_folder_on_uninstallation) { $deleted = ft_delete_folder("{$g_root_dir}/modules/{$module_folder}"); } if ($deleted) { $message = $LANG["notify_module_uninstalled"]; } else { $message = $LANG["notify_module_uninstalled_files_not_deleted"]; } extract(ft_process_hook_calls("end", compact("module_id", "success", "message"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }