Example #1
0
/**
 * This constructs and sends the email from an individual email template for a single form
 * submission.
 *
 * @param integer $form_id
 * @param integer $submission_id
 * @param integer $email_id
 */
function ft_process_email_template($form_id, $submission_id, $email_id)
{
    list($success, $email_components) = ft_get_email_components($form_id, $submission_id, $email_id);
    if (!$success) {
        return array(false, "Email components not returned properly (ft_get_email_components).");
    }
    extract(ft_process_hook_calls("start", compact("form_id", "submission_id", "email_id", "email_components"), array("email_components")), EXTR_OVERWRITE);
    // if Swift Mailer is enabled, send the emails with that
    $continue = true;
    if (ft_check_module_enabled("swift_mailer")) {
        $sm_settings = ft_get_module_settings("", "swift_mailer");
        if (isset($sm_settings["swiftmailer_enabled"]) && $sm_settings["swiftmailer_enabled"] == "yes") {
            ft_include_module("swift_mailer");
            list($success, $message) = swift_send_email($email_components);
            $continue = false;
        }
    }
    // if it was sent (or was attempted to have been sent) by the Swift Mailer module, stop here
    if (!$continue) {
        return array($success, $message);
    }
    $eol = _ft_get_email_eol_char();
    $recipient_list = array();
    foreach ($email_components["to"] as $to_info) {
        $recipient_list[] = $to_info["recipient_line"];
    }
    $to = join(", ", $recipient_list);
    $to = htmlspecialchars_decode($to);
    if (empty($to)) {
        return array(false, "No main recipient specified.");
    }
    $headers = "MIME-Version: 1.0{$eol}";
    if (!empty($email_components["from"])) {
        $from = htmlspecialchars_decode($email_components["from"]["recipient_line"]);
        $headers .= "From: {$from}{$eol}";
    }
    if (!empty($email_components["reply_to"])) {
        $reply_to = htmlspecialchars_decode($email_components["reply_to"]["recipient_line"]);
        $headers .= "Reply-to: {$reply_to}{$eol}";
    }
    if (!empty($email_components["cc"])) {
        $cc_list = array();
        foreach ($email_components["cc"] as $cc_info) {
            $cc_list[] = $cc_info["recipient_line"];
        }
        $cc = join(", ", $cc_list);
        $cc = htmlspecialchars_decode($cc);
        $headers .= "Cc: {$cc}{$eol}";
    }
    if (!empty($email_components["bcc"])) {
        $bcc_list = array();
        foreach ($email_components["bcc"] as $bcc_info) {
            $bcc_list[] = $bcc_info["recipient_line"];
        }
        $bcc = join(", ", $bcc_list);
        $bcc = htmlspecialchars_decode($bcc);
        $headers .= "Bcc: {$bcc}{$eol}";
    }
    $message = "";
    $html_content = isset($email_components["html_content"]) ? $email_components["html_content"] : "";
    $text_content = isset($email_components["text_content"]) ? $email_components["text_content"] : "";
    $html_content = trim($html_content);
    $text_content = trim($text_content);
    // if there's no TO line or there's no email content for either types, we can't send the email
    if (empty($html_content) && empty($text_content)) {
        return array(false, "No text or HTML email content specified");
    }
    if (!empty($html_content) && !empty($text_content)) {
        $headers .= _ft_get_multipart_message($html_content, $text_content, $eol);
    } else {
        if (!empty($html_content)) {
            $message = $html_content;
            $headers .= "Content-type: text/html; charset=UTF-8";
        } else {
            if (!empty($text_content)) {
                $message = $text_content;
                $headers .= "Content-type: text/plain; charset=UTF-8";
            }
        }
    }
    $subject = $email_components["subject"];
    // send the email
    $email_sent = @mail("{$to}", $subject, $message, $headers);
    if ($email_sent) {
        return array(true, "");
    } else {
        return array(false, "The mail() function failed to send the email.");
    }
}
Example #2
0
/**
 * Builds a dropdown of available pages for a client. This is used by the administrator
 * to display the list of pages available for the clients menus, etc.
 *
 * @param string $selected
 * @param array $attributes
 * @param array $omit_pages
 */
