/** * This function is tightly coupled with ft_get_email_components and has gotten increasingly more awful as * time passed. It examines the content of an email template and detects any field and file attachments. * Field attachments are files that have been uploaded through a form field; file attachments are just files * on the server that want to be sent out. It then returns the updated email template (i.e. minus the * attachment string) and information about the attachment (file name, location, mimetype) for use by the * emailing function (only Swift Mailer module at this time). * * @param string $template_str the email template (HTML or text) * @param integer $form_id * @param array $submission_placeholders */ function _ft_extract_email_attachment_info($template_str, $form_id, $submission_placeholders) { global $g_root_dir; // see if there are any filename placeholders (i.e. uploaded files in this submission) $file_field_name_to_filename_hash = array(); while (list($placeholder, $value) = each($submission_placeholders)) { if (!preg_match("/^FILENAME_/", $placeholder)) { continue; } $field_name = preg_replace("/^FILENAME_/", "", $placeholder); $file_field_name_to_filename_hash[$field_name] = $value; } $attachment_info = array(); if (!empty($file_field_name_to_filename_hash)) { // if there are any fields marked as attachments, store them and remove the attachment string $field_attachments_regexp = '/\\{\\$attachment\\s+field=("|\')(.+)("|\')\\}/'; if (preg_match_all($field_attachments_regexp, $template_str, $matches)) { foreach ($matches[2] as $field_name) { $field_id = ft_get_form_field_id_by_field_name($field_name, $form_id); if (!empty($field_name) && array_key_exists($field_name, $file_field_name_to_filename_hash)) { $field_settings = ft_get_field_settings($field_id); $file_upload_dir = $field_settings["folder_path"]; $file_and_path = "{$file_upload_dir}/{$file_field_name_to_filename_hash[$field_name]}"; if (is_file($file_and_path)) { $info = array("field_name" => $field_name, "file_and_path" => $file_and_path, "filename" => $file_field_name_to_filename_hash[$field_name], "mimetype" => mime_content_type($file_and_path)); $attachment_info[] = $info; } } } $template_str = preg_replace($field_attachments_regexp, "", $template_str); } } $file_attachments_regexp = '/\\{\\$attachment\\s+file=("|\')(.+)("|\')\\}/'; if (preg_match_all($file_attachments_regexp, $template_str, $matches)) { foreach ($matches[2] as $file_and_relative_path) { if (is_file("{$g_root_dir}/{$file_and_relative_path}")) { $pathinfo = pathinfo($file_and_relative_path); $file_name = $pathinfo["basename"]; $info = array("file_and_path" => "{$g_root_dir}/{$file_and_relative_path}", "filename" => $file_name); $attachment_info[] = $info; } } $template_str = preg_replace($file_attachments_regexp, "", $template_str); } $file_attachments_regexp = '/\\{\\$attachment\\s+fieldvalue=("|\')(.+)("|\')\\}/'; if (preg_match_all($file_attachments_regexp, $template_str, $matches)) { foreach ($matches[2] as $file_and_relative_path) { $file_and_relative_path = ft_eval_smarty_string("{\$" . $file_and_relative_path . "}", $submission_placeholders); if (is_file("{$g_root_dir}/{$file_and_relative_path}")) { $pathinfo = pathinfo($file_and_relative_path); $file_name = $pathinfo["basename"]; $info = array("file_and_path" => "{$g_root_dir}/{$file_and_relative_path}", "filename" => $file_name); $attachment_info[] = $info; } } $template_str = preg_replace($file_attachments_regexp, "", $template_str); } return array($template_str, $attachment_info); }
/** * Processes a form submission, either for a single page of a multi-page form or the entire form itself. If the * "submit_button_name key exists in $params (i.e. if the user just submitted the form), it updates the database for * the submission ID. * * Assumption: the ft_api_init_form_page function has been called on the page prior to calling this function. * * @param array $params * * Required keys: * "submit_button": the "name" attribute value of the form submit button * "form_data": the contents of $_POST (or $_GET, if "method" setting is set to "GET" ... ) * "file_data": the contents of $_FILES (only needed if your form contained file fields) * * Optional keys: * "next_page": the URL (relative or absolute) of which page to redirect to (e.g. the next page * in the form or the "thankyou" page). * "finalize": this tells the function to finalize the submission. This prevents it being subsequently * editable via this function and makes the submission appear in the Form Tools UI. * "no_sessions_url": for multi-page forms it's a good idea to pass along this value. It should be the URL * of a page (usually the FIRST page in the form sequence) where the user will be redirected to if * they didn't start the form from the first page. It ensures the form submission gets created & * submitted properly. * "may_update_finalized_submissions": true / false (true by default) * "namespace": if you specified a custom namespace for ft_api_init_form_page, for where the form values will * be stored temporarily in sessions, you need to pass that same value to this function - otherwise * it won't be able to retrieve the form and submission ID * "send_emails": (boolean). By default, Form Tools will trigger any emails that have been attached to the * "on submission" event ONLY when the submission is finalized (finalize=true). This setting provides * you with direct control over when the emails get sent. If not specified, will use the default * behaviour. * * @return mixed ordinarily, this function will just redirect the user to whatever URL is specified in the * "next_page" key. But if that value isn't set, it returns an array: * [0] success / false * [1] if failure, the API Error Code, otherwise blank */ function ft_api_process_form($params) { global $g_table_prefix, $g_multi_val_delimiter, $LANG, $g_api_debug, $g_api_recaptcha_private_key, $g_api_recaptcha_error; // the form data parameter must ALWAYS be defined if (!isset($params["form_data"])) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 306, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 306); } } // special case: if "form_tools_delete_image_field__[fieldname]" exists, the user is just deleting an image // already uploaded through the form using the HTML generated by the ft_api_display_image_field function. // In this case, we process the page normally - even though the form data wasn't submitted & the page may // contain nothing in $form_data $is_deleting_file = false; $file_field_to_delete = ""; $namespace = isset($params["namespace"]) ? $params["namespace"] : "form_tools_form"; $form_id = isset($_SESSION[$namespace]["form_tools_form_id"]) ? $_SESSION[$namespace]["form_tools_form_id"] : ""; $submission_id = isset($_SESSION[$namespace]["form_tools_submission_id"]) ? $_SESSION[$namespace]["form_tools_submission_id"] : ""; while (list($key, $value) = each($params["form_data"])) { if (preg_match("/form_tools_delete_image_field__(.*)\$/", $key, $matches)) { $file_field_to_delete = $matches[1]; $is_deleting_file = true; $field_id = ft_get_form_field_id_by_field_name($file_field_to_delete, $form_id); ft_delete_file_submission($form_id, $submission_id, $field_id, true); unset($_SESSION[$namespace][$file_field_to_delete]); unset($params["form_data"][$key]); } } // check the submission exists if (is_numeric($form_id) && is_numeric($submission_id) && !ft_check_submission_exists($form_id, $submission_id)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 305, "error_type" => "user", "debugging" => "{$LANG["phrase_submission_id"]}: {$submission_id}"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 305); } } // extract the submission ID and form ID from sessions $form_data = $params["form_data"]; $form_id = isset($_SESSION[$namespace]["form_tools_form_id"]) ? $_SESSION[$namespace]["form_tools_form_id"] : ""; $submission_id = isset($_SESSION[$namespace]["form_tools_submission_id"]) ? $_SESSION[$namespace]["form_tools_submission_id"] : ""; $has_captcha = isset($form_data["recaptcha_response_field"]) ? true : false; $no_sessions_url = isset($params["no_sessions_url"]) ? $params["no_sessions_url"] : false; if (!isset($_GET["ft_sessions_url_override"]) && (empty($form_id) || empty($submission_id))) { if (!empty($no_sessions_url)) { header("location: {$no_sessions_url}"); exit; } else { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 300, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 300); } } } // if the user is neither deleting a file or making a regular form submission, it means they've just // arrived at the page. Cool! Do nothing! if (!$is_deleting_file && !isset($params["form_data"][$params["submit_button"]])) { return; } $submit_button_name = $params["submit_button"]; $next_page = isset($params["next_page"]) ? $params["next_page"] : ""; $file_data = isset($params["file_data"]) ? $params["file_data"] : array(); $finalize = isset($params["finalize"]) ? $params["finalize"] : false; $namespace = isset($params["namespace"]) ? $params["namespace"] : "form_tools_form"; $may_update_finalized_submissions = isset($params["may_update_finalized_submissions"]) ? $params["may_update_finalized_submissions"] : true; // if we're in test mode, we don't do anything with the database - just store the fields in // sessions to emulate if ($form_id == "test" || $submission_id == "test") { reset($form_data); while (list($field_name, $value) = each($form_data)) { $_SESSION[$namespace][$field_name] = $value; } } else { if (isset($_SESSION[$namespace]["form_tools_initialize_form"])) { // only process the form if this submission is being set to be finalized if ($finalize) { // if the user is just putting through a test submission and we've reached the finalization step, // overwrite $form_data with ALL the $all_form_data = array_merge($_SESSION[$namespace], $form_data); ft_initialize_form($all_form_data); } reset($form_data); while (list($field_name, $value) = each($form_data)) { $_SESSION[$namespace][$field_name] = $value; } } else { // check the form ID is valid if (!ft_check_form_exists($form_id)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 301, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 301); } } // check the submission ID isn't finalized if (!$may_update_finalized_submissions && ft_check_submission_finalized($form_id, $submission_id)) { if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 302, "error_type" => "user", "debugging" => "{$LANG["phrase_submission_id"]}: {$submission_id}"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 302); } } $form_info = ft_get_form($form_id); // 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; } if ($g_api_debug) { $page_vars = array("message_type" => "error", "error_code" => 303, "error_type" => "user"); ft_display_page("error.tpl", $page_vars); exit; } else { return array(false, 303); } } // now we sanitize the data (i.e. get it ready for the DB query) $form_data = ft_sanitize($form_data); extract(ft_process_hook_calls("start", compact("form_info", "form_id", "form_data"), array("form_data")), EXTR_OVERWRITE); // 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 (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"]; $is_finalized = $finalize ? "yes" : "no"; $set_query = ""; while (list($col_name, $value) = each($valid_form_fields)) { $set_query .= "{$col_name} = {$value},\n"; } // in this section, we update the database submission info & upload files. Note: we don't do ANYTHING // if the form_tools_ignore_submission key is set in the POST data if (!isset($form_data["form_tools_ignore_submission"])) { // construct our query. Note that we do TWO queries: one if there was no CAPTCHA sent with this // post (which automatically finalizes the result), and one if there WAS. For the latter, the submission // is finalized later if ($has_captcha && $finalize) { $query = "\n UPDATE {$g_table_prefix}form_{$form_id}\n SET {$set_query}\n last_modified_date = '{$now}',\n ip_address = '{$ip_address}'\n WHERE submission_id = {$submission_id}\n "; } else { // only update the is_finalized setting if $may_update_finalized_submissions === false if (!$finalize && $may_update_finalized_submissions) { $is_finalized_clause = ""; } else { $is_finalized_clause = ", is_finalized = '{$is_finalized}'"; } $query = "\n UPDATE {$g_table_prefix}form_{$form_id}\n SET {$set_query}\n last_modified_date = '{$now}',\n ip_address = '{$ip_address}'\n {$is_finalized_clause}\n WHERE submission_id = {$submission_id}\n "; } // only process the query if the form_tools_ignore_submission key isn't defined if (!mysql_query($query)) { if ($g_api_debug) { $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; } else { return array(false, 304); } } // used for uploading files. The error handling is incomplete here, like previous versions. Although the hooks // are permitted to return values, they're not used extract(ft_process_hook_calls("manage_files", compact("form_id", "submission_id", "file_fields", "namespace"), array("success", "message")), EXTR_OVERWRITE); } // store all the info in sessions reset($form_data); while (list($field_name, $value) = each($form_data)) { $_SESSION[$namespace][$field_name] = $value; } } } // was there a reCAPTCHA response? If so, a recaptcha was just submitted, check it was entered correctly $passes_captcha = true; if ($has_captcha) { $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}/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; // if the developer wanted the submission to be finalized at this step, do so - it wasn't earlier! if ($finalize) { mysql_query("\n UPDATE {$g_table_prefix}form_{$form_id}\n SET is_finalized = 'yes'\n WHERE submission_id = {$submission_id}\n "); } } else { // register the recaptcha as a global, which can be picked up silently by ft_api_display_captcha to // let them know they entered it wrong $g_api_recaptcha_error = $resp->error; } } if ($passes_captcha && !empty($next_page) && !$is_deleting_file) { // if the user wasn't putting through a test submission or initializing the form, we can send safely // send emails at this juncture, but ONLY if it was just finalized OR if the send_emails parameter // allows for it if ($form_id != "test" && $submission_id != "test" && !isset($_SESSION[$namespace]["form_tools_initialize_form"]) && !isset($form_data["form_tools_ignore_submission"])) { // send any emails attached to the on_submission trigger if (isset($params["send_emails"]) && $params["send_emails"] === true) { ft_send_emails("on_submission", $form_id, $submission_id); } else { if ($is_finalized == "yes" && (!isset($params["send_emails"]) || $params["send_emails"] !== false)) { ft_send_emails("on_submission", $form_id, $submission_id); } } } header("location: {$next_page}"); exit; } return array(true, ""); }