function smarty_function_languages_dropdown($params, &$smarty) { global $LANG; if (empty($params["name_id"])) { $smarty->trigger_error("assign: missing 'name_id' parameter. This is used to give the select field a name and id value."); return; } $default_value = isset($params["default"]) ? $params["default"] : ""; $onchange = isset($params["onchange"]) ? $params["onchange"] : ""; $attributes = array("id" => $params["name_id"], "name" => $params["name_id"], "onchange" => $onchange); $attribute_str = ""; while (list($key, $value) = each($attributes)) { if (!empty($value)) { $attribute_str .= " {$key}=\"{$value}\""; } } $available_language_info = ft_get_settings("available_languages"); $available_language_arr = explode("|", $available_language_info); $html = "<select {$attribute_str}>\n\t <option value=\"\">{$LANG["phrase_please_select"]}</option>"; foreach ($available_language_arr as $lang_info) { list($lang_file, $lang_display) = explode(",", $lang_info); $selected = $default_value == $lang_file ? "selected" : ""; $html .= "<option value=\"{$lang_file}\" {$selected}>{$lang_display}</option>\n"; } $html .= "</select>"; return $html; }
$placeholders["export_group_name"] = ft_eval_smarty_string($export_group_info["group_name"]); $placeholders["export_types"] = $export_types; $placeholders["export_type_smarty_template"] = $export_type_smarty_template; $page = ft_eval_smarty_string($template, $placeholders); if ($export_group_info["action"] == "new_window" || $export_group_info["action"] == "popup") { // if required, send the HTTP headers if (!empty($export_group_info["headers"])) { $headers = preg_replace("/\r\n|\r/", "\n", $export_group_info["headers"]); $header_lines = explode("\n", $headers); foreach ($header_lines as $header) { header(ft_eval_smarty_string($header, $placeholders)); } } echo $page; } else { $settings = ft_get_settings("", "export_manager"); $file_upload_dir = $settings["file_upload_dir"]; $file_upload_url = $settings["file_upload_url"]; $file = "{$file_upload_dir}/{$placeholders["filename"]}"; if ($handle = @fopen($file, "w")) { fwrite($handle, $page); fclose($handle); @chmod($file, 0777); $placeholders = array("url" => "{$file_upload_url}/{$placeholders["filename"]}"); $message = ft_eval_smarty_string($LANG["export_manager"]["notify_file_generated"], $placeholders); echo "{ \"success\": 1, \"message\": \"{$message}\", \"target_message_id\": \"ft_message\" }"; exit; } else { $placeholders = array("url" => "{$file_upload_url}/{$placeholders["filename"]}", "folder" => $file_upload_dir, "export_manager_settings_link" => "{$g_root_url}/modules/export_manager/settings.php"); $message = ft_eval_smarty_string($LANG["export_manager"]["notify_file_not_generated"], $placeholders); echo "{ \"success\": 0, \"message\": \"{$message}\", \"target_message_id\": \"ft_message\" }";
} else { $params = array("\"success\": \"1\""); $count = 1; foreach ($uploaded_file_info as $url) { $params[] = "\"url_{$count}\": \"{$url}\""; $count++; } echo "{ " . implode(", ", $params) . " }"; } break; // used on Edit Field Options pages. It uploads the files to the /upload folder and returns the filenames (renamed // & stored in sessions). That information is then used by the JS to load and process the page content // used on Edit Field Options pages. It uploads the files to the /upload folder and returns the filenames (renamed // & stored in sessions). That information is then used by the JS to load and process the page content case "upload_scraped_page_for_smart_fill": $settings = ft_get_settings(array("file_upload_dir", "file_upload_url"), "core"); $file_upload_dir = $settings["file_upload_dir"]; $file_upload_url = $settings["file_upload_url"]; $upload_tmp_file_prefix = "ft_sf_tmp_"; if (!isset($_SESSION["ft"]["smart_fill_tmp_uploaded_files"])) { $_SESSION["ft"]["smart_fill_tmp_uploaded_files"] = array(); } $uploaded_file_info = array(); $error = false; if (!isset($_FILES["form_page_1"])) { continue; } $filename = $upload_tmp_file_prefix . $_FILES["form_page_1"]["name"]; $tmp_location = $_FILES["form_page_1"]["tmp_name"]; list($g_success, $g_message, $final_filename) = ft_upload_file($file_upload_dir, $filename, $tmp_location); if ($g_success) {
} $preselected_subids_str = implode(",", $preselected_subids); $field_types = ft_get_field_types(true); $has_searchable_field = false; foreach ($view_info["fields"] as $field_info) { if ($field_info["is_searchable"] == "yes") { $has_searchable_field = true; break; } } $settings = ft_get_settings("", "core"); $date_picker_info = ft_get_default_date_field_search_value($settings["default_date_field_search_value"]); $default_date_field_search_value = $date_picker_info["default_date_field_search_value"]; $date_field_search_js_format = $date_picker_info["date_field_search_js_format"]; // get all the shared resources $shared_resources_list = ft_get_settings("edit_submission_onload_resources"); $shared_resources_array = explode("|", $shared_resources_list); $shared_resources = ""; foreach ($shared_resources_array as $resource) { $shared_resources .= ft_eval_smarty_string($resource, array("g_root_url" => $g_root_url)) . "\n"; } // ------------------------------------------------------------------------------------------------ // compile the header information $page_vars = array(); $page_vars["page"] = "client_forms"; $page_vars["page_url"] = ft_get_page_url("client_form_submissions", array("form_id" => $form_id)); $page_vars["head_title"] = $LANG["word_submissions"]; $page_vars["form_info"] = $form_info; $page_vars["form_id"] = $form_id; $page_vars["view_id"] = $view_id; $page_vars["search_rows"] = $search_rows;
/** * Smarty plugin * ------------------------------------------------------------- * File: function.edit_custom_field * Type: function * Name: edit_custom_field * Purpose: This is used on the Edit Submission pages. It does all the clever stuff needed to generate the * actual markup for a single field, with whatever user-defined settings have been employed. * * It's strongly coupled to the ft_get_grouped_view_fields function (when called with the form ID & * submission ID params) to ensure that all data is efficiently returned for use by this function. * ------------------------------------------------------------- */ function smarty_function_edit_custom_field($params, &$smarty) { global $LANG, $g_root_url, $g_root_dir, $g_multi_val_delimiter, $g_table_prefix; if (empty($params["form_id"])) { $smarty->trigger_error("assign: missing 'form_id' parameter."); return; } if (empty($params["field_info"])) { $smarty->trigger_error("assign: missing 'field_info' parameter."); return; } if (empty($params["field_types"])) { $smarty->trigger_error("assign: missing 'field_types' parameter."); return; } if (empty($params["settings"])) { $smarty->trigger_error("assign: missing 'settings' parameter."); return; } $form_id = $params["form_id"]; $field_info = $params["field_info"]; $field_types = $params["field_types"]; $settings = $params["settings"]; $submission_id = isset($params["submission_id"]) ? $params["submission_id"] : ""; // loop through the field types and store the one we're interested in in $field_type_info $field_type_info = array(); foreach ($field_types as $curr_field_type) { if ($field_info["field_type_id"] == $curr_field_type["field_type_id"]) { $field_type_info = $curr_field_type; break; } } if ($field_info["is_editable"] == "no") { $markup_with_placeholders = trim($field_type_info["view_field_smarty_markup"]); if (empty($markup_with_placeholders)) { echo $field_info["submission_info"]["value"]; return; } } else { $markup_with_placeholders = $field_type_info["edit_field_smarty_markup"]; } // now construct all available placeholders $placeholders = array("FORM_ID" => $form_id, "VIEW_ID" => $field_info["view_id"], "SUBMISSION_ID" => $submission_id, "FIELD_ID" => $field_info["field_id"], "NAME" => $field_info["field_name"], "COLNAME" => $field_info["col_name"], "VALUE" => isset($field_info["submission_value"]) ? $field_info["submission_value"] : "", "SETTINGS" => $settings, "CONTEXTPAGE" => "edit_submission", "ACCOUNT_INFO" => isset($_SESSION["ft"]["account"]) ? $_SESSION["ft"]["account"] : array(), "g_root_url" => $g_root_url, "g_root_dir" => $g_root_dir, "g_multi_val_delimiter" => $g_multi_val_delimiter); // add in all field type settings and their replacements foreach ($field_type_info["settings"] as $setting_info) { $curr_setting_id = $setting_info["setting_id"]; $curr_setting_field_type = $setting_info["field_type"]; $default_value_type = $setting_info["default_value_type"]; $value = $setting_info["default_value"]; $identifier = $setting_info["field_setting_identifier"]; foreach ($field_info["field_settings"] as $setting) { $found = false; while (list($setting_id, $setting_value) = each($setting)) { if ($setting_id == $curr_setting_id) { $value = $setting_value; break; } } reset($setting); if ($found) { break; } } // next, if the setting is dynamic, convert the stored value if ($default_value_type == "dynamic") { // dynamic setting values should ALWAYS be of the form "setting_name,module_folder/'core'". If they're not, just ignore it $parts = explode(",", $value); if (count($parts) == 2) { $value = ft_get_settings($parts[0], $parts[1]); } } // if this setting type is a dropdown list and $value is non-empty, get the list of options if ($curr_setting_field_type == "option_list_or_form_field" && !empty($value)) { if (preg_match("/^form_field/", $value)) { $value = ft_get_mapped_form_field_data($value); } else { $value = ft_get_option_list($value); } } $placeholders[$identifier] = $value; } echo ft_eval_smarty_string($markup_with_placeholders, $placeholders); }
/** * This function processes the form submissions, after the form has been set up in the database. */ function ft_process_form($form_data) { global $g_table_prefix, $g_multi_val_delimiter, $g_query_str_multi_val_separator, $g_root_dir, $LANG, $g_api_version, $g_api_recaptcha_private_key; // ensure the incoming values are escaped $form_data = ft_sanitize($form_data); $form_id = $form_data["form_tools_form_id"]; $form_info = ft_get_form($form_id); // do we have a form for this id? if (!ft_check_form_exists($form_id)) { $page_vars = array("message_type" => "error", "message" => $LANG["processing_invalid_form_id"]); ft_display_page("error.tpl", $page_vars); exit; } extract(ft_process_hook_calls("start", compact("form_info", "form_id", "form_data"), array("form_data")), EXTR_OVERWRITE); // check to see if this form has been completely set up if ($form_info["is_complete"] == "no") { $page_vars = array("message_type" => "error", "message" => $LANG["processing_form_incomplete"]); ft_display_page("error.tpl", $page_vars); exit; } // check to see if this form has been disabled if ($form_info["is_active"] == "no") { if (isset($form_data["form_tools_inactive_form_redirect_url"])) { header("location: {$form_data["form_tools_inactive_form_redirect_url"]}"); exit; } $page_vars = array("message_type" => "error", "message" => $LANG["processing_form_disabled"]); ft_display_page("error.tpl", $page_vars); exit; } // do we have a form for this id? if (!ft_check_form_exists($form_id)) { $page_vars = array("message_type" => "error", "message" => $LANG["processing_invalid_form_id"]); ft_display_page("error.tpl", $page_vars); exit; } // was there a reCAPTCHA response? If so, a recaptcha was just submitted. This generally implies the // form page included the API, so check it was entered correctly. If not, return the user to the webpage if (isset($g_api_version) && isset($form_data["recaptcha_response_field"])) { $passes_captcha = false; $recaptcha_challenge_field = $form_data["recaptcha_challenge_field"]; $recaptcha_response_field = $form_data["recaptcha_response_field"]; $folder = dirname(__FILE__); require_once "{$folder}/global/api/recaptchalib.php"; $resp = recaptcha_check_answer($g_api_recaptcha_private_key, $_SERVER["REMOTE_ADDR"], $recaptcha_challenge_field, $recaptcha_response_field); if ($resp->is_valid) { $passes_captcha = true; } else { // since we need to pass all the info back to the form page we do it by storing the data in sessions. Enable 'em. @ft_api_start_sessions(); $_SESSION["form_tools_form_data"] = $form_data; $_SESSION["form_tools_form_data"]["api_recaptcha_error"] = $resp->error; // if there's a form_tools_form_url specified, redirect to that if (isset($form_data["form_tools_form_url"])) { header("location: {$form_data["form_tools_form_url"]}"); exit; } else { if (isset($_SERVER["HTTP_REFERER"])) { header("location: {$_SERVER["HTTP_REFERER"]}"); exit; } else { $page_vars = array("message_type" => "error", "message" => $LANG["processing_no_form_url_for_recaptcha"]); ft_display_page("error.tpl", $page_vars); exit; } } } } // get a list of the custom form fields (i.e. non-system) for this form $form_fields = ft_get_form_fields($form_id, array("include_field_type_info" => true)); $custom_form_fields = array(); $file_fields = array(); foreach ($form_fields as $field_info) { $field_id = $field_info["field_id"]; $is_system_field = $field_info["is_system_field"]; $field_name = $field_info["field_name"]; // ignore system fields if ($is_system_field == "yes") { continue; } if ($field_info["is_file_field"] == "no") { $custom_form_fields[$field_name] = array("field_id" => $field_id, "col_name" => $field_info["col_name"], "field_title" => $field_info["field_title"], "include_on_redirect" => $field_info["include_on_redirect"], "field_type_id" => $field_info["field_type_id"], "is_date_field" => $field_info["is_date_field"]); } else { $file_fields[] = array("field_id" => $field_id, "field_info" => $field_info); } } // now examine the contents of the POST/GET submission and get a list of those fields // which we're going to update $valid_form_fields = array(); while (list($form_field, $value) = each($form_data)) { // if this field is included, store the value for adding to DB if (array_key_exists($form_field, $custom_form_fields)) { $curr_form_field = $custom_form_fields[$form_field]; $cleaned_value = $value; if (is_array($value)) { if ($form_info["submission_strip_tags"] == "yes") { for ($i = 0; $i < count($value); $i++) { $value[$i] = strip_tags($value[$i]); } } $cleaned_value = implode("{$g_multi_val_delimiter}", $value); } else { if ($form_info["submission_strip_tags"] == "yes") { $cleaned_value = strip_tags($value); } } $valid_form_fields[$curr_form_field["col_name"]] = "'{$cleaned_value}'"; } } $now = ft_get_current_datetime(); $ip_address = $_SERVER["REMOTE_ADDR"]; $col_names = array_keys($valid_form_fields); $col_names_str = join(", ", $col_names); if (!empty($col_names_str)) { $col_names_str .= ", "; } $col_values = array_values($valid_form_fields); $col_values_str = join(", ", $col_values); if (!empty($col_values_str)) { $col_values_str .= ", "; } // build our query $query = "\r\n INSERT INTO {$g_table_prefix}form_{$form_id} ({$col_names_str} submission_date, last_modified_date, ip_address, is_finalized)\r\n VALUES ({$col_values_str} '{$now}', '{$now}', '{$ip_address}', 'yes')\r\n "; // add the submission to the database (if form_tools_ignore_submission key isn't set by either the form or a module) $submission_id = ""; if (!isset($form_data["form_tools_ignore_submission"])) { $result = mysql_query($query); if (!$result) { $page_vars = array("message_type" => "error", "error_code" => 304, "error_type" => "system", "debugging" => "Failed query in <b>" . __FUNCTION__ . ", " . __FILE__ . "</b>, line " . __LINE__ . ": <i>" . nl2br($query) . "</i>", mysql_error()); ft_display_page("error.tpl", $page_vars); exit; } $submission_id = mysql_insert_id(); extract(ft_process_hook_calls("end", compact("form_id", "submission_id"), array()), EXTR_OVERWRITE); } $redirect_query_params = array(); // build the redirect query parameter array foreach ($form_fields as $field_info) { if ($field_info["include_on_redirect"] == "no" || $field_info["is_file_field"] == "yes") { continue; } switch ($field_info["col_name"]) { case "submission_id": $redirect_query_params[] = "submission_id={$submission_id}"; break; case "submission_date": $settings = ft_get_settings(); $submission_date_formatted = ft_get_date($settings["default_timezone_offset"], $now, $settings["default_date_format"]); $redirect_query_params[] = "submission_date=" . rawurlencode($submission_date_formatted); break; case "last_modified_date": $settings = ft_get_settings(); $submission_date_formatted = ft_get_date($settings["default_timezone_offset"], $now, $settings["default_date_format"]); $redirect_query_params[] = "last_modified_date=" . rawurlencode($submission_date_formatted); break; case "ip_address": $redirect_query_params[] = "ip_address={$ip_address}"; break; default: $field_name = $field_info["field_name"]; // if $value is an array, convert it to a string, separated by $g_query_str_multi_val_separator if (isset($form_data[$field_name])) { if (is_array($form_data[$field_name])) { $value_str = join($g_query_str_multi_val_separator, $form_data[$field_name]); $redirect_query_params[] = "{$field_name}=" . rawurlencode($value_str); } else { $redirect_query_params[] = "{$field_name}=" . rawurlencode($form_data[$field_name]); } } break; } } // only upload files & send emails if we're not ignoring the submission if (!isset($form_data["form_tools_ignore_submission"])) { // now process any file fields. This is placed after the redirect query param code block above to allow whatever file upload // module to append the filename to the query string, if needed extract(ft_process_hook_calls("manage_files", compact("form_id", "submission_id", "file_fields", "redirect_query_params"), array("success", "message", "redirect_query_params")), EXTR_OVERWRITE); // send any emails ft_send_emails("on_submission", $form_id, $submission_id); } // if the redirect URL has been specified either in the database or as part of the form // submission, redirect the user [form submission form_tools_redirect_url value overrides // database value] if (!empty($form_info["redirect_url"]) || !empty($form_data["form_tools_redirect_url"])) { // build redirect query string $redirect_url = isset($form_data["form_tools_redirect_url"]) && !empty($form_data["form_tools_redirect_url"]) ? $form_data["form_tools_redirect_url"] : $form_info["redirect_url"]; $query_str = ""; if (!empty($redirect_query_params)) { $query_str = join("&", $redirect_query_params); } if (!empty($query_str)) { // only include the ? if it's not already there if (strpos($redirect_url, "?")) { $redirect_url .= "&" . $query_str; } else { $redirect_url .= "?" . $query_str; } } header("Location: " . $redirect_url); exit; } // the user should never get here! This means that the no redirect URL has been specified $page_vars = array("message_type" => "error", "message" => $LANG["processing_no_redirect_url"]); ft_display_page("error.tpl", $page_vars); exit; }
/** * A helper function to return Form Tool's best guess at the timezone offset. First it checks * sessions to see if a person's logged in; if so it uses that. If NOT, it pulls the default * timezone offset value from settings. * * @return string $timezone_offset */ function ft_get_current_timezone_offset() { $timezone_offset = ""; if (isset($_SESSION["ft"]["account"]["timezone_offset"])) { $timezone_offset = $_SESSION["ft"]["account"]["timezone_offset"]; } else { $timezone_offset = ft_get_settings("timezone_offset"); } return $timezone_offset; }
// They need to exactly correspond to the ordering of the search results or they don't make sense $search = isset($_SESSION["ft"]["current_search"]) ? $_SESSION["ft"]["current_search"] : array(); if (isset($_SESSION["ft"]["new_search"]) && $_SESSION["ft"]["new_search"] == "yes") { $searchable_columns = ft_get_view_searchable_fields("", $view_info["fields"]); // extract the original search settings and get the list of IDs $submission_ids = ft_get_search_submission_ids($form_id, $view_id, $search["results_per_page"], $search["order"], $search["search_fields"], $searchable_columns); $_SESSION["ft"]["form_{$form_id}_view_{$view_id}_submissions"] = $submission_ids; $_SESSION["ft"]["new_search"] = "no"; } list($prev_link_html, $search_results_link_html, $next_link_html) = _ft_code_get_link_html($form_id, $view_id, $submission_id, $search["results_per_page"]); // construct the page label $submission_placeholders = ft_get_submission_placeholders($form_id, $submission_id); $edit_submission_page_label = ft_eval_smarty_string($form_info["edit_submission_page_label"], $submission_placeholders); $validation_js = ft_generate_submission_js_validation($grouped_fields); // get all the shared resources $settings = ft_get_settings("", "core"); $shared_resources_list = $settings["edit_submission_onload_resources"]; $shared_resources_array = explode("|", $shared_resources_list); $shared_resources = ""; foreach ($shared_resources_array as $resource) { $shared_resources .= ft_eval_smarty_string($resource, array("g_root_url" => $g_root_url)) . "\n"; } // ------------------------------------------------------------------------------------------------ // compile the header information $page_vars = array(); $page_vars["page"] = "admin_edit_submission"; $page_vars["page_url"] = ft_get_page_url("admin_edit_submission"); $page_vars["head_title"] = $edit_submission_page_label; $page_vars["form_info"] = $form_info; $page_vars["form_id"] = $form_id; $page_vars["view_id"] = $view_id;
/** * 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); }
/** * Used by the "forget password?" page to have a client's login information sent to them. * * @param array $info the $_POST containing a "username" key. That value is used to find the user * account information to email them. * @return array [0]: true/false (success / failure) * [1]: message string */ function ft_send_password($info) { global $g_root_url, $g_root_dir, $g_table_prefix, $LANG; $info = ft_sanitize($info); extract(ft_process_hook_calls("start", compact("info"), array("info")), EXTR_OVERWRITE); $success = true; $message = $LANG["notify_login_info_emailed"]; if (!isset($info["username"]) || empty($info["username"])) { $success = false; $message = $LANG["validation_no_username_or_js"]; return array($success, $message); } $username = $info["username"]; $query = mysql_query("\r\n SELECT *\r\n FROM {$g_table_prefix}accounts\r\n WHERE username = '******'\r\n "); // not found if (!mysql_num_rows($query)) { $success = false; $message = $LANG["validation_account_not_recognized_info"]; return array($success, $message); } $account_info = mysql_fetch_assoc($query); $email = $account_info["email"]; // one final check: confirm the email is defined & valid if (empty($email) || !ft_is_valid_email($email)) { $success = false; $message = $LANG["validation_email_not_found_or_invalid"]; return array($success, $message); } $account_id = $account_info["account_id"]; $username = $account_info["username"]; $new_password = ft_generate_password(); $encrypted_password = md5(md5($new_password)); // update the database with the new password (encrypted). As of 2.1.0 there's a second field to store the // temporary generated password, leaving the original password intact. This prevents a situation arising when // someone other than the admin / client uses the "Forget Password" feature and invalidates a valid, known password. // Any time the user successfully logs in, mysql_query("\r\n UPDATE {$g_table_prefix}accounts\r\n SET temp_reset_password = '******'\r\n WHERE account_id = {$account_id}\r\n "); // now build and sent the email // 1. build the email content $placeholders = array("login_url" => "{$g_root_url}/?id={$account_id}", "email" => $email, "username" => $username, "new_password" => $new_password); $smarty_template_email_content = file_get_contents("{$g_root_dir}/global/emails/forget_password.tpl"); $email_content = ft_eval_smarty_string($smarty_template_email_content, $placeholders); // 2. build the email subject line $placeholders = array("program_name" => ft_get_settings("program_name")); $smarty_template_email_subject = file_get_contents("{$g_root_dir}/global/emails/forget_password_subject.tpl"); $email_subject = trim(ft_eval_smarty_string($smarty_template_email_subject, $placeholders)); // if Swift Mailer is enabled, send the emails with that. In case there's a problem sending the message with // Swift, it falls back the default mail() function. $swift_mail_error = false; $swift_mail_enabled = ft_check_module_enabled("swift_mailer"); if ($swift_mail_enabled) { $sm_settings = ft_get_module_settings("", "swift_mailer"); if ($sm_settings["swiftmailer_enabled"] == "yes") { ft_include_module("swift_mailer"); // get the admin info. We'll use that info for the "from" and "reply-to" values. Note // that we DON'T use that info for the regular mail() function. This is because retrieving // the password is important functionality and we don't want to cause problems that could // prevent the email being sent. Many servers don't all the 4th headers parameter of the mail() // function $admin_info = ft_get_admin_info(); $admin_email = $admin_info["email"]; $email_info = array(); $email_info["to"] = array(); $email_info["to"][] = array("email" => $email); $email_info["from"] = array(); $email_info["from"]["email"] = $admin_email; $email_info["subject"] = $email_subject; $email_info["text_content"] = $email_content; list($success, $sm_message) = swift_send_email($email_info); // if the email couldn't be sent, display the appropriate error message. Otherwise // the default success message is used if (!$success) { $swift_mail_error = true; $message = $sm_message; } } } // if there was an error sending with Swift, or if it wasn't installed, send it by mail() if (!$swift_mail_enabled || $swift_mail_error) { // send email [note: the double quotes around the email recipient and content are intentional: some systems fail without it] if (!@mail("{$email}", $email_subject, $email_content)) { $success = false; $message = $LANG["notify_email_not_sent"]; return array($success, $message); } } extract(ft_process_hook_calls("end", compact("success", "message", "info"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }
/** * Generates the placeholders for a particular form submission. This is used in the email templates, and here and there * for providing placeholder functionality to fields (like the "Edit Submission Label" textfield for a form, where they can * enter placeholders populated here). * * This returns ALL available placeholders for a form, regardless of View. * * @param integer $form_id * @param integer $submission_id * @param array $client_info a hash of information about the appropriate user (optional) * @return array a hash of placeholders and their replacement values (e.g. $arr["FORMURL"] => 17) */ function ft_get_submission_placeholders($form_id, $submission_id, $client_info = "") { global $g_root_url; $placeholders = array(); $settings = ft_get_settings(); $form_info = ft_get_form($form_id); $submission_info = ft_get_submission($form_id, $submission_id); $admin_info = ft_get_admin_info(); $file_field_type_ids = ft_get_file_field_type_ids(); $field_types = ft_get_field_types(true); // now loop through the info stored for this particular submission and for this particular field, // add the custom submission responses to the placeholder hash $form_field_params = array("include_field_type_info" => true, "include_field_settings" => true, "evaluate_dynamic_settings" => true); $form_fields = ft_get_form_fields($form_id, $form_field_params); foreach ($submission_info as $field_info) { $field_id = $field_info["field_id"]; $field_name = $field_info["field_name"]; $field_type_id = $field_info["field_type_id"]; if ($field_info["is_system_field"] == "no") { $placeholders["QUESTION_{$field_name}"] = $field_info["field_title"]; } if (in_array($field_type_id, $file_field_type_ids)) { $field_settings = ft_get_field_settings($field_id); $placeholders["FILENAME_{$field_name}"] = $field_info["content"]; $placeholders["FILEURL_{$field_name}"] = "{$field_settings["folder_url"]}/{$field_info["content"]}"; } else { $detailed_field_info = array(); foreach ($form_fields as $curr_field_info) { if ($curr_field_info["field_id"] != $field_id) { continue; } $detailed_field_info = $curr_field_info; break; } $params = array("form_id" => $form_id, "submission_id" => $submission_id, "value" => $field_info["content"], "field_info" => $detailed_field_info, "field_types" => $field_types, "settings" => $settings, "context" => "email_template"); $value = ft_generate_viewable_field($params); $placeholders["ANSWER_{$field_name}"] = $value; // for backward compatibility if ($field_name == "core__submission_date") { $placeholders["SUBMISSIONDATE"] = $value; } else { if ($field_name == "core__last_modified") { $placeholders["LASTMODIFIEDDATE"] = $value; } else { if ($field_name == "core__ip_address") { $placeholders["IPADDRESS"] = $value; } } } } } // other misc placeholders $placeholders["ADMINEMAIL"] = $admin_info["email"]; $placeholders["FORMNAME"] = $form_info["form_name"]; $placeholders["FORMURL"] = $form_info["form_url"]; $placeholders["SUBMISSIONID"] = $submission_id; $placeholders["LOGINURL"] = $g_root_url . "/index.php"; if (!empty($client_info)) { $placeholders["EMAIL"] = $client_info["email"]; $placeholders["FIRSTNAME"] = $client_info["first_name"]; $placeholders["LASTNAME"] = $client_info["last_name"]; $placeholders["COMPANYNAME"] = $client_info["company_name"]; } extract(ft_process_hook_calls("end", compact("placeholders"), array("placeholders")), EXTR_OVERWRITE); return $placeholders; }
/** * Updates a client account. Used for whomever is currently logged in. * * @param array $info This parameter should be a hash (e.g. $_POST or $_GET) containing keys * named the same as the database fields. * @return array [0]: true/false (success / failure) * [1]: message string */ function ft_update_client($account_id, $info) { global $g_table_prefix, $LANG, $g_password_special_chars; $success = true; $message = $LANG["notify_account_updated"]; $info = ft_sanitize($info); extract(ft_process_hook_calls("start", compact("account_id", "info"), array("info")), EXTR_OVERWRITE); $client_info = ft_get_account_info($account_id); $page = $info["page"]; switch ($page) { case "main": $first_name = $info["first_name"]; $last_name = $info["last_name"]; $email = $info["email"]; $username = $info["username"]; $password_clause = ""; $rules = array(); if (!empty($info["password"])) { $required_password_chars = explode(",", $client_info["settings"]["required_password_chars"]); if (in_array("uppercase", $required_password_chars)) { $rules[] = "reg_exp,password,[A-Z],{$LANG["validation_client_password_missing_uppercase"]}"; } if (in_array("number", $required_password_chars)) { $rules[] = "reg_exp,password,[0-9],{$LANG["validation_client_password_missing_number"]}"; } if (in_array("special_char", $required_password_chars)) { $error = ft_eval_smarty_string($LANG["validation_client_password_missing_special_char"], array("chars" => $g_password_special_chars)); $password_special_chars = preg_quote($g_password_special_chars); $rules[] = "reg_exp,password,[{$password_special_chars}],{$error}"; } if (!empty($client_info["settings"]["min_password_length"])) { $rule = ft_eval_smarty_string($LANG["validation_client_password_too_short"], array("number" => $client_info["settings"]["min_password_length"])); $rules[] = "length>={$client_info["settings"]["min_password_length"]},password,{$rule}"; } // encrypt the password on the assumption that it passes validation. It'll be used in the update query $password = md5(md5($info['password'])); $password_clause = "password = '******',"; } $errors = validate_fields($info, $rules); // check to see if username is already taken list($valid_username, $problem) = _ft_is_valid_username($username, $account_id); if (!$valid_username) { $errors[] = $problem; } // check the password isn't already in password history (if relevant) if (!empty($info["password"])) { if (!empty($client_info["settings"]["num_password_history"])) { $encrypted_password = md5(md5($info["password"])); if (ft_password_in_password_history($account_id, $encrypted_password, $client_info["settings"]["num_password_history"])) { $errors[] = ft_eval_smarty_string($LANG["validation_password_in_password_history"], array("history_size" => $client_info["settings"]["num_password_history"])); } else { ft_add_password_to_password_history($account_id, $encrypted_password); } } } if (!empty($errors)) { $success = false; array_walk($errors, create_function('&$el', '$el = "• " . $el;')); $message = implode("<br />", $errors); return array($success, $message); } $query = "\n UPDATE {$g_table_prefix}accounts\n SET {$password_clause}\n first_name = '{$first_name}',\n last_name = '{$last_name}',\n username = '******',\n email = '{$email}'\n WHERE account_id = {$account_id}\n "; if (mysql_query($query)) { // if the password wasn't empty, reset the temporary password, in case it was set if (!empty($info["password"])) { mysql_query("UPDATE {$g_table_prefix}accounts SET temp_reset_password = NULL where account_id = {$account_id}"); } } else { ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>: <i>{$query}</i>", mysql_error()); } break; case "settings": $rules = array(); if ($client_info["settings"]["may_edit_page_titles"] == "yes") { $rules[] = "required,page_titles,{$LANG["validation_no_titles"]}"; } if ($client_info["settings"]["may_edit_theme"] == "yes") { $rules[] = "required,theme,{$LANG["validation_no_theme"]}"; } if ($client_info["settings"]["may_edit_logout_url"] == "yes") { $rules[] = "required,logout_url,{$LANG["validation_no_logout_url"]}"; } if ($client_info["settings"]["may_edit_language"] == "yes") { $rules[] = "required,ui_language,{$LANG["validation_no_ui_language"]}"; } if ($client_info["settings"]["may_edit_timezone_offset"] == "yes") { $rules[] = "required,timezone_offset,{$LANG["validation_no_timezone_offset"]}"; } if ($client_info["settings"]["may_edit_sessions_timeout"] == "yes") { $rules[] = "required,sessions_timeout,{$LANG["validation_no_sessions_timeout"]}"; $rules[] = "digits_only,sessions_timeout,{$LANG["validation_invalid_sessions_timeout"]}"; } if ($client_info["settings"]["may_edit_date_format"] == "yes") { $rules[] = "required,date_format,{$LANG["validation_no_date_format"]}"; } $errors = validate_fields($info, $rules); if (!empty($errors)) { $success = false; array_walk($errors, create_function('&$el', '$el = "• " . $el;')); $message = implode("<br />", $errors); return array($success, $message); } // update the main accounts table. Only update those settings they're ALLOWED to $settings = array(); if ($client_info["settings"]["may_edit_language"] == "yes") { $settings["ui_language"] = $info["ui_language"]; } if ($client_info["settings"]["may_edit_timezone_offset"] == "yes") { $settings["timezone_offset"] = $info["timezone_offset"]; } if ($client_info["settings"]["may_edit_logout_url"] == "yes") { $settings["logout_url"] = $info["logout_url"]; } if ($client_info["settings"]["may_edit_sessions_timeout"] == "yes") { $settings["sessions_timeout"] = $info["sessions_timeout"]; } if ($client_info["settings"]["may_edit_theme"] == "yes") { $settings["theme"] = $info["theme"]; $settings["swatch"] = ""; if (isset($info["{$info["theme"]}_theme_swatches"])) { $settings["swatch"] = $info["{$info["theme"]}_theme_swatches"]; } } if ($client_info["settings"]["may_edit_date_format"] == "yes") { $settings["date_format"] = $info["date_format"]; } if (!empty($settings)) { $sql_rows = array(); while (list($column, $value) = each($settings)) { $sql_rows[] = "{$column} = '{$value}'"; } $sql = implode(",\n", $sql_rows); $query = "\n UPDATE {$g_table_prefix}accounts\n SET {$sql}\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()); } $settings = array(); if (isset($info["page_titles"])) { $settings["page_titles"] = $info["page_titles"]; } if (isset($info["footer_text"])) { $settings["footer_text"] = $info["footer_text"]; } if (isset($info["max_failed_login_attempts"])) { $settings["max_failed_login_attempts"] = $info["max_failed_login_attempts"]; } if (!empty($settings)) { ft_set_account_settings($account_id, $settings); } break; } extract(ft_process_hook_calls("end", compact("account_id", "info"), array("success", "message")), EXTR_OVERWRITE); // update sessions $_SESSION["ft"]["settings"] = ft_get_settings(); $_SESSION["ft"]["account"] = ft_get_account_info($account_id); $_SESSION["ft"]["account"]["is_logged_in"] = true; return array($success, $message); }
/** * Creates a client account in the database. * * @param array $account_info this has has 4 required keys: first_name, last_name, user_name, password * * The password is automatically encrypted by this function. * * It also accepts the following optional keys: * account_status: "active", "disabled", "pending" * ui_language: (should only be one of the languages currently supported by the script, e.g. "en_us") * timezone_offset: +- an integer value, for each hour * sessions_timeout: * date_format: * login_page: * logout_url: * theme: * menu_id: * * @return array [0] true / false * [1] an array of error codes (if false) or the new account ID */ function ft_api_create_client_account($account_info) { global $g_api_debug, $g_table_prefix; $account_info = ft_sanitize($account_info); $error_codes = array(); // check all the valid fields if (!isset($account_info["first_name"]) || empty($account_info["first_name"])) { $error_codes[] = 700; } if (!isset($account_info["last_name"]) || empty($account_info["last_name"])) { $error_codes[] = 701; } if (!isset($account_info["email"]) || empty($account_info["email"])) { $error_codes[] = 702; } if (!ft_is_valid_email($account_info["email"])) { $error_codes[] = 703; } if (!isset($account_info["username"]) || empty($account_info["username"])) { $error_codes[] = 704; } else { if (preg_match('/[^A-Za-z0-9]/', $account_info["username"])) { $error_codes[] = 705; } if (!_ft_is_valid_username($account_info["username"])) { $error_codes[] = 706; } } if (!isset($account_info["password"]) || empty($account_info["password"])) { $error_codes[] = 707; } else { if (preg_match('/[^A-Za-z0-9]/', $account_info["password"])) { $error_codes[] = 708; } } if (!empty($error_codes)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_codes" => $error_codes); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, $error_codes); } } $first_name = $account_info["first_name"]; $last_name = $account_info["last_name"]; $email = $account_info["email"]; $username = $account_info["username"]; $password = md5(md5($account_info["password"])); $settings = ft_get_settings(); $account_status = isset($account_info["account_status"]) ? $account_info["account_status"] : "pending"; $language = isset($account_info["ui_language"]) ? $account_info["ui_language"] : $settings["default_language"]; $timezone_offset = isset($account_info["timezone_offset"]) ? $account_info["timezone_offset"] : $settings["default_timezone_offset"]; $sessions_timeout = isset($account_info["sessions_timeout"]) ? $account_info["sessions_timeout"] : $settings["default_sessions_timeout"]; $date_format = isset($account_info["date_format"]) ? $account_info["date_format"] : $settings["default_date_format"]; $login_page = isset($account_info["login_page"]) ? $account_info["login_page"] : $settings["default_login_page"]; $logout_url = isset($account_info["logout_url"]) ? $account_info["logout_url"] : $settings["default_logout_url"]; $theme = isset($account_info["theme"]) ? $account_info["theme"] : $settings["default_theme"]; $menu_id = isset($account_info["menu_id"]) ? $account_info["menu_id"] : $settings["default_client_menu_id"]; // first, insert the record into the accounts table. This contains all the settings common to ALL // accounts (including the administrator and any other future account types) $query = "\n INSERT INTO {$g_table_prefix}accounts (account_type, account_status, ui_language, timezone_offset, sessions_timeout,\n date_format, login_page, logout_url, theme, menu_id, first_name, last_name, email, username, password)\n VALUES ('client', '{$account_status}', '{$language}', '{$timezone_offset}', '{$sessions_timeout}',\n '{$date_format}', '{$login_page}', '{$logout_url}', '{$theme}', {$menu_id}, '{$first_name}', '{$last_name}', '{$email}',\n '{$username}', '{$password}')\n "; if (!mysql_query($query)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 709, "error_type" => "user", "debugging" => "Failed query in <b>" . __FUNCTION__ . "</b>: <i>{$query}</i> " . mysql_error()); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, $error_codes); } } $new_user_id = mysql_insert_id(); // now create all the custom client account settings, most of which are based on the default values // in the settings table $account_settings = array("client_notes" => "", "company_name" => "", "page_titles" => $settings["default_page_titles"], "footer_text" => $settings["default_footer_text"], "may_edit_page_titles" => $settings["clients_may_edit_page_titles"], "may_edit_footer_text" => $settings["clients_may_edit_footer_text"], "may_edit_theme" => $settings["clients_may_edit_theme"], "may_edit_logout_url" => $settings["clients_may_edit_logout_url"], "may_edit_language" => $settings["clients_may_edit_ui_language"], "may_edit_timezone_offset" => $settings["clients_may_edit_timezone_offset"], "may_edit_sessions_timeout" => $settings["clients_may_edit_sessions_timeout"], "may_edit_date_format" => $settings["clients_may_edit_date_format"]); ft_set_account_settings($new_user_id, $account_settings); return array(true, $new_user_id); }
/** * Loads a theme opening page for a module. This should be used loaded for every page in a * module. It serves the same function as ft_display_page, except that it sets the appropriate root * folder for the module and loads the * * @param array $page_vars a hash of information to display / provide to the template. * @param string $theme */ function ft_display_module_page($template, $page_vars = array(), $theme = "", $swatch = "") { global $g_root_dir, $g_root_url, $g_success, $g_message, $g_link, $g_smarty_debug, $g_language, $LANG, $g_smarty, $L, $g_smarty_use_sub_dirs, $g_js_debug, $g_benchmark_start, $g_enable_benchmarking, $g_hide_upgrade_link; $module_folder = _ft_get_current_module_folder(); // $module_id = ft_get_module_id_from_module_folder($module_folder); $default_module_language = "en_us"; if (empty($theme) && isset($_SESSION["ft"]["account"]["theme"])) { $theme = $_SESSION["ft"]["account"]["theme"]; $swatch = isset($_SESSION["ft"]["account"]["swatch"]) ? $_SESSION["ft"]["account"]["swatch"] : ""; } elseif (empty($theme)) { $settings = ft_get_settings(array("default_theme", "default_client_swatch")); $theme = $settings["default_theme"]; $swatch = $settings["default_client_swatch"]; } if (!isset($_SESSION["ft"]["account"]["is_logged_in"])) { $_SESSION["ft"]["account"]["is_logged_in"] = false; } if (!isset($_SESSION["ft"]["account"]["account_type"])) { $_SESSION["ft"]["account"]["account_type"] = ""; } // common variables. These are sent to EVERY template $g_smarty->template_dir = "{$g_root_dir}/themes/{$theme}"; $g_smarty->compile_dir = "{$g_root_dir}/themes/{$theme}/cache/"; $g_smarty->use_sub_dirs = $g_smarty_use_sub_dirs; $g_smarty->assign("LANG", $LANG); // this contains the custom language content of the module, in the language required. It's populated by // ft_init_module_page(), called on every module page $g_smarty->assign("L", $L); $g_smarty->assign("SESSION", $_SESSION["ft"]); $settings = isset($_SESSION["ft"]["settings"]) ? $_SESSION["ft"]["settings"] : array(); $g_smarty->assign("settings", $settings); $g_smarty->assign("account", $_SESSION["ft"]["account"]); $g_smarty->assign("g_root_dir", $g_root_dir); $g_smarty->assign("g_root_url", $g_root_url); $g_smarty->assign("g_js_debug", $g_js_debug ? "true" : "false"); $g_smarty->assign("g_hide_upgrade_link", $g_hide_upgrade_link); $g_smarty->assign("same_page", ft_get_clean_php_self()); $g_smarty->assign("query_string", $_SERVER["QUERY_STRING"]); // TODO FIX $g_smarty->assign("dir", $LANG["special_text_direction"]); $g_smarty->assign("g_enable_benchmarking", $g_enable_benchmarking); $g_smarty->assign("swatch", $swatch); // if this page has been told to dislay a custom message, override g_success and g_message if (isset($_GET["message"])) { list($g_success, $g_message) = ft_display_custom_page_message($_GET["message"]); } $g_smarty->assign("g_success", $g_success); $g_smarty->assign("g_message", $g_message); $module_id = ft_get_module_id_from_module_folder($module_folder); $module_nav = ft_get_module_menu_items($module_id, $module_folder); $g_smarty->assign("module_nav", $module_nav); // if there's no module title, display the module name. TODO not compatible with languages... if (!isset($page_vars["head_title"])) { $module_id = ft_get_module_id_from_module_folder($module_folder); $module_info = ft_get_module($module_id); $page_vars["head_title"] = $module_info["module_name"]; } // check the "required" vars are at least set so they don't produce warnings when smarty debug is enabled if (!isset($page_vars["head_css"])) { $page_vars["head_css"] = ""; } if (!isset($page_vars["head_js"])) { $page_vars["head_js"] = ""; } if (!isset($page_vars["page"])) { $page_vars["page"] = ""; } // if we need to include custom JS messages in the page, add it to the generated JS. Note: even if the js_messages // key is defined but still empty, the ft_generate_js_messages function is called, returning the "base" JS - like // the JS version of g_root_url. Only if it is not defined will that info not be included. This feature was hacked // in 2.1 to support js_messages from a single module file $js_messages = ""; if (isset($page_vars["js_messages"]) || isset($page_vars["module_js_messages"])) { $core_js_messages = isset($page_vars["js_messages"]) ? $page_vars["js_messages"] : ""; $module_js_messages = isset($page_vars["module_js_messages"]) ? $page_vars["module_js_messages"] : ""; $js_messages = ft_generate_js_messages($core_js_messages, $module_js_messages); } if (!empty($page_vars["head_js"]) || !empty($js_messages)) { $page_vars["head_js"] = "<script type=\"text/javascript\">\n//<![CDATA[\n{$page_vars["head_js"]}\n{$js_messages}\n//]]>\n</script>"; } if (!isset($page_vars["head_css"])) { $page_vars["head_css"] = ""; } else { if (!empty($page_vars["head_css"])) { $page_vars["head_css"] = "<style type=\"text/css\">\n{$page_vars["head_css"]}\n</style>"; } } // theme-specific vars $g_smarty->assign("images_url", "{$g_root_url}/themes/{$theme}/images"); $g_smarty->assign("theme_url", "{$g_root_url}/themes/{$theme}"); $g_smarty->assign("theme_dir", "{$g_root_dir}/themes/{$theme}"); // if there's a Smarty folder, import any of its resources if (is_dir("{$g_root_dir}/modules/{$module_folder}/smarty")) { $g_smarty->plugins_dir[] = "{$g_root_dir}/modules/{$module_folder}/smarty"; } // now add the custom variables for this template, as defined in $page_vars foreach ($page_vars as $key => $value) { $g_smarty->assign($key, $value); } // if smarty debug is on, enable Smarty debugging if ($g_smarty_debug) { $g_smarty->debugging = true; } extract(ft_process_hook_calls("main", compact("g_smarty", "template", "page_vars"), array("g_smarty")), EXTR_OVERWRITE); $g_smarty->display("{$g_root_dir}/modules/{$module_folder}/{$template}"); ft_db_disconnect($g_link); }
<?php $sortable_id = "edit_fields"; if (isset($request["update_fields"])) { $request["sortable_id"] = $sortable_id; list($g_success, $g_message) = ft_update_form_fields_tab($form_id, $request); } $form_info = ft_get_form($form_id); if (isset($request["num_fields_per_page"])) { $num_fields_per_page = $request["num_fields_per_page"]; ft_set_settings(array("admin_num_fields_per_page_{$form_id}" => $request["num_fields_per_page"])); $_GET["fields_page"] = 1; } else { $saved_num_fields_per_page = ft_get_settings("admin_num_fields_per_page_{$form_id}"); $num_fields_per_page = !empty($saved_num_fields_per_page) ? $saved_num_fields_per_page : "all"; } if (empty($num_fields_per_page)) { ft_set_settings("admin_num_fields_per_page_{$form_id}", "all"); } $fields_page = ft_load_field("fields_page", "fields_page", 1); $form_fields = ft_get_form_fields($form_id, array("page" => $fields_page, "num_fields_per_page" => $num_fields_per_page)); $total_form_fields = ft_get_num_form_fields($form_id); $reserved_words = ft_get_mysql_reserved_words(); $escaped_words = array(); foreach ($reserved_words as $word) { $escaped_words[] = "\"{$word}\""; } $reserved_words = implode(",", $escaped_words); $field_type_sizes_js = ft_generate_field_type_sizes_map_js(); $field_sizes_js = ft_generate_field_type_size_labels(); $field_settings_js = ft_generate_field_type_settings_js();
/** * Called by administrators; updates the content stored on the "Fields" tab in the Edit Form pages. * * @param integer $form_id the unique form ID * @param array $infohash a hash containing the contents of the Edit Form Display tab * @return array returns array with indexes:<br/> * [0]: true/false (success / failure)<br/> * [1]: message string<br/> */ function ft_update_form_fields_tab($form_id, $infohash) { global $g_table_prefix, $g_root_url, $g_root_dir, $g_debug, $LANG, $g_field_sizes; $success = true; $message = $LANG["notify_field_changes_saved"]; $infohash = ft_sanitize($infohash); extract(ft_process_hook_calls("start", compact("infohash", "form_id"), array("infohash")), EXTR_OVERWRITE); // stores the cleaned-up version of the POST content $field_info = array(); $sortable_id = $infohash["sortable_id"]; $field_ids = explode(",", $infohash["{$sortable_id}_sortable__rows"]); $order = $infohash["sortable_row_offset"]; $new_sort_groups = explode(",", $infohash["{$sortable_id}_sortable__new_groups"]); foreach ($field_ids as $field_id) { $is_new_field = preg_match("/^NEW/", $field_id) ? true : false; $display_name = isset($infohash["field_{$field_id}_display_name"]) ? $infohash["field_{$field_id}_display_name"] : ""; $form_field_name = isset($infohash["field_{$field_id}_name"]) ? $infohash["field_{$field_id}_name"] : ""; $include_on_redirect = isset($infohash["field_{$field_id}_include_on_redirect"]) ? "yes" : "no"; $field_size = isset($infohash["field_{$field_id}_size"]) ? $infohash["field_{$field_id}_size"] : ""; $col_name = isset($infohash["col_{$field_id}_name"]) ? $infohash["col_{$field_id}_name"] : ""; $old_field_size = isset($infohash["old_field_{$field_id}_size"]) ? $infohash["old_field_{$field_id}_size"] : ""; $old_col_name = isset($infohash["old_col_{$field_id}_name"]) ? $infohash["old_col_{$field_id}_name"] : ""; $is_system_field = in_array($field_id, $infohash["system_fields"]) ? "yes" : "no"; // this is only sent for non-system fields $field_type_id = isset($infohash["field_{$field_id}_type_id"]) ? $infohash["field_{$field_id}_type_id"] : ""; // won't be defined for new fields $old_field_type_id = isset($infohash["old_field_{$field_id}_type_id"]) ? $infohash["old_field_{$field_id}_type_id"] : ""; $field_info[] = array("is_new_field" => $is_new_field, "field_id" => $field_id, "display_name" => $display_name, "form_field_name" => $form_field_name, "field_type_id" => $field_type_id, "old_field_type_id" => $old_field_type_id, "include_on_redirect" => $include_on_redirect, "is_system_field" => $is_system_field, "list_order" => $order, "is_new_sort_group" => in_array($field_id, $new_sort_groups) ? "yes" : "no", "col_name" => $col_name, "old_col_name" => $old_col_name, "col_name_changed" => $col_name != $old_col_name ? "yes" : "no", "field_size" => $field_size, "old_field_size" => $old_field_size, "field_size_changed" => $field_size != $old_field_size ? "yes" : "no"); $order++; } reset($infohash); // delete any extended field settings for those fields whose field type just changed. Two comments: // 1. this is compatible with editing the fields in the dialog window. When that happens & the user updates // it, the code updates the old_field_type_id info in the page so this is never called. // 2. with the addition of Shared Characteristics, this only deletes fields that aren't mapped between the // two fields types (old and new) $changed_fields = array(); foreach ($field_info as $curr_field_info) { if ($curr_field_info["is_new_field"] || $curr_field_info["is_system_field"] == "yes" || $curr_field_info["field_type_id"] == $curr_field_info["old_field_type_id"]) { continue; } $changed_fields[] = $curr_field_info; } if (!empty($changed_fields)) { $field_type_settings_shared_characteristics = ft_get_settings("field_type_settings_shared_characteristics"); $field_type_map = ft_get_field_type_id_to_identifier(); $shared_settings = array(); foreach ($changed_fields as $changed_field_info) { $field_id = $changed_field_info["field_id"]; $shared_settings[] = ft_get_shared_field_setting_info($field_type_map, $field_type_settings_shared_characteristics, $field_id, $changed_field_info["field_type_id"], $changed_field_info["old_field_type_id"]); ft_delete_extended_field_settings($field_id); ft_delete_field_validation($field_id); } foreach ($shared_settings as $setting) { foreach ($setting as $setting_info) { $field_id = $setting_info["field_id"]; $setting_id = $setting_info["new_setting_id"]; $setting_value = ft_sanitize($setting_info["setting_value"]); mysql_query("\n INSERT INTO {$g_table_prefix}field_settings (field_id, setting_id, setting_value)\n VALUES ({$field_id}, {$setting_id}, '{$setting_value}')\n "); } } } // the database column name and size field both affect the form's actual database table structure. If either // of those changed, we need to update the database $db_col_changes = array(); $db_col_change_hash = array(); // added later. Could use refactoring... $table_name = "{$g_table_prefix}form_{$form_id}"; foreach ($field_info as $curr_field_info) { if ($curr_field_info["col_name_changed"] == "no" && $curr_field_info["field_size_changed"] == "no") { continue; } if ($curr_field_info["is_new_field"]) { continue; } $field_id = $curr_field_info["field_id"]; $old_col_name = $curr_field_info["old_col_name"]; $new_col_name = $curr_field_info["col_name"]; $new_field_size = $curr_field_info["field_size"]; $new_field_size_sql = $g_field_sizes[$new_field_size]["sql"]; list($is_success, $err_message) = _ft_alter_table_column($table_name, $old_col_name, $new_col_name, $new_field_size_sql); if ($is_success) { $db_col_changes[$field_id] = array("col_name" => $new_col_name, "field_size" => $new_field_size); } else { // if there have already been successful database column name changes already made, // update the database. This helps prevent things getting out of whack if (!empty($db_col_changes)) { while (list($field_id, $changes) = each($db_col_changes)) { $col_name = $changes["col_name"]; $field_size = $changes["field_size"]; @mysql_query("\n UPDATE {$g_table_prefix}form_fields\n SET col_name = '{$col_name}',\n field_size = '{$field_size}'\n WHERE field_id = {$field_id}\n "); } } $message = $LANG["validation_db_not_updated_invalid_input"]; if ($g_debug) { $message .= " \"{$err_message}\""; } return array(false, $message); } } // now update the fields, and, if need be, the form's database table foreach ($field_info as $field) { if ($field["is_new_field"]) { continue; } $field_id = $field["field_id"]; $display_name = $field["display_name"]; $field_name = $field["form_field_name"]; $field_type_id = $field["field_type_id"]; $include_on_redirect = $field["include_on_redirect"]; $is_system_field = $field["is_system_field"]; $field_size = $field["field_size"]; $col_name = $field["col_name"]; $list_order = $field["list_order"]; $is_new_sort_group = $field["is_new_sort_group"]; if ($is_system_field == "yes") { $query = "\n UPDATE {$g_table_prefix}form_fields\n SET field_title = '{$display_name}',\n include_on_redirect = '{$include_on_redirect}',\n list_order = {$list_order},\n is_new_sort_group = '{$is_new_sort_group}'\n WHERE field_id = {$field_id}\n "; } else { $query = "\n UPDATE {$g_table_prefix}form_fields\n SET field_name = '{$field_name}',\n field_title = '{$display_name}',\n field_size = '{$field_size}',\n col_name = '{$col_name}',\n field_type_id = '{$field_type_id}',\n include_on_redirect = '{$include_on_redirect}',\n list_order = {$list_order},\n is_new_sort_group = '{$is_new_sort_group}'\n WHERE field_id = {$field_id}\n "; } mysql_query($query) or ft_handle_error("Failed query in <b>" . __FUNCTION__ . "</b>, line " . __LINE__ . ": <i>{$query}</i>", mysql_error()); } // if any of the database column names just changed we need to update any View filters that relied on them if (!empty($db_col_changes)) { while (list($field_id, $changes) = each($db_col_changes)) { ft_update_field_filters($field_id); } } // okay! now add any new fields that the user just added $new_fields = array(); foreach ($field_info as $curr_field) { if ($curr_field["is_new_field"]) { $new_fields[] = $curr_field; } } if (!empty($new_fields)) { list($is_success, $error) = ft_add_form_fields($form_id, $new_fields); // if there was a problem adding any of the new fields, inform the user if (!$is_success) { $success = false; $message = $error; } } // Lastly, delete the specified fields. Since some field types (e.g. files) may have additional functionality // needed at this stage (e.g. deleting the actual files that had been uploaded via the form). This occurs regardless // of whether the add fields step worked or not $deleted_field_ids = explode(",", $infohash["{$sortable_id}_sortable__deleted_rows"]); extract(ft_process_hook_calls("delete_fields", compact("deleted_field_ids", "infohash", "form_id"), array()), EXTR_OVERWRITE); // now actually delete the fields ft_delete_form_fields($form_id, $deleted_field_ids); extract(ft_process_hook_calls("end", compact("infohash", "field_info", "form_id"), array("success", "message")), EXTR_OVERWRITE); return array($success, $message); }
/** * Returns the current core version, whether it's a Beta or main release. The way Form Tools handles * the release versions was changed in 2.0.3-beta-20100919. Prior to that release, the "program_version" * setting stored the version information. The format changed depending on the release type: * 2.0.0 - example of main build version * 2.0.1-beta-20100931 - example of Beta version * * Now the current version information is stored in 3 fields in the settings table: * "program_version" - JUST the main build info (e.g. 2.0.0) * "release_type" - "alpha", "beta" or "main" * "release_date" - the date in the format YYYYMMDD * * * @return array a hash with the following keys: * "version" => e.g. 2.0.0 * "release_type" => "main" or "beta" * "release_date" => e.g. 20081231 * "full" => e.g. 2.0.0-beta-20081231 or 2.0.3 */ function ft_get_core_version_info() { $settings = ft_get_settings(); $program_version = $settings["program_version"]; // if there's a hyphen in the program version, we know we're dealing with an old beta version if (strpos($program_version, "-") !== false) { $parts = split("-", $program_version); $version_info = array("full" => $program_version, "version" => $parts[0], "release_type" => $parts[1], "release_date" => $parts[2]); } else { if ($program_version == "2.0.0") { $version_info = array("full" => "2.0.0-main-20100101", "version" => "2.0.0", "release_date" => "20100101", "release_type" => "main"); } else { if ($program_version == "2.0.1") { $version_info = array("full" => "2.0.1-main-20100412", "version" => "2.0.1", "release_date" => "20100412", "release_type" => "main"); } else { if ($program_version == "2.0.2") { $version_info = array("full" => "2.0.2-main-20100704", "version" => "2.0.2", "release_date" => "20100704", "release_type" => "main"); } else { // here, there will always be release_date and release_type values in $settings, except // for ONE scenario: when a user is upgrading to that first version. Here, the DB won't have // any values for those fields (release_date, release_type). To get around this, we set the // release date to be the day before: this enables the calling function (ft_upgrade_form_tools) // to just seamlessly upgrade to the new versioning scheme. From there on out, we can rely // on those settings being in the database $release_date = isset($settings["release_date"]) ? $settings["release_date"] : "20100919"; $release_type = isset($settings["release_type"]) ? $settings["release_type"] : "beta"; $version_info = array("full" => "{$program_version}-{$release_type}-{$release_date}", "version" => $program_version, "release_date" => $release_date, "release_type" => $release_type); } } } } return $version_info; }
/** * This is used exclusively on the Edit Forms -> fields tab. It returns a JS version of the shared characteristics * information for use by the page. The JS it returns in an anonymous JS object of the following form: * { * s(setting ID): array(characteristic IDs), * ... * } * * "Characteristic ID" is a made-up number for the sake of the use-case. We just need a way to recognize the shared * characteristics - that's what it does. * * @return string */ function ft_get_field_type_setting_shared_characteristics_js() { $field_type_settings_shared_characteristics = ft_get_settings("field_type_settings_shared_characteristics"); $info = ft_get_field_type_and_setting_info(); $field_type_id_to_identifier = $info["field_type_id_to_identifier"]; $field_identifier_to_id = array_flip($field_type_id_to_identifier); $groups = explode("|", $field_type_settings_shared_characteristics); $return_info = array(); // this is what we're trying to generate: a hash of setting id => array( characteristic IDs ) // The �characteristic ID� is a new (temporary) number for characteristic. In every situation that I can // think of, the value array will contain a single entry (why would a setting be mapped to multiple // characteristics?). However, the interface doesn't limit it. To be safe, I�ll stash it in an array. $setting_ids_to_characteristic_ids = array(); $characteristic_id = 1; foreach ($groups as $group_info) { list($group_name, $vals) = explode(":", $group_info); $pairs = explode("`", $vals); $settings = array(); foreach ($pairs as $str) { // we need to do a little legwork here to actually find the setting ID. The problem is that many // field types reference fields with the same setting identifier (it's only required to be unique within the // field type - not ALL field types). list($field_type_identifier, $setting_identifier) = explode(",", $str); // the shared characteristic settings may reference uninstalled modules if (!array_key_exists($field_type_identifier, $field_identifier_to_id)) { continue; } $field_type_id = $field_identifier_to_id[$field_type_identifier]; $all_field_type_setting_ids = $info["field_type_ids_to_setting_ids"][$field_type_id]; // loop through all the settings for this field type and locate the one we're interested in foreach ($all_field_type_setting_ids as $setting_id) { if ($info["setting_id_to_identifier"][$setting_id] != $setting_identifier) { continue; } if (!array_key_exists($setting_id, $setting_ids_to_characteristic_ids)) { $setting_ids_to_characteristic_ids[$setting_id] = array(); } $setting_ids_to_characteristic_ids[$setting_id][] = $characteristic_id; } } $characteristic_id++; } // now convert the info into a simple JS object. We could have done it above, but this keeps it simple. $js_lines = array(); while (list($setting_id, $characteristic_ids) = each($setting_ids_to_characteristic_ids)) { $js_lines[] = "s{$setting_id}:[" . implode(",", $characteristic_ids) . "]"; } $js = "{" . implode(",", $js_lines) . "}"; return $js; }
/** * ft_get_extended_field_settings() doesn't quite do what I need, so I added this secondary function. It's * similar to ft_get_form_field_field_type_settings(), except for a single field. * * All it does is return all settings for a form field TAKING INTO ACCOUNT what's been overridden. * * Note: it returns the information as a hash of identifier => value pairs. This is fine, because no two field * settings for a single field type may have the same identifier. * * @param $field_id * @return array a hash of [identifier] = values */ function ft_get_field_settings($field_id) { global $g_table_prefix; if (empty($field_id) || !is_numeric($field_id)) { return array(); } // get the overridden settings $query = "\n SELECT fts.field_type_id, fs.field_id, fts.field_setting_identifier, fs.setting_value\n FROM {$g_table_prefix}field_type_settings fts, {$g_table_prefix}field_settings fs\n WHERE fts.setting_id = fs.setting_id AND\n fs.field_id = {$field_id}\n ORDER BY fs.field_id\n "; $result = mysql_query($query); $overridden_settings = array(); while ($row = mysql_fetch_assoc($result)) { $overridden_settings[$row["field_setting_identifier"]] = $row["setting_value"]; } $field_type_id = ft_get_field_type_id_by_field_id($field_id); $default_field_type_settings = ft_get_field_type_settings($field_type_id); // now overlay the two and return all field settings for all fields $complete_settings = array(); foreach ($default_field_type_settings as $setting_info) { $identifier = $setting_info["field_setting_identifier"]; $default_value_type = $setting_info["default_value_type"]; if ($default_value_type == "static") { $value = $setting_info["default_value"]; } else { $parts = explode(",", $setting_info["default_value"]); // dynamic setting values should ALWAYS be of the form "setting_name,module_folder/'core'". If they're // not, just ignore it if (count($parts) != 2) { $value = ""; } else { $value = ft_get_settings($parts[0], $parts[1]); } } // if the field has been overwritten use that instead! if (isset($overridden_settings[$identifier])) { $value = $overridden_settings[$identifier]; } $complete_settings[$identifier] = $value; } return $complete_settings; }
<?php require_once "../../global/library.php"; ft_init_module_page(); // ------------------------------------------------------------------------------------------------ $settings = ft_get_settings(); $core_version = $settings["release_type"] == "beta" ? "{$settings["program_version"]}-beta-{$settings["release_date"]}" : $settings["program_version"]; // --------------------------------------- // *** example for generating config file for a module. Make sure you omit the table prefixes! *** /*$tables = array( "account_settings", "accounts", "client_forms", "client_views", "email_template_edit_submission_views", "email_template_recipients", "email_templates", "field_options", "field_settings", "field_type_setting_options", "field_type_settings", "field_types", "form_email_fields", "form_fields", "forms", "hooks", "list_groups", "menu_items", "menus", "module_js_error_logs", "module_menu_items",
/** * Retrieves one or more settings for a module. This can be used in two ways: * 1. It can be called within any module page WITHOUT the second parameter; it then figures out * what module you're currently on, and returns those setting(s) for that module. * 2. It's called from outside a module folder (or within a different module, trying to access the * settings of another module). In that case, it needs to specify the second $module_folder param. * * To return all settings for the current module, just call the function with no parameters. * * @param mixed $settings a single setting name or an array of setting names * @param string $module_folder * @return mixed a single setting string value or an array of setting values */ function ft_get_module_settings($settings = "", $module_folder = "") { if (empty($module_folder)) { $module_folder = _ft_get_current_module_folder(); } return ft_get_settings($settings, $module_folder); }