function ft_get_client_menu_pages_dropdown($selected, $attributes, $omit_pages = array())
{
    global $LANG;
    // stores the non-option lines of the select box: <select>, </select> and the optgroups
    $select_lines = array();
    $select_lines[] = array("type" => "select_open");
    if (!in_array("", $omit_pages)) {
        $select_lines[] = array("type" => "option", "v" => $LANG["phrase_please_select"]);
    }
    if (!in_array("custom_url", $omit_pages)) {
        $select_lines[] = array("type" => "optgroup_open", "label" => $LANG["word_custom"]);
        $select_lines[] = array("type" => "option", "k" => "custom_url", "v" => $LANG["phrase_custom_url"]);
        $select_lines[] = array("type" => "optgroup_close");
    }
    $select_lines[] = array("type" => "optgroup_open", "label" => $LANG["word_main"]);
    if (!in_array("client_forms", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "client_forms", "v" => $LANG["word_forms"]);
    }
    if (!in_array("client_form_submissions", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "client_form_submissions", "v" => $LANG["phrase_form_submissions"]);
    }
    if (!in_array("client_account", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "client_account", "v" => $LANG["word_account"]);
    }
    if (!in_array("client_account_login", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "client_account_login", "v" => $LANG["phrase_login_info"]);
    }
    if (!in_array("client_account_settings", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "client_account_settings", "v" => $LANG["phrase_account_settings"]);
    }
    if (!in_array("logout", $omit_pages)) {
        $select_lines[] = array("type" => "option", "k" => "logout", "v" => $LANG["word_logout"]);
    }
    $select_lines[] = array("type" => "optgroup_close");
    // if the Pages module is enabled, display any custom pages that have been defined. Only show the optgroup
    // if there's at least ONE page defined
    if (ft_check_module_enabled("pages")) {
        ft_include_module("pages");
        $pages_info = pg_get_pages("all");
        $pages = $pages_info["results"];
        if (count($pages) > 0) {
            $select_lines[] = array("type" => "optgroup_open", "label" => $LANG["phrase_pages_module"]);
            foreach ($pages as $page) {
                $page_id = $page["page_id"];
                $page_name = $page["page_name"];
                $select_lines[] = array("type" => "option", "k" => "page_{$page_id}", "v" => $page_name);
            }
            $select_lines[] = array("type" => "optgroup_close");
        }
    }
    extract(ft_process_hook_calls("middle", compact("select_lines"), array("select_lines")), EXTR_OVERWRITE);
    $select_lines[] = array("type" => "select_close");
    // now build the HTML
    $dd = "";
    foreach ($select_lines as $line) {
        switch ($line["type"]) {
            case "select_open":
                $attribute_str = "";
                while (list($key, $value) = each($attributes)) {
                    $attribute_str .= " {$key}=\"{$value}\"";
                }
                $dd .= "<select {$attribute_str}>";
                break;
            case "select_close":
                $dd .= "</select>";
                break;
            case "optgroup_open":
                $dd .= "<optgroup label=\"{$line["label"]}\">";
                break;
            case "optgroup_close":
                $dd .= "</optgroup>";
                break;
            case "option":
                $key = $line["k"];
                $value = $line["v"];
                $dd .= "<option value=\"{$key}\"" . ($selected == $key ? " selected" : "") . ">{$value}</option>\n";
                break;
        }
    }
    return $dd;
}
Example #3
0
/**
 * This processes all template hooks for a particular template location (e.g. edit client page, at the top).
 * It works similarly to the ft_process_hooks function, except there are no options to override values in the
 * template. This is used purely to insert content into the templates.
 *
 * @param string $location
 * @param array an array of all variables currently in the template
 * @param array in most cases, template hooks just contain the single "location" parameter which identifies
 *     where the hook is from. But hooks may also contain any additional rbitrary attribute names. This
 *     param contains all of them.
 */
