/** * Adds new form field(s) to the database. This was totally re-written in 2.1.0, for the new Edit Fields * page. * * @param integer $infohash a hash containing the contents of the Edit Form Advanced -> Add Fields page. * @param integer $form_id The unique form ID * @return array Returns array with indexes:<br/> * [0]: true/false (success / failure)<br/> * [1]: message string<br/> */ function ft_add_form_fields($form_id, $fields) { global $g_debug, $g_table_prefix, $LANG, $g_field_sizes; $success = true; $message = ""; $fields = ft_sanitize($fields); foreach ($fields as $field_info) { $field_name = $field_info["form_field_name"]; $field_size = $field_info["field_size"]; $field_type_id = $field_info["field_type_id"]; $display_name = $field_info["display_name"]; $include_on_redirect = $field_info["include_on_redirect"]; $list_order = $field_info["list_order"]; $col_name = $field_info["col_name"]; $is_new_sort_group = $field_info["is_new_sort_group"]; // in order for the field to be added, it needs to have the label, name, size and column name. Otherwise they're // ignored if (empty($display_name) || empty($field_name) || empty($field_size) || empty($col_name)) { continue; } // add the new field to form_fields $query = "\n INSERT INTO {$g_table_prefix}form_fields (form_id, field_name, field_size, field_type_id,\n data_type, field_title, col_name, list_order, is_new_sort_group, include_on_redirect)\n VALUES ({$form_id}, '{$field_name}', '{$field_size}', {$field_type_id},\n 'string', '{$display_name}', '{$col_name}', {$list_order}, '{$is_new_sort_group}', '{$include_on_redirect}')\n "; $result = mysql_query($query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>, line " . __LINE__ . ": <i>{$query}</i>", mysql_error()); $new_field_id = mysql_insert_id(); $new_field_size = $g_field_sizes[$field_size]["sql"]; list($is_success, $err_message) = _ft_add_table_column("{$g_table_prefix}form_{$form_id}", $col_name, $new_field_size); // if the alter table didn't work, return with an error message and remove the entry we just added to the form_fields table if (!$is_success) { if (!empty($new_field_id) && is_numeric($new_field_id)) { mysql_query("\n DELETE FROM {$g_table_prefix}form_fields\n WHERE field_id = {$new_field_id}\n LIMIT 1\n "); } $success = false; $replacement_info = array("fieldname" => $field_name); $message = ft_eval_smarty_string($LANG["notify_form_field_not_added"], $replacement_info); if ($g_debug) { $message .= " <i>\"{$err_message}\"</i>"; } return array($success, $message); } } extract(ft_process_hook_calls("end", compact("infohash", "form_id"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }
/** * Retrieves all information about any user account (administrator or client). * * @param integer $user_id the unique account ID * @return array returns a hash of all pertinent data. */ function ft_get_account_info($account_id) { global $g_table_prefix; $query = "\r\n SELECT *\r\n FROM {$g_table_prefix}accounts\r\n WHERE account_id = {$account_id}\r\n "; $result = mysql_query($query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: <i>{$query}</i>", mysql_error()); $account_info = mysql_fetch_assoc($result); if (empty($account_info)) { return array(); } // also extract any account-specific settings from account_settings $query = mysql_query("SELECT * FROM {$g_table_prefix}account_settings WHERE account_id = {$account_id}"); $settings = array(); while ($row = mysql_fetch_assoc($query)) { $settings[$row["setting_name"]] = $row["setting_value"]; } $account_info["settings"] = $settings; extract(ft_process_hook_calls("main", compact("account_info"), array("account_info")), EXTR_OVERWRITE); return $account_info; }
/** * Creates and returns a search for any form View, and any subset of its columns, returning results in * any column order and for any single page subset (or all pages). The final $search_columns parameter * was added most recently to fix bug #173. That parameter lets the caller differentiate between the * columns being returned ($columns param) and columns to be searched ($search_columns). * * @param integer $form_id the unique form ID * @param integer $view_id the unique View ID * @param mixed $results_per_page an integer, or "all". * @param integer $page_num The current page number - or empty string, if this function is returning all * results in one page (e.g. printer friendly page). * @param string $order A string of form: "{db column}_{ASC|DESC}" * @param mixed $columns An array containing which database columns to search and return, or a string: * "all" - which returns all columns in the form. * @param array $search_fields an optional hash with these keys:<br/> * search_field<br/> * search_date<br/> * search_keyword<br/> * @param array submission_ids - an optional array containing a list of submission IDs to return. * This may seem counterintuitive to pass the results that it needs to return to the function that * figures out WHICH results to return, but it's actually kinda handy: this function returns exactly * the field information that's needed in the order that's needed. * @param array $submission_ids an optional array of submission IDs to return * @param array $search_columns an optional array determining which database columns should be included * in the search. Note: this is different from the $columns parameter which just determines which * database columns will be returned. If it's not defined, it's just set to $columns. * * @return array returns a hash with these keys:<br/> * ["search_query"] => an array of hashes, each index a search result row<br /> * ["search_num_results"] => the number of results in the search (not just the 10 or so * that will appear in the current page, listed in the * "search_query" key<br /> * ["view_num_results"] => the total number of results in this View, regardless of the * current search values. */ function ft_search_submissions($form_id, $view_id, $results_per_page, $page_num, $order, $columns_to_return, $search_fields = array(), $submission_ids = array(), $searchable_columns = array()) { global $g_table_prefix; // for backward compatibility if (empty($searchable_columns)) { $searchable_columns = $columns_to_return; } // determine the various SQL clauses for the searches $order_by = _ft_get_search_submissions_order_by_clause($form_id, $order); $limit_clause = _ft_get_limit_clause($page_num, $results_per_page); $select_clause = _ft_get_search_submissions_select_clause($columns_to_return); $filter_clause = _ft_get_search_submissions_view_filter_clause($view_id); $submission_id_clause = _ft_get_search_submissions_submission_id_clause($submission_ids); $search_where_clause = _ft_get_search_submissions_search_where_clause($form_id, $search_fields, $searchable_columns); // (1) our main search query that returns a PAGE of submission info $search_query = "\n SELECT {$select_clause}\n FROM {$g_table_prefix}form_{$form_id}\n WHERE is_finalized = 'yes'\n {$search_where_clause}\n {$filter_clause}\n {$submission_id_clause}\n ORDER BY {$order_by}\n {$limit_clause}\n "; $search_result = mysql_query($search_query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>; Query: {$search_query}; Error: ", mysql_error()); $search_result_rows = array(); while ($row = mysql_fetch_assoc($search_result)) { $search_result_rows[] = $row; } // (2) find out how many results there are in this current search $search_results_count_query = mysql_query("\n SELECT count(*) as c\n FROM {$g_table_prefix}form_{$form_id}\n WHERE is_finalized = 'yes'\n {$search_where_clause}\n {$filter_clause}\n {$submission_id_clause}\n ") or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: ", mysql_error()); $search_num_results_info = mysql_fetch_assoc($search_results_count_query); $search_num_results = $search_num_results_info["c"]; // (3) find out how many results should appear in the View, regardless of the current search criteria $view_results_count_query = mysql_query("\n SELECT count(*) as c\n FROM {$g_table_prefix}form_{$form_id}\n WHERE is_finalized = 'yes'\n {$filter_clause}\n ") or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: ", mysql_error()); $view_num_results_info = mysql_fetch_assoc($view_results_count_query); $view_num_results = $view_num_results_info["c"]; $return_hash["search_rows"] = $search_result_rows; $return_hash["search_num_results"] = $search_num_results; $return_hash["view_num_results"] = $view_num_results; extract(ft_process_hook_calls("end", compact("form_id", "submission_id", "view_id", "results_per_page", "page_num", "order", "columns", "search_fields", "submission_ids", "return_hash"), array("return_hash")), EXTR_OVERWRITE); return $return_hash; }
/** * This function is called whenever the user adds an option list through the Add External form process. It checks * all existing option lists to see if an identical set already exists. If it does, it returns the existing * option list ID and if not, creates a new one and returns that ID. * * @param integer $form_id * @param array $option_list_info * @return integer $list_id the new or existing option list ID */ function ft_create_unique_option_list($form_id, $option_list_info) { global $g_table_prefix; $existing_option_lists = ft_get_option_lists("all"); $already_exists = false; $list_id = ""; foreach ($existing_option_lists["results"] as $existing_option_list) { $curr_list_id = $existing_option_list["list_id"]; // when comparing field groups, just compare the actual field options. The option list name & original // form aren't considered. This may lead to a little head-shaking in the UI when they see an inappropriate // option list name, but it's easily changed $grouped_option_list_info = ft_get_option_list_options($curr_list_id); // $curr_options contains an array of hashes. Each hash contains information about the group & info about // the options in that group. Since we're just comparing a brand new list, we know that it only has one group: // hence, rule out those option lists with more than one group if (count($grouped_option_list_info) > 1) { continue; } // fringe case. Technically, a user may have created an Option List then deleted all options & groups. if (count($grouped_option_list_info) == 0) { continue; } $curr_options = $grouped_option_list_info[0]["options"]; if (count($curr_options) != count($option_list_info["options"])) { continue; } $has_same_option_fields = true; for ($i = 0; $i < count($curr_options); $i++) { $val = ft_sanitize($curr_options[$i]["option_value"]); $txt = ft_sanitize($curr_options[$i]["option_name"]); $val2 = $option_list_info["options"][$i]["value"]; $txt2 = $option_list_info["options"][$i]["text"]; if ($val != $val2 || $txt != $txt2) { $has_same_option_fields = false; break; } } if (!$has_same_option_fields) { continue; } $already_exists = true; $list_id = $curr_list_id; break; } // if this group didn't already exist, add it! if (!$already_exists) { $option_list_name = $option_list_info["option_list_name"]; $query = "INSERT INTO {$g_table_prefix}option_lists (option_list_name, is_grouped, original_form_id)\n VALUES ('{$option_list_name}', 'no', {$form_id})"; $result = mysql_query($query) or ft_handle_error($query, mysql_error()); if (!$result) { return false; } $list_id = mysql_insert_id(); // now add the list group entry $query = mysql_query("\n INSERT INTO {$g_table_prefix}list_groups (group_type, list_order)\n VALUES ('option_list_{$list_id}', 1)\n ") or die(mysql_error()); $list_group_id = mysql_insert_id(); // add the options $order = 1; foreach ($option_list_info["options"] as $option) { $value = ft_sanitize($option["value"]); $text = ft_sanitize($option["text"]); $query = "\n INSERT INTO {$g_table_prefix}field_options (list_id, list_group_id, option_value, option_name, option_order)\n VALUES ({$list_id}, {$list_group_id}, '{$value}', '{$text}', {$order})\n "; $result = mysql_query($query) or ft_handle_error($query, mysql_error()); $order++; } } return $list_id; }
/** * Caches the total number of (finalized) submissions in a particular form - or all forms - * in the $_SESSION["ft"]["form_{$form_id}_num_submissions"] key. That value is used on the administrators * main Forms page to list the form submission count. * * @param integer $form_id */ function _ft_cache_form_stats($form_id = "") { global $g_table_prefix; $where_clause = ""; if (!empty($form_id)) { $where_clause = "AND form_id = {$form_id}"; } $query = mysql_query("\n SELECT form_id\n FROM {$g_table_prefix}forms\n WHERE is_complete = 'yes'\n {$where_clause}\n "); // loop through all forms, extract the submission count and first submission date while ($form_info = mysql_fetch_assoc($query)) { $form_id = $form_info["form_id"]; $count_query = mysql_query("\n SELECT count(*) as c\n FROM {$g_table_prefix}form_{$form_id}\n WHERE is_finalized = 'yes'\n ") or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>, line " . __LINE__, mysql_error()); $info = mysql_fetch_assoc($count_query); $_SESSION["ft"]["form_{$form_id}_num_submissions"] = $info["c"]; } }
<?php require "../../global/session_start.php"; // this just checks that SOMEONE's logged in - even someone via the Submission Accounts module ft_check_permission("user"); ft_include_module("pages"); $request = array_merge($_POST, $_GET); $page_id = $request["id"]; $page_info = pg_get_page($page_id); // check permissions! The above code handles booting a user out if they're not logged in, // so the only case we're worried about $account_type = isset($_SESSION["ft"]["account"]["account_type"]) ? $_SESSION["ft"]["account"]["account_type"] : ""; $account_id = isset($_SESSION["ft"]["account"]["account_id"]) ? $_SESSION["ft"]["account"]["account_id"] : ""; if ($account_type == "client" && $page_info["access_type"] == "private") { if (!in_array($account_id, $page_info["clients"])) { ft_handle_error("Sorry, you do not have permissions to see this page."); exit; } } $content = $page_info["content"]; switch ($page_info["content_type"]) { case "php": ob_start(); eval($page_info["content"]); $content = ob_get_contents(); ob_end_clean(); break; case "smarty": $content = ft_eval_smarty_string($page_info["content"]); break; }
// if the form ID is specified in GET or POST, store it in sessions as curr_form_id $form_id = ft_load_field("form_id", "curr_form_id"); if (empty($form_id)) { session_write_close(); header("location: index.php"); exit; } $view_id = ft_load_field("view_id", "form_{$form_id}_view_id"); // check the current client is permitted to view this information! ft_check_client_may_view($account_id, $form_id, $view_id); // this returns all and ONLY the Views accessible by this client $grouped_views = ft_get_grouped_views($form_id, array("omit_hidden_views" => true, "omit_empty_groups" => true, "account_id" => $account_id)); if (empty($view_id) || !ft_check_view_exists($view_id, true)) { if (count($grouped_views[0]["views"]) == 0) { // no Views defined for this client ft_handle_error($LANG["notify_no_views_assigned_to_client_form"], "", "notify"); exit; } else { $view_id = $grouped_views[0]["views"][0]["view_id"]; } } $_SESSION["ft"]["form_{$form_id}_view_id"] = $view_id; $form_info = ft_get_form($form_id); $view_info = ft_get_view($view_id); if (isset($_GET["add_submission"]) && $view_info["may_add_submissions"] == "yes") { $submission_id = ft_create_blank_submission($form_id, $view_id, true); header("location: edit_submission.php?form_id={$form_id}&view_id={$view_id}&submission_id={$submission_id}"); exit; } // if the View just changed (i.e. it was just selected by the user), deselect any items in // this form
/** * Updates the administrator account. With the addition of the "UI Language" option, this action * gets a little more complicated. The problem is that we can't just update the UI language in * sessions *within* this function, because by the time this function is called, the appropriate * language file is already in memory and being used. So, to get around this problem, the login * information form now passes along both the new and old UI languages. If it's different, AFTER * this function is called, you need to reset sessions and refresh the page. So be aware that * this problem is NOT handled by this function, see: * /admin/accounts/index.php to see how it's solved. * * @param array $infohash This parameter should be a hash (e.g. $_POST or $_GET) containing the * following keys: first_name, last_name, user_name, password. * @param integer $user_id the administrator's user ID * @return array [0]: true/false (success / failure) * [1]: message string */ function ft_update_admin_account($infohash, $account_id) { global $g_table_prefix, $g_root_url, $LANG; $success = true; $message = $LANG["notify_account_updated"]; $infohash = ft_sanitize($infohash); extract(ft_process_hook_calls("start", compact("infohash", "account_id"), array("infohash")), EXTR_OVERWRITE); $rules = array(); $rules[] = "required,first_name,{$LANG["validation_no_first_name"]}"; $rules[] = "required,last_name,{$LANG["validation_no_last_name"]}"; $rules[] = "required,email,{$LANG["validation_no_email"]}"; $rules[] = "required,theme,{$LANG["validation_no_theme"]}"; $rules[] = "required,login_page,{$LANG["validation_no_login_page"]}"; $rules[] = "required,logout_url,{$LANG["validation_no_account_logout_url"]}"; $rules[] = "required,ui_language,{$LANG["validation_no_ui_language"]}"; $rules[] = "required,sessions_timeout,{$LANG["validation_no_sessions_timeout"]}"; $rules[] = "required,date_format,{$LANG["validation_no_date_format"]}"; $rules[] = "required,username,{$LANG["validation_no_username"]}"; $rules[] = "if:password!=,required,password_2,{$LANG["validation_no_account_password_confirmed"]}"; $rules[] = "if:password!=,same_as,password,password_2,{$LANG["validation_passwords_different"]}"; $errors = validate_fields($infohash, $rules); if (!empty($errors)) { $success = false; array_walk($errors, create_function('&$el', '$el = "• " . $el;')); $message = implode("<br />", $errors); return array($success, $message); } $first_name = $infohash["first_name"]; $last_name = $infohash["last_name"]; $email = $infohash["email"]; $theme = $infohash["theme"]; $login_page = $infohash["login_page"]; $logout_url = $infohash["logout_url"]; $ui_language = $infohash["ui_language"]; $timezone_offset = $infohash["timezone_offset"]; $sessions_timeout = $infohash["sessions_timeout"]; $date_format = $infohash["date_format"]; $username = $infohash["username"]; $password = $infohash["password"]; $swatch = ""; if (isset($infohash["{$theme}_theme_swatches"])) { $swatch = $infohash["{$theme}_theme_swatches"]; } // if the password is defined, md5 it $password_sql = !empty($password) ? "password = '******', " : ""; // check to see if username is already taken list($valid_username, $problem) = _ft_is_valid_username($username, $account_id); if (!$valid_username) { return array(false, $problem); } $query = "\n UPDATE {$g_table_prefix}accounts\n SET {$password_sql}\n first_name = '{$first_name}',\n last_name = '{$last_name}',\n email = '{$email}',\n theme = '{$theme}',\n swatch = '{$swatch}',\n login_page = '{$login_page}',\n logout_url = '{$logout_url}',\n ui_language = '{$ui_language}',\n timezone_offset = '{$timezone_offset}',\n sessions_timeout = '{$sessions_timeout}',\n date_format = '{$date_format}',\n username = '******'\n WHERE account_id = {$account_id}\n "; mysql_query($query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: <i>{$query}</i>", mysql_error()); // update the settings $_SESSION["ft"]["settings"] = ft_get_settings(); $_SESSION["ft"]["account"] = ft_get_account_info($account_id); $_SESSION["ft"]["account"]["is_logged_in"] = true; // if the password just changed, update sessions and empty any temporary password that happens to have been // stored if (!empty($password)) { $_SESSION["ft"]["account"] = ft_get_account_info($account_id); $_SESSION["ft"]["account"]["is_logged_in"] = true; $_SESSION["ft"]["account"]["password"] = md5(md5($password)); mysql_query("UPDATE {$g_table_prefix}accounts SET temp_reset_password = NULL where account_id = {$account_id}"); } extract(ft_process_hook_calls("end", compact("infohash", "account_id"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }
/** * Retrieves a list of all clients in the database ordered by last name. N.B. As of 2.0.0, this function * no longer returns a MySQL resource. * * @return array $clients an array of hashes. Each hash is the client info. */ function ft_get_client_list() { global $g_table_prefix; $query = "SELECT * FROM {$g_table_prefix}accounts WHERE account_type = 'client' ORDER BY last_name"; $result = mysql_query($query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: <i>{$query}</i>", mysql_error()); $clients = array(); while ($client = mysql_fetch_assoc($result)) { $clients[] = $client; } return $clients; }
/** * Caches the total number of (finalized) submissions in a particular form - or all forms - * in the $_SESSION["ft"]["form_{$form_id}_num_submissions"] key. That value is used on the administrators * main Forms page to list the form submission count. * * @param integer $form_id */ function _ft_cache_view_stats($form_id, $view_id = "") { global $g_table_prefix; $view_ids = array(); if (empty($view_id)) { $view_ids = ft_get_view_ids($form_id); } else { $view_ids[] = $view_id; } foreach ($view_ids as $view_id) { $filters = ft_get_view_filter_sql($view_id); // if there aren't any filters, just set the submission count & first submission date to the same // as the parent form if (empty($filters)) { $_SESSION["ft"]["view_{$view_id}_num_submissions"] = $_SESSION["ft"]["form_{$form_id}_num_submissions"]; } else { $filter_clause = join(" AND ", $filters); $count_query = mysql_query("\r\n SELECT count(*) as c\r\n FROM {$g_table_prefix}form_{$form_id}\r\n WHERE is_finalized = 'yes' AND\r\n {$filter_clause}\r\n ") or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>, line " . __LINE__, mysql_error()); $info = mysql_fetch_assoc($count_query); $_SESSION["ft"]["view_{$view_id}_num_submissions"] = $info["c"]; } } }
<?php require "../../global/session_start.php"; ft_check_permission("admin"); $request = array_merge($_POST, $_GET); // if the form ID is specified in GET or POST, store it in sessions as curr_form_id $form_id = ft_load_field("form_id", "curr_form_id"); if (empty($form_id) || !is_numeric($form_id)) { session_write_close(); header("location: index.php"); exit; } // check this is a valid form if (!ft_check_form_exists($form_id)) { ft_handle_error($LANG["notify_form_does_not_exist"]); exit; } // next, get the View. If it's not defined, the user has just arrives at the page. We grab the first View in // (ordered) list of Views for this form. If THAT doesn't exist, the user has deleted all Views (doh!), so // there's nothing to show. In that case, just redirect them to the Views tab, where an error / warning message // will appear in the page $view_id = ft_load_field("view_id", "form_{$form_id}_view_id"); $grouped_views = ft_get_grouped_views($form_id, array("omit_hidden_views" => true, "omit_empty_groups" => true)); if (empty($view_id) || !ft_check_view_exists($view_id, true)) { // here, we know that the first View group has at least one item. [hmm...] if (count($grouped_views[0]["views"]) == 0) { // no Views defined for this form! redirect to the Views page and display a message header("location: edit.php?page=views&form_id={$form_id}&message=no_views"); exit; } else { $view_id = $grouped_views[0]["views"][0]["view_id"];