| 1 |
<?php |
| 2 |
|
| 3 |
namespace King_Addons; |
| 4 |
|
| 5 |
use King_Addons\Core; |
| 6 |
|
| 7 |
if (!defined('ABSPATH')) { |
| 8 |
exit; |
| 9 |
} |
| 10 |
|
| 11 |
class Send_Email |
| 12 |
{ |
| 13 |
|
| 14 |
public function __construct() |
| 15 |
{ |
| 16 |
add_action('wp_ajax_king_addons_form_builder_email', [$this, 'send_email']); |
| 17 |
add_action('wp_ajax_nopriv_king_addons_form_builder_email', [$this, 'send_email']); |
| 18 |
} |
| 19 |
|
| 20 |
public function send_email() |
| 21 |
{ |
| 22 |
|
| 23 |
$nonce = $_POST['nonce']; |
| 24 |
|
| 25 |
// Security fix: Generate nonce server-side instead of relying on client-provided nonce |
| 26 |
$server_nonce = wp_create_nonce('king-addons-js'); |
| 27 |
if (!wp_verify_nonce($nonce, 'king-addons-js')) { |
| 28 |
return; |
| 29 |
} |
| 30 |
|
| 31 |
$message_body = []; |
| 32 |
|
| 33 |
// Security fix: Validate and sanitize form_content array |
| 34 |
$form_content = isset($_POST['form_content']) && is_array($_POST['form_content']) ? $_POST['form_content'] : []; |
| 35 |
|
| 36 |
foreach ($form_content as $field) { |
| 37 |
if (!is_array($field) || count($field) < 2) { |
| 38 |
continue; // Skip malformed fields |
| 39 |
} |
| 40 |
|
| 41 |
if ($field[0] === 'email') { |
| 42 |
if (!is_email(sanitize_email($field[1]))) { |
| 43 |
wp_send_json_error(array( |
| 44 |
'action' => 'king_addons_form_builder_email', |
| 45 |
'message' => esc_html__('Email provided is invalid', 'king-addons'), |
| 46 |
'status' => 'error' |
| 47 |
)); |
| 48 |
} |
| 49 |
} |
| 50 |
} |
| 51 |
|
| 52 |
|
| 53 |
$content_type = get_option('king_addons_email_content_type_' . $_POST['king_addons_form_id']); |
| 54 |
|
| 55 |
$line_break = 'html' === $content_type ? '<br>' : "\n"; |
| 56 |
|
| 57 |
$email_fields = trim(get_option('king_addons_email_fields_' . $_POST['king_addons_form_id'])); |
| 58 |
|
| 59 |
if ($email_fields === '[all-fields]' || str_contains($email_fields, '[all-fields]')) { |
| 60 |
|
| 61 |
|
| 62 |
$replace_shortcode_with_value = function ($matches) use ($form_content) { |
| 63 |
$field_id = sanitize_text_field($matches[1]); |
| 64 |
foreach ($form_content as $key => $value) { |
| 65 |
$key_parts = explode('-', $key); |
| 66 |
$last_part = end($key_parts); |
| 67 |
if ($last_part === $field_id) { |
| 68 |
// Security fix: Sanitize form field values before using in email |
| 69 |
return is_array($value[1]) ? implode("\n", array_map('sanitize_text_field', $value[1])) : sanitize_text_field($value[1]); |
| 70 |
} |
| 71 |
} |
| 72 |
return ''; |
| 73 |
}; |
| 74 |
|
| 75 |
|
| 76 |
$all_fields_content = []; |
| 77 |
|
| 78 |
foreach ($form_content as $key => $value) { |
| 79 |
if (!is_array($value) || count($value) < 3) { |
| 80 |
continue; // Skip malformed fields |
| 81 |
} |
| 82 |
// Security fix: Sanitize all field data before using in email |
| 83 |
$field_label = sanitize_text_field($value[2]); |
| 84 |
$field_value = is_array($value[1]) ? implode("\n", array_map('sanitize_text_field', $value[1])) : sanitize_text_field($value[1]); |
| 85 |
$all_fields_content[] = $field_label . ': ' . $field_value; |
| 86 |
} |
| 87 |
$all_fields_content = implode("\n", $all_fields_content); |
| 88 |
|
| 89 |
|
| 90 |
$processed_message = str_replace('[all-fields]', $all_fields_content, $email_fields); |
| 91 |
|
| 92 |
$processed_message = preg_replace_callback( |
| 93 |
'/\[id="([^"]+)"\]/', |
| 94 |
$replace_shortcode_with_value, |
| 95 |
$processed_message |
| 96 |
); |
| 97 |
} else { |
| 98 |
|
| 99 |
|
| 100 |
$replace_shortcode_with_value = function ($matches) use ($form_content) { |
| 101 |
$field_id = sanitize_text_field($matches[1]); |
| 102 |
foreach ($form_content as $key => $value) { |
| 103 |
if (!is_array($value) || count($value) < 3) { |
| 104 |
continue; // Skip malformed fields |
| 105 |
} |
| 106 |
$key_parts = explode('-', $key); |
| 107 |
$last_part = end($key_parts); |
| 108 |
if ($last_part === $field_id) { |
| 109 |
// Security fix: Sanitize form field data |
| 110 |
$field_label = sanitize_text_field($value[2]); |
| 111 |
$field_value = is_array($value[1]) ? implode("\n", array_map('sanitize_text_field', $value[1])) : sanitize_text_field($value[1]); |
| 112 |
return $field_label . ': ' . $field_value; |
| 113 |
} |
| 114 |
} |
| 115 |
return ''; |
| 116 |
}; |
| 117 |
|
| 118 |
|
| 119 |
$processed_message = preg_replace_callback( |
| 120 |
'/\[id="([^"]+)"\]/', |
| 121 |
$replace_shortcode_with_value, |
| 122 |
$email_fields |
| 123 |
); |
| 124 |
} |
| 125 |
|
| 126 |
$meta_keys = get_option('king_addons_meta_keys_' . $_POST['king_addons_form_id']); |
| 127 |
$meta_fields = []; |
| 128 |
|
| 129 |
foreach ($meta_keys as $metadata_type) { |
| 130 |
switch ($metadata_type) { |
| 131 |
case 'date': |
| 132 |
$meta_fields['date'] = [ |
| 133 |
'title' => esc_html__('Date', 'king-addons'), |
| 134 |
'value' => date_i18n(get_option('date_format')), |
| 135 |
]; |
| 136 |
break; |
| 137 |
|
| 138 |
case 'time': |
| 139 |
$meta_fields['time'] = [ |
| 140 |
'title' => esc_html__('Time', 'king-addons'), |
| 141 |
'value' => date_i18n(get_option('time_format')), |
| 142 |
]; |
| 143 |
break; |
| 144 |
|
| 145 |
case 'page_url': |
| 146 |
$meta_fields['page_url'] = [ |
| 147 |
'title' => esc_html__('Page URL', 'king-addons'), |
| 148 |
|
| 149 |
'value' => get_option('king_addons_referrer_' . $_POST['king_addons_form_id']) ? get_option('king_addons_referrer_' . $_POST['king_addons_form_id']) : '', |
| 150 |
]; |
| 151 |
break; |
| 152 |
|
| 153 |
case 'page_title': |
| 154 |
$meta_fields['page_title'] = [ |
| 155 |
'title' => esc_html__('Page Title', 'king-addons'), |
| 156 |
|
| 157 |
'value' => get_option('king_addons_referrer_title_' . $_POST['king_addons_form_id']) ? get_option('king_addons_referrer_title_' . $_POST['king_addons_form_id']) : '', |
| 158 |
]; |
| 159 |
break; |
| 160 |
|
| 161 |
case 'user_agent': |
| 162 |
$meta_fields['user_agent'] = [ |
| 163 |
'title' => esc_html__('User Agent', 'king-addons'), |
| 164 |
'value' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_textarea_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '', |
| 165 |
]; |
| 166 |
break; |
| 167 |
|
| 168 |
case 'remote_ip': |
| 169 |
$meta_fields['remote_ip'] = [ |
| 170 |
'title' => esc_html__('Remote IP', 'king-addons'), |
| 171 |
'value' => Core::getClientIP(), |
| 172 |
]; |
| 173 |
break; |
| 174 |
|
| 175 |
case 'credit': |
| 176 |
$meta_fields['credit'] = [ |
| 177 |
'title' => esc_html__('Powered by', 'king-addons'), |
| 178 |
'value' => esc_html__('King Addons', 'king-addons'), |
| 179 |
]; |
| 180 |
break; |
| 181 |
} |
| 182 |
} |
| 183 |
|
| 184 |
$email_meta = []; |
| 185 |
|
| 186 |
foreach ($meta_fields as $key => $value) { |
| 187 |
$email_meta[] = $value['title'] . ': ' . $value['value']; |
| 188 |
} |
| 189 |
|
| 190 |
$to = get_option('king_addons_email_to_' . $_POST['king_addons_form_id']); |
| 191 |
|
| 192 |
$to = preg_replace_callback( |
| 193 |
'/\[id="(\w+)"\]/', |
| 194 |
function ($matches) { |
| 195 |
return $this->get_field_value($matches[1]); |
| 196 |
}, |
| 197 |
$to |
| 198 |
); |
| 199 |
|
| 200 |
$subject = get_option('king_addons_email_subject_' . $_POST['king_addons_form_id']); |
| 201 |
|
| 202 |
$subject = preg_replace_callback( |
| 203 |
'/\[id="(\w+)"\]/', |
| 204 |
function ($matches) { |
| 205 |
return $this->get_field_value($matches[1]); |
| 206 |
}, |
| 207 |
$subject |
| 208 |
); |
| 209 |
|
| 210 |
if ($processed_message) { |
| 211 |
$message_body[] = $processed_message; |
| 212 |
} |
| 213 |
|
| 214 |
|
| 215 |
if ($content_type === 'html') { |
| 216 |
|
| 217 |
foreach ($message_body as &$item) { |
| 218 |
$item = nl2br($item); |
| 219 |
} |
| 220 |
unset($item); |
| 221 |
} |
| 222 |
|
| 223 |
$body = implode($line_break, $message_body) . $line_break . '-----' . $line_break . implode($line_break, $email_meta); |
| 224 |
|
| 225 |
$cc_header = ''; |
| 226 |
if (!empty(get_option('king_addons_cc_header_' . $_POST['king_addons_form_id']))) { |
| 227 |
$cc_header = 'Cc: ' . get_option('king_addons_cc_header_' . $_POST['king_addons_form_id']); |
| 228 |
|
| 229 |
$cc_header = preg_replace_callback( |
| 230 |
'/\[id="(\w+)"\]/', |
| 231 |
function ($matches) { |
| 232 |
return $this->get_field_value($matches[1]); |
| 233 |
}, |
| 234 |
$cc_header |
| 235 |
); |
| 236 |
} |
| 237 |
|
| 238 |
$bcc_header = ''; |
| 239 |
if (!empty(get_option('king_addons_bcc_header_' . $_POST['king_addons_form_id']))) { |
| 240 |
$bcc_header = 'Bcc: ' . get_option('king_addons_bcc_header_' . $_POST['king_addons_form_id']); |
| 241 |
|
| 242 |
$bcc_header = preg_replace_callback( |
| 243 |
'/\[id="([^\"]+)"\]/', |
| 244 |
function ($matches) { |
| 245 |
return $this->get_field_value($matches[1]); |
| 246 |
}, |
| 247 |
$bcc_header |
| 248 |
); |
| 249 |
} |
| 250 |
|
| 251 |
// Initialize reply-to and email-from variables to avoid undefined variable warnings |
| 252 |
$reply_to_address = ''; |
| 253 |
$email_from_name = ''; |
| 254 |
$email_from_mail = ''; |
| 255 |
$reply_to = ''; |
| 256 |
|
| 257 |
if (!empty(get_option('king_addons_reply_to_' . $_POST['king_addons_form_id'])) && !empty(get_option('king_addons_email_from_name_' . $_POST['king_addons_form_id'])) && !empty(get_option('king_addons_email_from_' . $_POST['king_addons_form_id']))) { |
| 258 |
|
| 259 |
preg_match_all('/id="([^"]+)"/', get_option('king_addons_reply_to_' . $_POST['king_addons_form_id']), $matche); |
| 260 |
$reply_to_field_id = $matche[1]; |
| 261 |
|
| 262 |
preg_match_all('/id="([^"]+)"/', get_option('king_addons_email_from_name_' . $_POST['king_addons_form_id']), $matche); |
| 263 |
$email_from_name_field_id = $matche[1]; |
| 264 |
|
| 265 |
preg_match_all('/id="([^"]+)"/', get_option('king_addons_email_from_' . $_POST['king_addons_form_id']), $matche); |
| 266 |
$email_from_field_id = $matche[1]; |
| 267 |
|
| 268 |
foreach ($form_content as $key => $value) { |
| 269 |
if (!is_array($value) || count($value) < 2) { |
| 270 |
continue; // Skip malformed fields |
| 271 |
} |
| 272 |
|
| 273 |
$key_parts = explode('-', $key); |
| 274 |
$last_part = end($key_parts); |
| 275 |
|
| 276 |
if (in_array($last_part, $reply_to_field_id)) { |
| 277 |
$reply_to_address = sanitize_email($value[1]); |
| 278 |
} |
| 279 |
|
| 280 |
if (in_array($last_part, $email_from_name_field_id)) { |
| 281 |
$email_from_name = sanitize_text_field($value[1]); |
| 282 |
} |
| 283 |
|
| 284 |
if (in_array($last_part, $email_from_field_id)) { |
| 285 |
$email_from_mail = sanitize_email($value[1]); |
| 286 |
} |
| 287 |
} |
| 288 |
|
| 289 |
if (!$reply_to_address) { |
| 290 |
$reply_to_address = get_option('king_addons_reply_to_' . $_POST['king_addons_form_id']); |
| 291 |
} |
| 292 |
|
| 293 |
if (!$email_from_name) { |
| 294 |
$email_from_name = get_option('king_addons_email_from_name_' . $_POST['king_addons_form_id']); |
| 295 |
} |
| 296 |
|
| 297 |
if (!$email_from_mail) { |
| 298 |
$email_from_mail = get_option('king_addons_email_from_' . $_POST['king_addons_form_id']); |
| 299 |
} |
| 300 |
|
| 301 |
$reply_to = 'Reply-To: ' . $reply_to_address; |
| 302 |
} |
| 303 |
|
| 304 |
$email_from = sprintf('From: %s <%s>' . "\r\n", $email_from_name, $email_from_mail); |
| 305 |
|
| 306 |
$headers = array('Content-Type: text/' . $content_type . '; charset=UTF-8', $email_from, $cc_header, $bcc_header, $reply_to); |
| 307 |
|
| 308 |
|
| 309 |
$sent = wp_mail($to, $subject, $body, $headers); |
| 310 |
|
| 311 |
if ($sent) { |
| 312 |
wp_send_json_success(array( |
| 313 |
'action' => 'king_addons_form_builder_email', |
| 314 |
'message' => esc_html__('Message sent successfully', 'king-addons'), |
| 315 |
'status' => 'success' |
| 316 |
// Security fix: Removed potentially unsafe details from response |
| 317 |
)); |
| 318 |
} else { |
| 319 |
wp_send_json_error(array( |
| 320 |
'action' => 'king_addons_form_builder_email', |
| 321 |
'message' => esc_html__('Message could not be sent', 'king-addons'), |
| 322 |
'status' => 'error' |
| 323 |
// Security fix: Removed potentially unsafe details from response |
| 324 |
)); |
| 325 |
} |
| 326 |
} |
| 327 |
|
| 328 |
public function get_field_value($field_id) |
| 329 |
{ |
| 330 |
// Security fix: Use sanitized form_content instead of $_POST directly |
| 331 |
$form_content = isset($_POST['form_content']) && is_array($_POST['form_content']) ? $_POST['form_content'] : []; |
| 332 |
|
| 333 |
foreach ($form_content as $key => $field) { |
| 334 |
if (!is_array($field) || count($field) < 2) { |
| 335 |
continue; // Skip malformed fields |
| 336 |
} |
| 337 |
|
| 338 |
$key_parts = explode('-', $key); |
| 339 |
$last_part = end($key_parts); |
| 340 |
|
| 341 |
if ($last_part === $field_id) { |
| 342 |
return sanitize_text_field($field[1]); |
| 343 |
} |
| 344 |
} |
| 345 |
return ''; |
| 346 |
} |
| 347 |
} |
| 348 |
|
| 349 |
new Send_Email(); |