function ft_process_template_hook_calls($location, $template_vars, $all_params = array())
{
    $hooks = ft_get_hook_calls($location, "template", "");
    // extract the var passed from the calling function into the current scope
    foreach ($hooks as $hook_info) {
        $module_folder = $hook_info["module_folder"];
        if (!ft_check_module_enabled($module_folder)) {
            continue;
        }
        // add the hook info to the $template_vars for access by the hooked function. N.B. the "form_tools_"
        // prefix was added to reduce the likelihood of naming conflicts with variables in any Form Tools page
        $template_vars["form_tools_hook_info"] = $hook_info;
        ft_process_template_hook_call($hook_info["module_folder"], $hook_info["hook_function"], $location, $template_vars, $all_params);
    }
}
Example #4
0
/**
 * 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);
}
Example #5
0
/**
 * This function lets you display the content generated from an export type into a webpage. You can
 * use this function on any export type in the database - even the ones that have been marked as "hidden". Note:
 * this function requires the Export Manager to be installed and enabled.
 *
 * @param integer $form_id
 * @param integer $view_id
 * @param integer $export_type_id
 * @param integer $page_num (defaults to 1)
 * @param array $options optional parameter that lets you configure the appearance of the data in a variety of ways.
 *
 *         num_per_page              - (integer) by default, it returns the number of results per page specified by
 *                                     the View. This setting overrides that.
 *         submission_ids            - (integer or array of integers) this limits the results returned to the submission ID
 *                                     or submission IDs specified in this field
 *         order                     - (string) the database column name with a -DESC or -ASC suffix (e.g. col_1-ASC).
 *         page_num_identifier       - (string) passed via the query string to denote what page it's on (default: "page")
 *         show_columns_only         - (boolean) limits the fields that are displayed to those fields marked as "Column"
 *                                     in the View. Defaults to false.
 *         return_as_string          - (boolean) if this value is set to true, instead of outputting the result it returns
 *                                     the HTML as a string.
 *         pagination_theme          - (string) the pagination links (<< 1 2 3 ...) HTML is generated by the pagination.tpl
 *                                     template, found in each of the theme folders. Generally this file is the same for
 *                                     all themes, but in case it isn't, this setting lets you choose the theme folder with
 *                                     which to render the HTML.
 *         pagination_location       - (string) accepts the values "top" (the default), "bottom", "both" or "none". This
 *                                     determines where (if anywhere) the pagination links should appear. By default it only
 *                                     appears at the top of the page, but you can set this value to either "both" or "bottom"
 *                                     to have it appear there instead / as well.
 *
 * @return mixed the return value of this function depends on the API settings & the options passed to it. Namely:
 *
 *     If error:
 *        if $g_api_debug == true, the error page will be displayed displaying the error code.
 *        if $g_api_debug == false, it returns an array with two indexes:
 *                   [0] false
 *                   [1] the API error code
 *     If successful:
 *        if "return_as_string" option key is set, it returns an array with two indexes:
 *                   [0] true
 *                   [1] the HTML content
 *        if "return_as_string" not set, it just prints the HTML to the page (the default behaviour)
 */
