PluginProbe ʕ •ᴥ•ʔ
Email Encoder – Protect Email Addresses and Phone Numbers / 2.4.3
Email Encoder – Protect Email Addresses and Phone Numbers v2.4.3
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 / src / Validate / Encoding.php
email-encoder-bundle / src / Validate Last commit date
EncoderForm.php 4 months ago Encoding.php 4 months ago Filters.php 4 months ago Validate.php 4 months ago
Encoding.php
584 lines
1 <?php
2
3 namespace OnlineOptimisation\EmailEncoderBundle\Validate;
4
5 use OnlineOptimisation\EmailEncoderBundle\Traits\PluginHelper;
6
7 class Encoding
8 {
9 use PluginHelper;
10
11 private string $at_identifier;
12
13 public function boot(): void
14 {
15 $this->at_identifier = $this->settings()->get_at_identifier();
16 }
17
18
19 /**
20 * ######################
21 * ###
22 * #### ENCODINGS
23 * ###
24 * ######################
25 */
26
27 /**
28 * @param string $content
29 * @param bool $decode
30 * @return string
31 */
32 public function temp_encode_at_symbol( string $content, bool $decode = false )
33 {
34 if ( $decode ) {
35 return str_replace( $this->at_identifier, '@', $content );
36 }
37
38 return str_replace( '@', $this->at_identifier, $content );
39 }
40
41 /**
42 * ASCII method
43 *
44 * @param string $value
45 * @param string $protection_text
46 * @return string
47 */
48 public function encode_ascii( $value, $protection_text )
49 {
50 $mail_link = $value;
51
52 // first encode, so special chars can be supported
53 $mail_link = $this->helper()->encode_uri_components( $mail_link );
54
55 $mail_letters = '';
56
57 for ( $i = 0; $i < strlen( $mail_link ); $i++ ) {
58 $l = substr($mail_link, $i, 1);
59
60 if (strpos($mail_letters, $l) === false) {
61 $p = rand(0, strlen($mail_letters));
62 $mail_letters = substr($mail_letters, 0, $p) .
63 $l . substr($mail_letters, $p, strlen($mail_letters));
64 }
65 }
66
67 $mail_letters_enc = str_replace( "\\", "\\\\", $mail_letters );
68 $mail_letters_enc = str_replace( "\"", "\\\"", $mail_letters_enc );
69
70 $mail_indices = '';
71 for ( $i = 0; $i < strlen( $mail_link ); $i++ ) {
72 $index = strpos( $mail_letters, substr( $mail_link, $i, 1 ) );
73 $index += 48;
74 $mail_indices .= chr( $index );
75 }
76
77 $mail_indices = str_replace("\\", "\\\\", $mail_indices);
78 $mail_indices = str_replace("\"", "\\\"", $mail_indices);
79
80 $element_id = 'eeb-' . mt_rand( 0, 1000000 ) . '-' . mt_rand(0, 1000000);
81
82 return '<span id="' . $element_id . '"></span>'
83 . '<script type="text/javascript">'
84 . '(function() {'
85 . 'var ml="' . $mail_letters_enc . '",mi="' . $mail_indices . '",o="";'
86 . 'for(var j=0,l=mi.length;j<l;j++) {'
87 . 'o+=ml.charAt(mi.charCodeAt(j)-48);'
88 . '}document.getElementById("' . $element_id . '").innerHTML = decodeURIComponent(o);' // decode at the end, this way special chars can be supported
89 . '}());'
90 . '</script><noscript>'
91 . $protection_text
92 . '</noscript>'
93 ;
94 }
95
96 /**
97 * Escape encoding method
98 *
99 * @param string $value
100 * @param string $protection_text
101 * @return string
102 */
103 public function encode_escape( $value, $protection_text )
104 {
105 $element_id = 'eeb-' . mt_rand( 0, 1000000 ) . '-' . mt_rand( 0, 1000000 );
106 $string = '\'' . $value . '\'';
107
108 //Validate escape sequences
109 $string = preg_replace('/\s+/S', " ", $string) ?? '';
110
111 // break string into array of characters, we can't use string_split because its php5 only
112 $split = preg_split( '||', $string );
113 $out = '<span id="' . $element_id . '"></span>'
114 . '<script type="text/javascript">' . 'document.getElementById("' . $element_id . '").innerHTML = ev' . 'al(decodeURIComponent("';
115
116 if ( is_array( $split ) )
117 foreach ( $split as $c ) {
118 // preg split will return empty first and last characters, check for them and ignore
119 if ( ! empty( $c ) || $c === '0' ) {
120 $out .= '%' . dechex( ord( $c ) );
121 }
122 }
123
124 $out .= '"))' . '</script><noscript>'
125 . $protection_text
126 . '</noscript>';
127
128 return $out;
129 }
130
131 /**
132 * Encode email in input field
133 * @param string $input
134 * @param string $email
135 * @param bool $strongEncoding
136 * @return string
137 */
138 public function encode_input_field( $input, $email, $strongEncoding = false )
139 {
140
141 $show_encoded_check = (bool) $this->getSetting( 'show_encoded_check', true );
142
143 if ( $strongEncoding === false ) {
144 // encode email with entities (default wp method)
145 $sub_return = str_replace( $email, antispambot( $email ), $input );
146
147 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
148 $sub_return .= $this->get_encoded_email_icon();
149 }
150
151 return $sub_return;
152 }
153
154 // add data-enc-email after "<input"
155 $inputWithDataAttr = substr( $input, 0, 6 );
156 $inputWithDataAttr .= ' data-enc-email="' . $this->get_encoded_email( $email ) . '"';
157 $inputWithDataAttr .= substr( $input, 6 );
158
159 // mark link as successfullly encoded (for admin users)
160 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
161 $inputWithDataAttr .= $this->get_encoded_email_icon();
162 }
163
164 // remove email from value attribute
165 $encInput = str_replace( $email, '', $inputWithDataAttr );
166
167 return $encInput;
168 }
169
170 /**
171 * Get encoded email, used for data-attribute (translate by javascript)
172 *
173 * @param string $email
174 * @return string
175 */
176 public function get_encoded_email( $email )
177 {
178 $encEmail = $email;
179
180 // decode entities
181 $encEmail = html_entity_decode( $encEmail );
182
183 // rot13 encoding
184 $encEmail = str_rot13( $encEmail );
185
186 // replace @
187 $encEmail = str_replace( '@', '[at]', $encEmail );
188
189 return $encEmail;
190 }
191
192 /**
193 * Get the ebcoded email icon
194 *
195 * @param string $text
196 * @return string
197 */
198 public function get_encoded_email_icon( $text = 'Email encoded successfully!' )
199 {
200
201 $html = '<i class="eeb-encoded dashicons-before dashicons-lock" title="' . __( $text, 'email-encoder-bundle' ) . '"></i>';
202
203 return apply_filters( 'eeb/validate/get_encoded_email_icon', $html, $text );
204 }
205
206 /**
207 * Create a protected email
208 *
209 * @param string $display
210 * @param array< string, string > $attrs
211 * @param string $protection_method
212 * @return string
213 */
214 public function create_protected_mailto( $display, $attrs = [], $protection_method = null )
215 {
216 $email = '';
217 $class_ori = ( empty( $attrs['class'] ) ) ? '' : $attrs['class'];
218 $custom_class = (string) $this->getSetting( 'class_name', true );
219 $show_encoded_check = (string) $this->getSetting( 'show_encoded_check', true );
220
221 // set user-defined class
222 if ( $custom_class !== '' && strpos( $class_ori, $custom_class ) === false ) {
223 $attrs['class'] = ( empty( $attrs['class'] ) ) ? $custom_class : $attrs['class'] . ' ' . $custom_class;
224 }
225
226 // check title for email address
227 if ( ! empty( $attrs['title'] ) ) {
228 $attrs['title'] = $this->filterPlainEmails( $attrs['title'], '{{email}}' ); // {{email}} will be replaced in javascript
229 }
230
231 // set ignore to data-attribute to prevent being processed by WPEL plugin
232 $attrs['data-wpel-link'] = 'ignore';
233
234 // create element code
235 $link = '<a ';
236
237 foreach ( $attrs as $key => $value ) {
238 if ( strtolower( $key ) === 'href' ) {
239 if ( $protection_method === 'without_javascript' ) {
240 $link .= $key . '="' . antispambot( $value ) . '" ';
241 } else {
242 // get email from href
243 $email = substr($value, 7);
244
245 $encoded_email = $this->get_encoded_email( $email );
246
247 // set attrs
248 $link .= 'href="javascript:;" ';
249 $link .= 'data-enc-email="' . $encoded_email . '" ';
250 }
251
252 } else {
253 $link .= $key . '="' . $value . '" ';
254 }
255 }
256
257 // remove last space
258 $link = substr( $link, 0, -1 );
259
260 $link .= '>';
261
262 $link .= ( preg_match( $this->settings()->get_email_regex(), $display) > 0 ) ? $this->get_protected_display( $display, $protection_method ) : $display;
263
264 $link .= '</a>';
265
266 // filter
267 $link = apply_filters( 'eeb_mailto', $link, $display, $email, $attrs );
268
269 // just in case there are still email addresses f.e. within title-tag
270 $link = $this->filterPlainEmails( $link, null, 'char_encode' );
271
272 // mark link as successfullly encoded (for admin users)
273 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check !== '' ) {
274 $link .= $this->get_encoded_email_icon();
275 }
276
277
278 return $link;
279 }
280
281 /**
282 * Create a protected custom attribute
283 *
284 * @param string $display
285 * @param array< string, string > $attrs Optional
286 * @param string $protection_method
287 * @return string
288 */
289 public function create_protected_href_att( $display, $attrs = [], $protection_method = null )
290 {
291 $email = '';
292 $class_ori = ( empty( $attrs['class'] ) ) ? '' : $attrs['class'];
293 $custom_class = (string) $this->getSetting( 'class_name', true );
294 $show_encoded_check = (string) $this->getSetting( 'show_encoded_check', true );
295
296 // set user-defined class
297 if ( $custom_class !== '' && strpos( $class_ori, $custom_class ) === false ) {
298 $attrs['class'] = ( empty( $attrs['class'] ) ) ? $custom_class : $attrs['class'] . ' ' . $custom_class;
299 }
300
301 // check title for email address
302 if ( ! empty( $attrs['title'] ) ) {
303 $attrs['title'] = antispambot( $attrs['title'] );
304 }
305
306 // set ignore to data-attribute to prevent being processed by WPEL plugin
307 $attrs['data-wpel-link'] = 'ignore';
308
309 // create element code
310 $link = '<a ';
311
312 foreach ( $attrs as $key => $value ) {
313 if ( strtolower( $key ) === 'href' ) {
314 $link .= $key . '="' . antispambot( $value ) . '" ';
315 } else {
316 $link .= $key . '="' . $value . '" ';
317 }
318 }
319
320 // remove last space
321 $link = substr( $link, 0, -1 );
322
323 $link .= '>';
324
325 $link .= $this->get_protected_display( $display, $protection_method );
326
327 $link .= '</a>';
328
329 // filter
330 $link = apply_filters( 'eeb_custom_href', $link, $display, $email, $attrs );
331
332 // mark link as successfullly encoded (for admin users)
333 if ( current_user_can( $this->getAdminCap( 'frontend-display-security-check' ) ) && $show_encoded_check ) {
334 $link .= $this->get_encoded_email_icon( 'Custom attribute encoded successfully!' );
335 }
336
337
338 return $link;
339 }
340
341 /**
342 * Create protected display combining these 3 methods:
343 * - reversing string
344 * - adding no-display spans with dummy values
345 * - using the wp antispambot function
346 *
347 * @param string|array<string> $display
348 * @param string $protection_method
349 * @return string Protected display
350 */
351 public function get_protected_display( $display, $protection_method = null )
352 {
353
354 $convert_plain_to_image = (bool) $this->getSetting( 'convert_plain_to_image', true, 'filter_body' );
355 $protection_text = __( $this->getSetting( 'protection_text', true ), 'email-encoder-bundle' );
356 $raw_display = $display;
357
358 // get display out of array (result of preg callback)
359 if ( is_array( $display ) ) {
360 $display = $display[0];
361 }
362
363 if ( $convert_plain_to_image ) {
364 $display = '<img src="' . $this->generate_email_image_url( $display ) . '" />';
365 } elseif ( $protection_method !== 'without_javascript' ) {
366 $display = $this->dynamic_js_email_encoding( $display, $protection_text );
367 } else {
368 $display = $this->encode_email_css( $display );
369 }
370
371 return apply_filters( 'eeb/validate/get_protected_display', $display, $raw_display, $protection_method, $protection_text );
372 }
373
374 /**
375 * Dynamic email encoding with certain javascript methods
376 *
377 * @param string $email
378 * @param string $protection_text
379 * @return string the encoded email
380 */
381 public function dynamic_js_email_encoding( $email, $protection_text = '' )
382 {
383 $return = $email;
384 $rand = apply_filters( 'eeb/validate/random_encoding', rand( 0, 2 ), $email, $protection_text );
385
386 switch ( $rand ) {
387 case 2:
388 $return = $this->encode_escape( $return, $protection_text );
389 break;
390 case 1:
391 $return = $this->encode_ascii( $return, $protection_text );
392 break;
393 default:
394 $return = $this->encode_ascii( $return, $protection_text );
395 break;
396 }
397
398 return $return;
399 }
400
401 /**
402 * @param string $display
403 * @return string
404 */
405 public function encode_email_css( $display )
406 {
407 $deactivate_rtl = (bool) $this->getSetting( 'deactivate_rtl', true, 'filter_body' );
408
409 // $this->log( 'display: ' . $display );
410 $stripped_display = strip_tags( $display );
411 $stripped_display = html_entity_decode( $stripped_display );
412
413 $length = strlen( $stripped_display );
414 $interval = (int) ceil( min( 5, $length / 2 ) );
415 $offset = 0;
416 $dummy_data = time();
417 $protected = '';
418 $protection_classes = 'eeb';
419
420 if ( $deactivate_rtl ) {
421 $rev = $stripped_display;
422 $protection_classes .= ' eeb-nrtl';
423 } else {
424 // reverse string ( will be corrected with CSS )
425 $rev = strrev( $stripped_display );
426 $protection_classes .= ' eeb-rtl';
427 }
428
429
430 while ( $offset < $length ) {
431 $protected .= '<span class="eeb-sd">' . antispambot( substr( $rev, $offset, $interval ) ) . '</span>';
432
433 // setup dummy content
434 $protected .= '<span class="eeb-nodis">' . $dummy_data . '</span>';
435 $offset += $interval;
436 }
437
438 $protected = '<span class="' . $protection_classes . '">' . $protected . '</span>';
439
440 return $protected;
441 }
442
443
444 /**
445 * @return string
446 */
447 public function email_to_image( string $email, string $image_string_color = 'default', string $image_background_color = 'default', int $alpha_string = 0, int $alpha_fill = 127, int $font_size = 4 )
448 {
449
450 $setting_image_string_color = (string) $this->getSetting( 'image_color', true, 'image_settings' );
451 $setting_image_background_color = (string) $this->getSetting( 'image_background_color', true, 'image_settings' );
452 $image_text_opacity = (int) $this->getSetting( 'image_text_opacity', true, 'image_settings' );
453 $image_background_opacity = (int) $this->getSetting( 'image_background_opacity', true, 'image_settings' );
454 $image_font_size = (int) $this->getSetting( 'image_font_size', true, 'image_settings' );
455 $border_height = (int) $this->getSetting( 'image_underline', true, 'image_settings' );
456 $border_padding = 0;
457 $border_offset = 2;
458
459 if ( $image_background_color === 'default' ) {
460 $image_background_color = $setting_image_background_color;
461 } else {
462 $image_background_color = '0,0,0';
463 }
464
465 $colors = explode( ',', $image_background_color );
466 $bg_red = max( 0, min( 255, (int) $colors[0] ) );
467 $bg_green = max( 0, min( 255, (int) $colors[1] ) );
468 $bg_blue = max( 0, min( 255, (int) $colors[2] ) );
469
470 if ( $image_string_color === 'default' ) {
471 $image_string_color = $setting_image_string_color;
472 } else {
473 $image_string_color = '0,0,0';
474 }
475
476 $colors = explode( ',', $image_string_color );
477 $string_red = max( 0, min( 255, (int) $colors[0] ) );
478 $string_green = max( 0, min( 255, (int) $colors[1] ) );
479 $string_blue = max( 0, min( 255, (int) $colors[2] ) );
480
481 if (
482 ! empty( $image_text_opacity )
483 && $image_text_opacity >= 0
484 && $image_text_opacity <= 127
485 ) {
486 $alpha_string = intval( $image_text_opacity );
487 }
488 $alpha_string = max( 0, min( 127, $alpha_string ) );
489
490 if (
491 ! empty( $image_background_opacity )
492 && $image_background_opacity >= 0
493 && $image_background_opacity <= 127
494 ) {
495 $alpha_fill = intval( $image_background_opacity );
496 }
497 $alpha_fill = max( 0, min( 127, $alpha_fill ) );
498
499 if ( ! empty( $image_font_size ) && $image_font_size >= 1 && $image_font_size <= 5 ) {
500 $font_size = intval( $image_font_size );
501 }
502
503 $img_width = max( 1, imagefontwidth( $font_size ) * strlen( $email ) );
504 $img_height = imagefontheight( $font_size );
505
506 if ( ! empty( $border_height ) ) {
507 $img_real_height = max( 1, $img_height + $border_offset + $border_height );
508 } else {
509 $img_real_height = max( 1, $img_height );
510 }
511
512 $img = imagecreatetruecolor( $img_width, $img_real_height );
513 imagesavealpha( $img, true );
514 imagefill( $img, 0, 0, max( 0, imagecolorallocatealpha($img, $bg_red, $bg_green, $bg_blue, $alpha_fill ) ) );
515 imagestring(
516 $img,
517 $font_size,
518 0,
519 0,
520 $email,
521 max( 0, imagecolorallocatealpha( $img, $string_red, $string_green, $string_blue, $alpha_string ) )
522 );
523
524
525 if ( ! empty( $border_height ) ) {
526 $border_fill = imagecolorallocatealpha ($img, $string_red, $string_green, $string_blue, $alpha_string );
527 imagefilledrectangle(
528 $img,
529 0,
530 $border_offset + $img_height + $border_height - 1,
531 $border_padding + $img_width,
532 $border_offset + $img_height,
533 max( 0, $border_fill )
534 );
535 }
536
537 ob_start();
538 imagepng( $img );
539 imagedestroy( $img );
540
541 return (string) ob_get_clean();
542 }
543
544
545 /**
546 * @param string $email
547 * @param string $secret
548 * @return string|bool
549 */
550 public function generate_email_signature( string $email, string $secret )
551 {
552
553 if ( ! $secret ) {
554 return false;
555 }
556
557 $hash_signature = apply_filters( 'eeb/validate/email_signature', 'sha256', $email );
558
559 return base64_encode( hash_hmac( $hash_signature, $email, $secret, true ) );
560 }
561
562 /**
563 * @param string $email
564 * @return string|bool
565 */
566 public function generate_email_image_url( ?string $email )
567 {
568 if ( ! function_exists( 'imagefontwidth' ) || empty( $email ) || ! is_email( $email ) ) {
569 return false;
570 }
571
572 $secret = $this->settings()->get_email_image_secret();
573 $signature = (string) $this->generate_email_signature( $email, $secret );
574 $url = home_url();
575 $url .= '?eeb_mail=' . urlencode( base64_encode( $email ) );
576 $url .= '&eeb_hash=' . urlencode( $signature );
577
578 $url = apply_filters( 'eeb/validate/generate_email_image_url', $url, $email );
579
580 return $url;
581 }
582
583 }
584