PluginProbe ʕ •ᴥ•ʔ
Email Encoder – Protect Email Addresses and Phone Numbers / 2.3.6
Email Encoder – Protect Email Addresses and Phone Numbers v2.3.6
2.5.3 2.5.2 2.5.1 2.5.0 2.4.8 trunk 0.10 0.11 0.12 0.20 0.21 0.22 0.30 0.31 0.32 0.40 0.41 0.42 0.50 0.60 0.70 0.71 0.80 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.5 1.5.2 1.51 1.53 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7
email-encoder-bundle / core / includes / classes / class-email-encoder-bundle-validate.php
email-encoder-bundle / core / includes / classes Last commit date
class-email-encoder-bundle-ajax.php 8 months ago class-email-encoder-bundle-helpers.php 8 months ago class-email-encoder-bundle-settings.php 8 months ago class-email-encoder-bundle-validate.php 8 months ago index.php 6 years ago
class-email-encoder-bundle-validate.php
1153 lines
1 <?php
2
3 namespace Legacy\EmailEncoderBundle;
4
5 use DOMDocument;
6 use OnlineOptimisation\EmailEncoderBundle\Traits\PluginHelper;
7
8 class Email_Encoder_Validate {
9
10 use PluginHelper;
11
12 private string $page_name;
13 // private string $page_title;
14 // private string $final_output_buffer_hook;
15 private string $at_identifier;
16
17
18 function __construct() {
19 $this->page_name = $this->getPageName();
20 // $this->page_title = $this->settings()->get_page_title();
21 // $this->final_output_buffer_hook = $this->settings()->get_final_output_buffer_hook();
22 $this->at_identifier = $this->settings()->get_at_identifier();
23 }
24
25 /**
26 * ######################
27 * ###
28 * #### FILTERS
29 * ###
30 * ######################
31 */
32
33 /**
34 * The main page filter function
35 *
36 * @param string $content - the content that needs to be filtered
37 * @param bool $convertPlainEmails - wether plain emails should be preserved or not
38 * @return string - The filtered content
39 */
40 public function filter_page( $content, $protect_using ) {
41
42 //Added in 2.0.6
43 $content = apply_filters( 'eeb/validate/filter_page_content', $content, $protect_using );
44
45 $content = $this->filter_soft_dom_attributes( $content, 'char_encode' );
46
47 $htmlSplit = preg_split( '/(<body(([^>]*)>))/is', $content, -1, PREG_SPLIT_DELIM_CAPTURE );
48
49 if ( count( $htmlSplit ) < 4 ) {
50 return $content;
51 }
52
53 switch( $protect_using ) {
54 case 'with_javascript':
55 case 'without_javascript':
56 case 'char_encode':
57 $head_encoding_method = 'char_encode';
58 break;
59 default:
60 $head_encoding_method = 'default';
61 break;
62 }
63
64 //Filter head area
65 $filtered_head = $this->filter_plain_emails( $htmlSplit[0], null, $head_encoding_method );
66
67 //Filter body
68 //Soft attributes always need to be protected using only the char encode method since otherwise the logic breaks
69 $filtered_body = $this->filter_soft_attributes( $htmlSplit[4], 'char_encode' );
70 $filtered_body = $this->filter_content( $filtered_body, $protect_using );
71
72 $filtered_content = $filtered_head . $htmlSplit[1] . $filtered_body;
73
74 //Revalidate filtered emails that should not bbe encoded
75 $filtered_content = $this->temp_encode_at_symbol( $filtered_content, true );
76
77 return $filtered_content;
78 }
79
80 /**
81 * Filter content
82 *
83 * @param string $content
84 * @param integer $protect_using
85 * @return string
86 */
87 public function filter_content( $content, $protect_using ) {
88 $filtered = $content;
89 $self = $this;
90 $encode_mailtos = (bool) $this->getSetting( 'encode_mailtos', true, 'filter_body' );
91 $convert_plain_to_image = (bool) $this->getSetting( 'convert_plain_to_image', true, 'filter_body' );
92
93 //Added in 2.0.6
94 $filtered = apply_filters( 'eeb/validate/filter_content_content', $filtered, $protect_using );
95
96 //Soft attributes always need to be protected using only the char encode method since otherwise the logic breaks
97 $filtered = $this->filter_soft_attributes( $filtered, 'char_encode' );
98
99 switch( $protect_using ) {
100 case 'char_encode':
101 $filtered = $this->filter_plain_emails( $filtered, null, 'char_encode' );
102 break;
103 case 'strong_method':
104 $filtered = $this->filter_plain_emails( $filtered );
105 break;
106 case 'without_javascript':
107 $filtered = $this->filter_input_fields( $filtered, $protect_using );
108 $filtered = $this->filter_mailto_links( $filtered, 'without_javascript' );
109 $filtered = $this->filter_custom_links( $filtered, 'without_javascript' );
110
111 if ( $convert_plain_to_image ) {
112 $replace_by = 'convert_image';
113 } else {
114 $replace_by = 'use_css';
115 }
116
117 if ( $encode_mailtos ) {
118 if ( ! ( function_exists( 'et_fb_enabled' ) && et_fb_enabled() ) ) {
119 $filtered = $this->filter_plain_emails( $filtered, function ( $match ) use ( $self ) {
120 return $self->create_protected_mailto( $match[0], array( 'href' => 'mailto:' . $match[0] ), 'without_javascript' );
121 }, $replace_by);
122 } else {
123 $filtered = $this->filter_plain_emails( $filtered, null, $replace_by );
124 }
125 } else {
126 $filtered = $this->filter_plain_emails( $filtered, null, $replace_by );
127 }
128
129 break;
130 case 'with_javascript':
131 $filtered = $this->filter_input_fields( $filtered, $protect_using );
132 $filtered = $this->filter_mailto_links( $filtered );
133 $filtered = $this->filter_custom_links( $filtered );
134
135 if ( $convert_plain_to_image ) {
136 $replace_by = 'convert_image';
137 } else {
138 $replace_by = 'use_javascript';
139 }
140
141 if ( $encode_mailtos ) {
142 if ( ! ( function_exists( 'et_fb_enabled' ) && et_fb_enabled() ) ) {
143 $filtered = $this->filter_plain_emails( $filtered, function ( $match ) use ( $self ) {
144 return $self->create_protected_mailto( $match[0], array( 'href' => 'mailto:' . $match[0] ), 'with_javascript' );
145 }, $replace_by);
146 } else {
147 $filtered = $this->filter_plain_emails( $filtered, null, $replace_by );
148 }
149 } else {
150 $filtered = $this->filter_plain_emails( $filtered, null, $replace_by );
151 }
152
153 break;
154 }
155
156 //Revalidate filtered emails that should not be encoded
157 $filtered = $this->temp_encode_at_symbol( $filtered, true );
158
159 return $filtered;
160 }
161
162 /**
163 * Emails will be replaced by '*protected email*'
164 * @param string $content
165 * @param string|callable $replace_by Optional
166 * @param string $protection_method Optional
167 * @param mixed $show_encoded_check Optional
168 * @return string
169 */
170 public function filter_plain_emails( $content, $replace_by = null, $protection_method = 'default', $show_encoded_check = 'default' ) {
171
172 if ( $show_encoded_check === 'default' ) {
173 $show_encoded_check = (bool) $this->getSetting( 'show_encoded_check', true );
174 }
175
176 if ( $replace_by === null ) {
177 $replace_by = __( $this->getSetting( 'protection_text', true ), 'email-encoder-bundle' );
178 }
179
180 $self = $this;
181
182 return preg_replace_callback( $this->settings()->get_email_regex(), function ( $matches ) use ( $replace_by, $protection_method, $show_encoded_check, $self ) {
183 // workaround to skip responsive image names containing @
184 $extention = strtolower( $matches[4] );
185 $excludedList = array(
186 '.jpg',
187 '.jpeg',
188 '.png',
189 '.gif',
190 '.svg',
191 '.webp',
192 '.bmp',
193 '.tiff',
194 '.avif',
195 );
196
197 //Added in 2.1.1
198 $excludedList = apply_filters( 'eeb/validate/excluded_image_urls', $excludedList );
199
200 if ( in_array( $extention, $excludedList ) ) {
201 return $matches[0];
202 }
203
204 if ( is_callable( $replace_by ) ) {
205 return call_user_func( $replace_by, $matches, $protection_method );
206 }
207
208 if ( $protection_method === 'char_encode' ) {
209 $protected_return = antispambot( $matches[0] );
210 } elseif ( $protection_method === 'convert_image' ) {
211
212 $image_link = $self->generate_email_image_url( $matches[0] );
213 if ( ! empty( $image_link ) ) {
214 $protected_return = '<img src="' . $image_link . '" />';
215 } else {
216 $protected_return = antispambot( $matches[0] );
217 }
218
219 } elseif ( $protection_method === 'use_javascript' ) {
220 $protection_text = __( $this->getSetting( 'protection_text', true ), 'email-encoder-bundle' );
221 $protected_return = $this->dynamic_js_email_encoding( $matches[0], $protection_text );
222 } elseif ( $protection_method === 'use_css' ) {
223 $protection_text = __( $this->getSetting( 'protection_text', true ), 'email-encoder-bundle' );
224 $protected_return = $this->encode_email_css( $matches[0], $protection_text );
225 } elseif ( $protection_method === 'no_encoding' ) {
226 $protected_return = $matches[0];
227 } else {
228 $protected_return = $replace_by;
229 }
230
231 // mark link as successfully encoded (for admin users)
232 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
233 $protected_return .= $this->get_encoded_email_icon();
234 }
235
236 return $protected_return;
237
238 }, $content );
239 }
240
241 /**
242 * Filter passed input fields
243 *
244 * @param string $content
245 * @return string
246 */
247 public function filter_input_fields( $content, $encoding_method = 'default' ) {
248 $self = $this;
249 $strong_encoding = (bool) $this->getSetting( 'input_strong_protection', true, 'filter_body' );
250
251 $callback_encode_input_fields = function ( $match ) use ( $self, $encoding_method, $strong_encoding ) {
252 $input = $match[0];
253 $email = $match[2];
254
255 //Only allow strong encoding if javascript is supported
256 if ( $encoding_method === 'without_javascript' ) {
257 $strong_encoding = false;
258 }
259
260 return $self->encode_input_field( $input, $email, $strong_encoding );
261 };
262
263 $regexpInputField = '/<input([^>]*)value=["\'][\s+]*' . $this->settings()->get_email_regex( true ) . '[\s+]*["\']([^>]*)>/is';
264
265 return preg_replace_callback( $regexpInputField, $callback_encode_input_fields, $content );
266 }
267
268 /**
269 * @param string $content
270 * @return string
271 */
272 public function filter_mailto_links( $content, $protection_method = null ) {
273 $self = $this;
274
275 $callbackEncodeMailtoLinks = function ( $match ) use ( $self, $protection_method ) {
276 $attrs = $this->helper()->parse_html_attributes( $match[1] );
277 return $self->create_protected_mailto( $match[4], $attrs, $protection_method );
278 };
279
280 $regexpMailtoLink = '/<a[\s+]*(([^>]*)href=["\']mailto\:([^>]*)["\' ])>(.*?)<\/a[\s+]*>/is';
281
282 return preg_replace_callback( $regexpMailtoLink, $callbackEncodeMailtoLinks, $content );
283 }
284
285 /**
286 * @param string $content
287 * @return string
288 */
289 public function filter_custom_links( $content, $protection_method = null ) {
290 $self = $this;
291 $custom_href_attr = (string) $this->getSetting( 'custom_href_attr', true );
292
293 if ( ! empty( $custom_href_attr ) ) {
294 $custom_attr_list = explode( ',', $custom_href_attr );
295 foreach( $custom_attr_list as $s_attr ) {
296 $attr_name = trim( $s_attr );
297
298 $callbackEncodeCustomLinks = function ( $match ) use ( $self, $protection_method ) {
299 $attrs = shortcode_parse_atts( $match[1] );
300 return $self->create_protected_href_att( $match[4], $attrs, $protection_method );
301 };
302
303 $regexpMailtoLink = '/<a[\s+]*(([^>]*)href=["\']' . addslashes( $attr_name ) . '\:([^>]*)["\' ])>(.*?)<\/a[\s+]*>/is';
304
305 $content = preg_replace_callback( $regexpMailtoLink, $callbackEncodeCustomLinks, $content );
306 }
307 }
308
309 return $content;
310 }
311
312 /**
313 * Emails will be replaced by '*protected email*'
314 *
315 * @param string $content
316 * @return string
317 */
318 public function filter_rss( $content, $protection_type ) {
319
320 if ( $protection_type === 'strong_method' ) {
321 $filtered = $this->filter_plain_emails( $content );
322 } else {
323 $filtered = $this->filter_plain_emails( $content, null, 'char_encode' );
324 }
325
326 return $filtered;
327 }
328
329 /**
330 * Filter plain emails using soft attributes
331 *
332 * @param string $content - the content that should be soft filtered
333 * @param string $protection_method - The method (E.g. char_encode)
334 * @return string
335 */
336 public function filter_soft_attributes( $content, $protection_method ) {
337 $soft_attributes = $this->settings()->get_soft_attribute_regex();
338
339 foreach( $soft_attributes as $ident => $regex ) {
340
341 $attributes = array();
342 preg_match_all( $regex, $content, $attributes );
343
344 if ( is_array( $attributes ) && isset( $attributes[0] ) ) {
345 foreach( $attributes[0] as $single ) {
346
347 if ( empty( $single ) ) {
348 continue;
349 }
350
351 $content = str_replace( $single, $this->filter_plain_emails( $single, null, $protection_method, false ), $content );
352 }
353 }
354
355 }
356
357 return $content;
358 }
359
360 /**
361 * Filter plain emails using soft dom attributes
362 *
363 * @param string $content - the content that should be soft filtered
364 * @param string $protection_method - The method (E.g. char_encode)
365 * @return string
366 */
367 public function filter_soft_dom_attributes( $content, $protection_method ) {
368
369 $no_script_tags = (bool) $this->getSetting( 'no_script_tags', true, 'filter_body' );
370 $no_attribute_validation = (bool) $this->getSetting( 'no_attribute_validation', true, 'filter_body' );
371
372 if ( ! empty( $content ) && is_string( $content ) ) {
373
374 if ( class_exists( 'DOMDocument' ) ) {
375 $dom = new DOMDocument();
376 @$dom->loadHTML($content);
377
378 //Filter html attributes
379 if ( ! $no_attribute_validation ) {
380 $allNodes = $dom->getElementsByTagName('*');
381 foreach( $allNodes as $snote ) {
382 if ( $snote->hasAttributes() ) {
383 foreach( $snote->attributes as $attr ) {
384 if ( $attr->nodeName == 'href' || $attr->nodeName == 'src' ) {
385 continue;
386 }
387
388 if ( strpos( $attr->nodeValue, '@' ) !== FALSE ) {
389 $single_tags = array();
390 preg_match_all( '/' . $attr->nodeName . '=["\']([^"]*)["\']/i', $content, $single_tags );
391
392 if ( is_array( $single_tags ) && isset( $single_tags[0] ) ) {
393 foreach( $single_tags[0] as $single ) {
394
395 if ( empty( $single ) ) {
396 continue;
397 }
398
399 $content = str_replace( $single, $this->filter_plain_emails( $single, null, $protection_method, false ), $content );
400 }
401 }
402
403 }
404 }
405 }
406 }
407 }
408
409 //Keep for now
410 //Soft-encode scripts
411 // $script = $dom->getElementsByTagName('script');
412 // if ( ! empty( $script ) ) {
413 // $scripts_encoded = true;
414
415 // if ( ! $no_script_tags ) {
416 // foreach( $script as $item ) {
417 // $content = str_replace( $item->nodeValue, $this->filter_plain_emails( $item->nodeValue, null, $protection_method, false ), $content );
418 // }
419 // } else {
420 // foreach( $script as $item ) {
421 // $content = str_replace( $item->nodeValue, $this->temp_encode_at_symbol( $item->nodeValue ), $content );
422 // }
423 // }
424 // }
425
426 }
427
428 //Validate script tags for better encoding
429 $pattern = '/<script\b[^>]*>(.*?)<\/script>/is';
430
431 preg_match_all($pattern, $content, $matches);
432 if (
433 isset( $matches[1] )
434 && ! empty( $matches[1] )
435 ) {
436 if ( ! $no_script_tags ) {
437 foreach( $matches[1] as $key => $item ) {
438
439 //Don't do anything if something doesn't add up
440 if ( ! isset( $matches[0][ $key ] ) ) {
441 continue;
442 }
443
444 $org_script = $matches[0][ $key ];
445
446 //Only encode emails when a CDATA is given to not cause any break within the scripts
447 if ( strpos( $item, '<![CDATA' ) !== false ) {
448 $validated_script = str_replace( $item, $this->filter_plain_emails( $item, null, $protection_method, false ), $org_script );
449 } else {
450 $validated_script = str_replace( $item, $this->temp_encode_at_symbol( $item ), $org_script );
451 }
452
453 $content = str_replace( $org_script, $validated_script, $content );
454 }
455 } else {
456 foreach( $matches[1] as $key => $item ) {
457
458 //Don't do anything if something doesn't add up
459 if ( ! isset( $matches[0][ $key ] ) ) {
460 continue;
461 }
462
463 $org_script = $matches[0][ $key ];
464 $validated_script = str_replace( $item, $this->temp_encode_at_symbol( $item ), $org_script );
465
466 $content = str_replace( $org_script, $validated_script, $content );
467 }
468 }
469 }
470
471 }
472
473
474 return $content;
475 }
476
477 /**
478 * ######################
479 * ###
480 * #### ENCODINGS
481 * ###
482 * ######################
483 */
484
485 public function temp_encode_at_symbol( $content, $decode = false ) {
486 if ( $decode ) {
487 return str_replace( $this->at_identifier, '@', $content );
488 }
489
490 return str_replace( '@', $this->at_identifier, $content );
491 }
492
493 /**
494 * ASCII method
495 *
496 * @param string $value
497 * @param string $protection_text
498 * @return string
499 */
500 public function encode_ascii($value, $protection_text) {
501 $mail_link = $value;
502
503 // first encode, so special chars can be supported
504 $mail_link = $this->helper()->encode_uri_components( $mail_link );
505
506 $mail_letters = '';
507
508 for ($i = 0; $i < strlen($mail_link); $i ++) {
509 $l = substr($mail_link, $i, 1);
510
511 if (strpos($mail_letters, $l) === false) {
512 $p = rand(0, strlen($mail_letters));
513 $mail_letters = substr($mail_letters, 0, $p) .
514 $l . substr($mail_letters, $p, strlen($mail_letters));
515 }
516 }
517
518 $mail_letters_enc = str_replace("\\", "\\\\", $mail_letters);
519 $mail_letters_enc = str_replace("\"", "\\\"", $mail_letters_enc);
520
521 $mail_indices = '';
522 for ($i = 0; $i < strlen($mail_link); $i ++) {
523 $index = strpos($mail_letters, substr($mail_link, $i, 1));
524 $index += 48;
525 $mail_indices .= chr($index);
526 }
527
528 $mail_indices = str_replace("\\", "\\\\", $mail_indices);
529 $mail_indices = str_replace("\"", "\\\"", $mail_indices);
530
531 $element_id = 'eeb-' . mt_rand( 0, 1000000 ) . '-' . mt_rand(0, 1000000);
532
533 return '<span id="'. $element_id . '"></span>'
534 . '<script type="text/javascript">'
535 . '(function() {'
536 . 'var ml="'. $mail_letters_enc .'",mi="'. $mail_indices .'",o="";'
537 . 'for(var j=0,l=mi.length;j<l;j++) {'
538 . 'o+=ml.charAt(mi.charCodeAt(j)-48);'
539 . '}document.getElementById("' . $element_id . '").innerHTML = decodeURIComponent(o);' // decode at the end, this way special chars can be supported
540 . '}());'
541 . '</script><noscript>'
542 . $protection_text
543 . '</noscript>';
544 }
545
546 /**
547 * Escape encoding method
548 *
549 * @param string $value
550 * @param string $protection_text
551 * @return string
552 */
553 public function encode_escape( $value, $protection_text ) {
554 $element_id = 'eeb-' . mt_rand( 0, 1000000 ) . '-' . mt_rand( 0, 1000000 );
555 $string = '\'' . $value . '\'';
556
557 //Validate escape sequences
558 $string = preg_replace('/\s+/S', " ", $string);
559
560 // break string into array of characters, we can't use string_split because its php5 only
561 $split = preg_split( '||', $string );
562 $out = '<span id="'. $element_id . '"></span>'
563 . '<script type="text/javascript">' . 'document.getElementById("' . $element_id . '").innerHTML = ev' . 'al(decodeURIComponent("';
564
565 foreach( $split as $c ) {
566 // preg split will return empty first and last characters, check for them and ignore
567 if ( ! empty( $c ) || $c === '0' ) {
568 $out .= '%' . dechex( ord( $c ) );
569 }
570 }
571
572 $out .= '"))' . '</script><noscript>'
573 . $protection_text
574 . '</noscript>';
575
576 return $out;
577 }
578
579 /**
580 * Encode email in input field
581 * @param string $input
582 * @param string $email
583 * @return string
584 */
585 public function encode_input_field( $input, $email, $strongEncoding = false ) {
586
587 $show_encoded_check = (bool) $this->getSetting( 'show_encoded_check', true );
588
589 if ( $strongEncoding === false ) {
590 // encode email with entities (default wp method)
591 $sub_return = str_replace( $email, antispambot( $email ), $input );
592
593 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
594 $sub_return .= $this->get_encoded_email_icon();
595 }
596
597 return $sub_return;
598 }
599
600 // add data-enc-email after "<input"
601 $inputWithDataAttr = substr( $input, 0, 6 );
602 $inputWithDataAttr .= ' data-enc-email="' . $this->get_encoded_email( $email ) . '"';
603 $inputWithDataAttr .= substr( $input, 6 );
604
605 // mark link as successfullly encoded (for admin users)
606 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
607 $inputWithDataAttr .= $this->get_encoded_email_icon();
608 }
609
610 // remove email from value attribute
611 $encInput = str_replace( $email, '', $inputWithDataAttr );
612
613 return $encInput;
614 }
615
616 /**
617 * Get encoded email, used for data-attribute (translate by javascript)
618 *
619 * @param string $email
620 * @return string
621 */
622 public function get_encoded_email( $email ) {
623 $encEmail = $email;
624
625 // decode entities
626 $encEmail = html_entity_decode( $encEmail );
627
628 // rot13 encoding
629 $encEmail = str_rot13( $encEmail );
630
631 // replace @
632 $encEmail = str_replace( '@', '[at]', $encEmail );
633
634 return $encEmail;
635 }
636
637 /**
638 * Get the ebcoded email icon
639 *
640 * @param string $email
641 * @return string
642 */
643 public function get_encoded_email_icon( $text = 'Email encoded successfully!' ) {
644
645 $html = '<i class="eeb-encoded dashicons-before dashicons-lock" title="' . __( $text, 'email-encoder-bundle' ) . '"></i>';
646
647 return apply_filters( 'eeb/validate/get_encoded_email_icon', $html, $text );
648 }
649
650 /**
651 * Create a protected email
652 *
653 * @param string $display
654 * @param array $attrs Optional
655 * @return string
656 */
657 public function create_protected_mailto( $display, $attrs = array(), $protection_method = null ) {
658 $email = '';
659 $class_ori = ( empty( $attrs['class'] ) ) ? '' : $attrs['class'];
660 $custom_class = (string) $this->getSetting( 'class_name', true );
661 $show_encoded_check = (string) $this->getSetting( 'show_encoded_check', true );
662
663 // set user-defined class
664 if ( $custom_class && strpos( $class_ori, $custom_class ) === FALSE ) {
665 $attrs['class'] = ( empty( $attrs['class'] ) ) ? $custom_class : $attrs['class'] . ' ' . $custom_class;
666 }
667
668 // check title for email address
669 if ( ! empty( $attrs['title'] ) ) {
670 $attrs['title'] = $this->filter_plain_emails( $attrs['title'], '{{email}}' ); // {{email}} will be replaced in javascript
671 }
672
673 // set ignore to data-attribute to prevent being processed by WPEL plugin
674 $attrs['data-wpel-link'] = 'ignore';
675
676 // create element code
677 $link = '<a ';
678
679 foreach ( $attrs AS $key => $value ) {
680 if ( strtolower( $key ) == 'href' ) {
681 if ( $protection_method === 'without_javascript' ) {
682 $link .= $key . '="' . antispambot( $value ) . '" ';
683 } else {
684 // get email from href
685 $email = substr($value, 7);
686
687 $encoded_email = $this->get_encoded_email( $email );
688
689 // set attrs
690 $link .= 'href="javascript:;" ';
691 $link .= 'data-enc-email="' . $encoded_email . '" ';
692 }
693
694 } else {
695 $link .= $key . '="' . $value . '" ';
696 }
697 }
698
699 // remove last space
700 $link = substr( $link, 0, -1 );
701
702 $link .= '>';
703
704 $link .= ( preg_match( $this->settings()->get_email_regex(), $display) > 0 ) ? $this->get_protected_display( $display, $protection_method ) : $display;
705
706 $link .= '</a>';
707
708 // filter
709 $link = apply_filters( 'eeb_mailto', $link, $display, $email, $attrs );
710
711 // just in case there are still email addresses f.e. within title-tag
712 $link = $this->filter_plain_emails( $link, null, 'char_encode' );
713
714 // mark link as successfullly encoded (for admin users)
715 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
716 $link .= $this->get_encoded_email_icon();
717 }
718
719
720 return $link;
721 }
722
723 /**
724 * Create a protected custom attribute
725 *
726 * @param string $display
727 * @param array $attrs Optional
728 * @return string
729 */
730 public function create_protected_href_att( $display, $attrs = array(), $protection_method = null ) {
731 $email = '';
732 $class_ori = ( empty( $attrs['class'] ) ) ? '' : $attrs['class'];
733 $custom_class = (string) $this->getSetting( 'class_name', true );
734 $show_encoded_check = (string) $this->getSetting( 'show_encoded_check', true );
735
736 // set user-defined class
737 if ( $custom_class && strpos( $class_ori, $custom_class ) === FALSE ) {
738 $attrs['class'] = ( empty( $attrs['class'] ) ) ? $custom_class : $attrs['class'] . ' ' . $custom_class;
739 }
740
741 // check title for email address
742 if ( ! empty( $attrs['title'] ) ) {
743 $attrs['title'] = antispambot( $attrs['title'] );
744 }
745
746 // set ignore to data-attribute to prevent being processed by WPEL plugin
747 $attrs['data-wpel-link'] = 'ignore';
748
749 // create element code
750 $link = '<a ';
751
752 foreach ( $attrs AS $key => $value ) {
753 if ( strtolower( $key ) == 'href' ) {
754 $link .= $key . '="' . antispambot( $value ) . '" ';
755 } else {
756 $link .= $key . '="' . $value . '" ';
757 }
758 }
759
760 // remove last space
761 $link = substr( $link, 0, -1 );
762
763 $link .= '>';
764
765 $link .= $this->get_protected_display( $display, $protection_method );
766
767 $link .= '</a>';
768
769 // filter
770 $link = apply_filters( 'eeb_custom_href', $link, $display, $email, $attrs );
771
772 // mark link as successfullly encoded (for admin users)
773 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
774 $link .= $this->get_encoded_email_icon( 'Custom attribute encoded successfully!' );
775 }
776
777
778 return $link;
779 }
780
781 /**
782 * Create protected display combining these 3 methods:
783 * - reversing string
784 * - adding no-display spans with dummy values
785 * - using the wp antispambot function
786 *
787 * @param string|array $display
788 * @return string Protected display
789 */
790 public function get_protected_display( $display, $protection_method = null ) {
791
792 $convert_plain_to_image = (bool) $this->getSetting( 'convert_plain_to_image', true, 'filter_body' );
793 $protection_text = __( $this->getSetting( 'protection_text', true ), 'email-encoder-bundle' );
794 $raw_display = $display;
795
796 // get display out of array (result of preg callback)
797 if ( is_array( $display ) ) {
798 $display = $display[0];
799 }
800
801 if ( $convert_plain_to_image ) {
802 $display = '<img src="' . $this->generate_email_image_url( $display ) . '" />';
803 } elseif ( $protection_method !== 'without_javascript' ) {
804 $display = $this->dynamic_js_email_encoding( $display, $protection_text );
805 } else {
806 $display = $this->encode_email_css( $display );
807 }
808
809 return apply_filters( 'eeb/validate/get_protected_display', $display, $raw_display, $protection_method, $protection_text );
810
811 }
812
813 /**
814 * Dynamic email encoding with certain javascript methods
815 *
816 * @param string $email
817 * @param string $protection_text
818 * @return the encoded email
819 */
820 public function dynamic_js_email_encoding( $email, $protection_text = null ) {
821 $return = $email;
822 $rand = apply_filters( 'eeb/validate/random_encoding', rand(0,2), $email, $protection_text );
823
824 switch( $rand ) {
825 case 2:
826 $return = $this->encode_escape( $return, $protection_text );
827 break;
828 case 1:
829 $return = $this->encode_ascii( $return, $protection_text );
830 break;
831 default:
832 $return = $this->encode_ascii( $return, $protection_text );
833 break;
834 }
835
836 return $return;
837 }
838
839 public function encode_email_css( $display ) {
840 $deactivate_rtl = (bool) $this->getSetting( 'deactivate_rtl', true, 'filter_body' );
841
842 $stripped_display = strip_tags( $display );
843 $stripped_display = html_entity_decode( $stripped_display );
844
845 $length = strlen( $stripped_display );
846 $interval = ceil( min( 5, $length / 2 ) );
847 $offset = 0;
848 $dummy_data = time();
849 $protected = '';
850 $protection_classes = 'eeb';
851
852 if ( $deactivate_rtl ) {
853 $rev = $stripped_display;
854 $protection_classes .= ' eeb-nrtl';
855 } else {
856 // reverse string ( will be corrected with CSS )
857 $rev = strrev( $stripped_display );
858 $protection_classes .= ' eeb-rtl';
859 }
860
861
862 while ( $offset < $length ) {
863 $protected .= '<span class="eeb-sd">' . antispambot( substr( $rev, $offset, $interval ) ) . '</span>';
864
865 // setup dummy content
866 $protected .= '<span class="eeb-nodis">' . $dummy_data . '</span>';
867 $offset += $interval;
868 }
869
870 $protected = '<span class="' . $protection_classes . '">' . $protected . '</span>';
871
872 return $protected;
873 }
874
875 public function email_to_image( $email, $image_string_color = 'default', $image_background_color = 'default', $alpha_string = 0, $alpha_fill = 127, $font_size = 4 ) {
876
877 $setting_image_string_color = (string) $this->getSetting( 'image_color', true, 'image_settings' );
878 $setting_image_background_color = (string) $this->getSetting( 'image_background_color', true, 'image_settings' );
879 $image_text_opacity = (int) $this->getSetting( 'image_text_opacity', true, 'image_settings' );
880 $image_background_opacity = (int) $this->getSetting( 'image_background_opacity', true, 'image_settings' );
881 $image_font_size = (int) $this->getSetting( 'image_font_size', true, 'image_settings' );
882 $image_underline = (int) $this->getSetting( 'image_underline', true, 'image_settings' );
883 $border_padding = 0;
884 $border_offset = 2;
885 $border_height = ( is_numeric( $image_underline ) && ! empty( $image_underline ) ) ? intval( $image_underline ) : 0;
886
887 if ( $image_background_color === 'default' ) {
888 $image_background_color = $setting_image_background_color;
889 } else {
890 $image_background_color = '0,0,0';
891 }
892
893 $colors = explode( ',', $image_background_color );
894 $bg_red = $colors[0];
895 $bg_green = $colors[1];
896 $bg_blue = $colors[2];
897
898 if ( $image_string_color === 'default' ) {
899 $image_string_color = $setting_image_string_color;
900 } else {
901 $image_string_color = '0,0,0';
902 }
903
904 $colors = explode( ',', $image_string_color );
905 $string_red = $colors[0];
906 $string_green = $colors[1];
907 $string_blue = $colors[2];
908
909 if ( ! empty( $image_text_opacity ) && $image_text_opacity >= 0 && $image_text_opacity <= 127 ) {
910 $alpha_string = intval( $image_text_opacity );
911 }
912
913 if ( ! empty( $image_background_opacity ) && $image_background_opacity >= 0 && $image_background_opacity <= 127 ) {
914 $alpha_fill = intval( $image_background_opacity );
915 }
916
917 if ( ! empty( $image_font_size ) && $image_font_size >= 1 && $image_font_size <= 5 ) {
918 $font_size = intval( $image_font_size );
919 }
920
921 $img_width = imagefontwidth( $font_size ) * strlen( $email );
922 $img_height = imagefontheight( $font_size );
923
924 if ( ! empty( $border_height ) ) {
925 $img_real_height = $img_height + $border_offset + $border_height;
926 } else {
927 $img_real_height = $img_height;
928 }
929
930 $img = imagecreatetruecolor( $img_width, $img_real_height );
931 imagesavealpha( $img, true );
932 imagefill( $img, 0, 0, imagecolorallocatealpha ($img, $bg_red, $bg_green, $bg_blue, $alpha_fill ) );
933 imagestring( $img, $font_size, 0, 0, $email, imagecolorallocatealpha( $img, $string_red, $string_green, $string_blue, $alpha_string ) );
934
935
936 if ( ! empty( $border_height ) ) {
937 $border_fill = imagecolorallocatealpha ($img, $string_red, $string_green, $string_blue, $alpha_string );
938 imagefilledrectangle( $img, 0, $border_offset + $img_height + $border_height - 1, $border_padding + $img_width, $border_offset + $img_height, $border_fill );
939 }
940
941 ob_start();
942 imagepng( $img );
943 imagedestroy( $img );
944
945 return ob_get_clean ();
946 }
947
948 public function generate_email_signature( $email, $secret ) {
949
950 if ( ! $secret ) {
951 return false;
952 }
953
954 $hash_signature = apply_filters( 'eeb/validate/email_signature', 'sha256', $email );
955
956 return base64_encode( hash_hmac( $hash_signature, $email, $secret, true ) );
957 }
958
959 public function generate_email_image_url( $email ) {
960
961 if ( ! function_exists( 'imagefontwidth' ) || empty( $email ) || ! is_email( $email ) ) {
962 return false;
963 }
964
965 $secret = $this->settings()->get_email_image_secret();
966 $signature = $this->generate_email_signature( $email, $secret );
967 $url = home_url() . '?eeb_mail=' . urlencode( base64_encode( $email ) ) . '&eeb_hash=' . urlencode( $signature );
968
969 $url = apply_filters( 'eeb/validate/generate_email_image_url', $url, $email );
970
971 return $url;
972 }
973
974 /**
975 * ######################
976 * ###
977 * #### ENCODER FORM
978 * ###
979 * ######################
980 */
981
982 /**
983 * Get the encoder form (to use as a demo, like on the options page)
984 * @return string
985 */
986 public function get_encoder_form() {
987 $powered_by_setting = (bool) $this->getSetting( 'powered_by', true, 'encoder_form' );
988
989 //shorten circle
990 if (
991 ! $this->helper()->is_page( $this->page_name )
992 && ! (bool) $this->getSetting( 'encoder_form_frontend', true, 'encoder_form' )
993 ) {
994 return apply_filters('eeb_form_content_inactive', '' );
995 }
996
997 $powered_by = '';
998 if ($powered_by_setting) {
999 $powered_by .= '<p class="powered-by">' . __('Powered by free', 'email-encoder-bundle') . ' <a rel="external" href="https://wordpress.org/plugins/email-encoder-bundle/">Email Encoder</a></p>';
1000 }
1001
1002 $smethods = array(
1003 'rot13' => __( 'Rot13 (Javascript)', 'email-encoder-bundle' ),
1004 'escape' => __( 'Escape (Javascript)', 'email-encoder-bundle' ),
1005 'encode' => __( 'Encode (HTML)', 'email-encoder-bundle' ),
1006 );
1007 $method_options = '';
1008 $selected = false;
1009 foreach( $smethods as $method_name => $name ) {
1010 $method_options .= '<option value="' . $method_name . '"' . ( ($selected === false ) ? ' selected="selected"' : '') . '>' . $name . '</option>';
1011 $selected = true;
1012 }
1013
1014 $labels = array(
1015 'email' => __( 'Email Address:', 'email-encoder-bundle' ),
1016 'display' => __( 'Display Text:', 'email-encoder-bundle' ),
1017 'mailto' => __( 'Mailto Link:', 'email-encoder-bundle' ),
1018 'method' => __( 'Encoding Method:', 'email-encoder-bundle' ),
1019 'create_link' => __( 'Create Protected Mail Link &gt;&gt;', 'email-encoder-bundle' ),
1020 'output' => __( 'Protected Mail Link (code):', 'email-encoder-bundle' ),
1021 'powered_by' => $powered_by,
1022 );
1023
1024 extract( $labels );
1025
1026 $form = <<<FORM
1027 <div class="eeb-form">
1028 <form>
1029 <fieldset>
1030 <div class="input">
1031 <table>
1032 <tbody>
1033 <tr>
1034 <th><label for="eeb-email">{$email}</label></th>
1035 <td><input type="text" class="regular-text" id="eeb-email" name="eeb-email" /></td>
1036 </tr>
1037 <tr>
1038 <th><label for="eeb-display">{$display}</label></th>
1039 <td><input type="text" class="regular-text" id="eeb-display" name="eeb-display" /></td>
1040 </tr>
1041 <tr>
1042 <th>{$mailto}</th>
1043 <td><span class="eeb-example"></span></td>
1044 </tr>
1045 <tr>
1046 <th><label for="eeb-encode-method">{$method}</label></th>
1047 <td><select id="eeb-encode-method" name="eeb-encode-method" class="postform">
1048 {$method_options}
1049 </select>
1050 <input type="button" id="eeb-ajax-encode" name="eeb-ajax-encode" value="{$create_link}" />
1051 </td>
1052 </tr>
1053 </tbody>
1054 </table>
1055 </div>
1056 <div class="eeb-output">
1057 <table>
1058 <tbody>
1059 <tr>
1060 <th><label for="eeb-encoded-output">{$output}</label></th>
1061 <td><textarea class="large-text node" id="eeb-encoded-output" name="eeb-encoded-output" cols="50" rows="4"></textarea></td>
1062 </tr>
1063 </tbody>
1064 </table>
1065 </div>
1066 {$powered_by}
1067 </fieldset>
1068 </form>
1069 </div>
1070 FORM;
1071
1072 // apply filters
1073 $form = apply_filters('eeb_form_content', $form, $labels, $powered_by_setting );
1074
1075 return $form;
1076 }
1077
1078
1079 public function is_post_excluded( $post_id = null ) {
1080
1081 $return = false;
1082 $skip_posts = (string) $this->getSetting( 'skip_posts', true );
1083 if ( ! empty( $skip_posts ) ) {
1084
1085 if ( empty( $post_id ) ) {
1086 global $post;
1087 if ( ! empty( $post ) ) {
1088 $post_id = $post->ID;
1089 }
1090 } else {
1091 $post_id = intval( $post_id );
1092 }
1093
1094 $exclude_pages = explode( ',', $skip_posts );
1095
1096 if ( is_array( $exclude_pages ) ) {
1097 $exclude_pages_validated = array();
1098
1099 foreach( $exclude_pages as $spost_id ) {
1100 $spost_id = trim($spost_id);
1101 if ( is_numeric( $spost_id ) ) {
1102 $exclude_pages_validated[] = intval( $spost_id );
1103 }
1104 }
1105
1106 if ( in_array( $post_id, $exclude_pages_validated ) ) {
1107 $return = true;
1108 }
1109 }
1110
1111 }
1112
1113 return apply_filters( 'eeb/validate/is_post_excluded', $return, $post_id, $skip_posts );
1114 }
1115
1116 /**
1117 * Filter if to exclude specific URL parameters from filtering
1118 *
1119 * @since 2.2.0
1120 * @param array $parameters
1121 * @return boolean
1122 */
1123 public function is_query_parameter_excluded( $parameters = null ) {
1124
1125 if ( $parameters === null ) {
1126 $parameters = $_GET;
1127 }
1128
1129 $return = false;
1130 $skip_query_parameters = (string) $this->getSetting( 'skip_query_parameters', true );
1131 if ( ! empty( $skip_query_parameters ) && ! empty( $parameters ) ) {
1132
1133 $excluded_parameters = explode( ',', $skip_query_parameters );
1134
1135 if ( is_array( $excluded_parameters ) ) {
1136
1137 foreach( $excluded_parameters as $param ) {
1138 $param = trim($param);
1139
1140 if ( isset( $parameters[ $param ] ) ) {
1141 $return = true;
1142 break;
1143 }
1144 }
1145
1146 }
1147
1148 }
1149
1150 return apply_filters( 'eeb/validate/is_query_parameter_excluded', $return, $parameters );
1151 }
1152 }
1153