function ft_api_show_submissions($form_id, $view_id, $export_type_id, $page_num = 1, $options = array())
{
    global $g_table_prefix, $LANG, $g_api_debug, $g_smarty;
    // sanitize all incoming data
    $form_id = ft_sanitize($form_id);
    $view_id = ft_sanitize($view_id);
    $export_type_id = ft_sanitize($export_type_id);
    $page_num = ft_sanitize($page_num);
    $options = ft_sanitize($options);
    // check the Export Manager module is enabled
    if (ft_check_module_enabled("export_manager")) {
        ft_include_module("export_manager");
    } else {
        if ($g_api_debug) {
            $page_vars = array("message_type" => "error", "error_code" => 400, "error_type" => "user");
            ft_display_page("error.tpl", $page_vars);
            exit;
        } else {
            return array(false, 400);
        }
    }
    // check the form ID, View ID and export ID are valid
    $form_query = mysql_query("SELECT count(*) as c FROM {$g_table_prefix}forms WHERE form_id = {$form_id}");
    $result = mysql_fetch_assoc($form_query);
    $form_found = $result["c"] == 1 ? true : false;
    if (!$form_found) {
        if ($g_api_debug) {
            $page_vars = array("message_type" => "error", "error_code" => 401, "error_type" => "user");
            ft_display_page("error.tpl", $page_vars);
            exit;
        } else {
            return array(false, 401);
        }
    }
    $view_query = mysql_query("SELECT count(*) as c FROM {$g_table_prefix}views WHERE form_id = {$form_id} AND view_id = {$view_id}");
    $result = mysql_fetch_assoc($view_query);
    $view_found = $result["c"] == 1 ? true : false;
    if (!$view_found) {
        if ($g_api_debug) {
            $page_vars = array("message_type" => "error", "error_code" => 402, "error_type" => "user");
            ft_display_page("error.tpl", $page_vars);
            exit;
        } else {
            return array(false, 402);
        }
    }
    $export_type_query = mysql_query("SELECT count(*) as c FROM {$g_table_prefix}module_export_types WHERE export_type_id = {$export_type_id}");
    $result = mysql_fetch_assoc($export_type_query);
    $export_type_found = $result["c"] == 1 ? true : false;
    if (!$export_type_found) {
        if ($g_api_debug) {
            $page_vars = array("message_type" => "error", "error_code" => 403, "error_type" => "user");
            ft_display_page("error.tpl", $page_vars);
            exit;
        } else {
            return array(false, 403);
        }
    }
    // okay, now lets figure out what needs to be displayed & rendered
    $form_info = ft_get_form($form_id);
    $form_fields = ft_get_form_fields($form_id, array("include_field_type_info" => true, "include_field_settings" => true));
    $view_info = ft_get_view($view_id);
    $export_type_info = exp_get_export_type($export_type_id);
    $export_group_id = $export_type_info["export_group_id"];
    $export_group_info = exp_get_export_group($export_group_id);
    // number of submissions per page (an integer or "all")
    $num_per_page = $view_info["num_submissions_per_page"];
    if (isset($options["num_per_page"])) {
        $num_per_page = $options["num_per_page"];
    }
    $order = "{$view_info["default_sort_field"]}-{$view_info["default_sort_field_order"]}";
    if (isset($options["order"])) {
        $order = $options["order"];
    }
    $display_fields = array();
    $columns = "all";
    if (isset($options["show_columns_only"]) && $options["show_columns_only"]) {
        $columns = array();
        foreach ($view_info["columns"] as $view_field_info) {
            $curr_field_id = $view_field_info["field_id"];
            foreach ($form_fields as $form_field_info) {
                if ($form_field_info["field_id"] != $curr_field_id) {
                    continue;
                }
                $display_fields[] = array_merge($form_field_info, $view_field_info);
                $columns[] = $form_field_info["col_name"];
            }
        }
    } else {
        foreach ($view_info["fields"] as $view_field_info) {
            $curr_field_id = $view_field_info["field_id"];
            foreach ($form_fields as $form_field_info) {
                if ($form_field_info["field_id"] != $curr_field_id) {
                    continue;
                }
                $display_fields[] = array_merge($form_field_info, $view_field_info);
            }
        }
    }
    /*
    $columns = "all";
    if (isset($options["show_columns_only"]) && $options["show_columns_only"])
    {
      $columns = array();
      foreach ($view_info["columns"] as $view_col_info)
      {
        foreach ($display_fields as $field_info)
        {
          if ($field_info["field_id"] == $view_col_info["field_id"])
          {
            $columns[] = $field_info["col_name"];
          }
        }
      }
    }
    */
    $submission_ids = array();
    if (isset($options["submission_ids"])) {
        if (is_numeric($options["submission_ids"])) {
            $submission_ids[] = $options["submission_ids"];
        } else {
            if (is_array($submission_ids)) {
                $submission_ids = $options["submission_ids"];
            }
        }
    }
    // perform the almighty search query
    $results_info = ft_search_submissions($form_id, $view_id, $num_per_page, $page_num, $order, $columns, array(), $submission_ids);
    $search_num_results = $results_info["search_num_results"];
    $settings = ft_get_settings();
    // now build the list of information we're going to send to the export type smarty template
    $placeholders = exp_get_export_filename_placeholder_hash();
    $placeholders["export_group_id"] = $export_group_id;
    $placeholders["export_type_id"] = $export_type_id;
    $placeholders["export_group_results"] = "all";
    $placeholders["same_page"] = ft_get_clean_php_self();
    $placeholders["display_fields"] = $display_fields;
    $placeholders["submissions"] = $results_info["search_rows"];
    $placeholders["num_results"] = $results_info["search_num_results"];
    $placeholders["view_num_results"] = $results_info["view_num_results"];
    $placeholders["form_info"] = $form_info;
    $placeholders["view_info"] = $view_info;
    $placeholders["field_types"] = ft_get_field_types(true);
    $placeholders["settings"] = $settings;
    // ...
    $placeholders["date_format"] = $settings["default_date_format"];
    $placeholders["timezone_offset"] = $settings["timezone_offset"];
    // pull out a few things into top level placeholders for easy use
    $placeholders["form_name"] = $form_info["form_name"];
    $placeholders["form_id"] = $form_id;
    $placeholders["form_url"] = $form_info["form_url"];
    $placeholders["view_name"] = $view_info["view_name"];
    $placeholders["view_id"] = $view_id;
    $placeholders["export_group_name"] = ft_create_slug(ft_eval_smarty_string($export_group_info["group_name"]));
    $placeholders["export_group_type"] = ft_create_slug(ft_eval_smarty_string($export_type_info["export_type_name"]));
    $placeholders["filename"] = ft_eval_smarty_string($export_type_info["filename"], $placeholders, "", $g_smarty->plugins_dir);
    $template = $export_type_info["export_type_smarty_template"];
    $placeholders["export_type_name"] = $export_type_info["export_type_name"];
    $export_type_smarty_template = ft_eval_smarty_string($template, $placeholders, "", $g_smarty->plugins_dir);
    // if we're not displaying all results on the single page, generate the pagination HTML
    $pagination = "";
    if ($num_per_page != "all") {
        $page_num_identifier = isset($options["page_num_identifier"]) ? $options["page_num_identifier"] : "page";
        $theme = isset($options["pagination_theme"]) ? $options["pagination_theme"] : $settings["default_theme"];
        $pagination = ft_get_page_nav($search_num_results, $num_per_page, $page_num, "", $page_num_identifier, $theme);
    }
    $pagination_location = isset($options["pagination_location"]) ? $options["pagination_location"] : "top";
    switch ($pagination_location) {
        case "top":
            $html = $pagination . $export_type_smarty_template;
            break;
        case "both":
            $html = $pagination . $export_type_smarty_template . $pagination;
            break;
        case "bottom":
            $html = $export_type_smarty_template . $pagination;
            break;
        case "none":
            $html = $export_type_smarty_template;
            break;
            // this is in case the user entered an invalid value
        // this is in case the user entered an invalid value
        default:
            if ($g_api_debug) {
                $page_vars = array("message_type" => "error", "error_code" => 404, "error_type" => "user");
                ft_display_page("error.tpl", $page_vars);
                exit;
            } else {
                return array(false, 404);
            }
            break;
    }
    if (isset($options["return_as_string"]) && $options["return_as_string"]) {
        return array(true, $html);
    } else {
        echo $html;
    }
}