Project

General

Profile

1
<?php
2
/**
3
 * protect email addresses (replace '@' and '.' and obfuscate address
4
 * @param string $content
5
 * @return string
6
 */
7
	function doFilterEmail($content, $output_filter_mode) {
8
	// test if js-decryption is installed
9
		if( preg_match('/<head.*<.*src=\".*\/mdcr.js.*>.*<\/head/siU', $content) ) {
10
			$output_filter_mode |= pow(2, 2); // n | 2^2
11
		}else {
12
		// try to insert js-decrypt into <head> if available
13
			$script = str_replace('\\', '/',str_replace(WB_PATH,'', dirname(__FILE__)).'/js/mdcr.js');
14
			if(is_readable(WB_PATH.$script)) {
15
				$scriptLink = '<script src="'.WB_URL.$script.'" type="text/javascript"></script>';
16
				$regex = '/(.*)(<\s*?\/\s*?head\s*>.*)/isU';
17
				$replace = '$1'.$scriptLink.'$2';
18
				$content = preg_replace ($regex, $replace, $content);
19
				$output_filter_mode |= pow(2, 2); // n | 2^2
20
			}
21
		}
22
	// define some constants so we do not call the database in the callback functions again
23
		define('OUTPUT_FILTER_MODE', (int)$output_filter_mode);
24
/* *** obfuscate mailto addresses by js:mdcr *** */
25
		// work out the defined output filter mode: possible output filter modes: [0], 1, 2, 3, 6, 7
26
		// 2^0 * (0.. disable, 1.. enable) filtering of mail addresses in text
27
		// 2^1 * (0.. disable, 1.. enable) filtering of mail addresses in mailto links
28
		// 2^2 * (0.. disable, 1.. enable) Javascript mailto encryption (only if mailto filtering enabled)
29

    
30
		// first search part to find all mailto email addresses
31
		$pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>';
32
		// second part to find all non mailto email addresses
33
		$pattern .= '|(value\s*=\s*"|\')??\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b#i';
34
/*
35
	Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)			-->	"<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
36
	Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})			-->	the email address in the mailto: part of the mail link
37
	Sub 3:([^"]*?)"												--> possible ?Subject&cc... stuff attached to the mail address
38
	Sub 4:([^>]*>)												--> all class or id statements after the mailto but before closing ..>
39
	Sub 5:(.*?)</a>\b											--> the mailto text; all characters between >xxxxx</a>
40
	Sub 6:|\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b		--> email addresses which may appear in the text (require word boundaries)
41
*/
42
		// find all email addresses embedded in the content and filter them using a callback function
43
		$content = preg_replace_callback($pattern, '_cbDoExecuteFilter', $content);
44
		return $content;
45
	}
46
/* ************************************************************************** */
47
/**
48
 * callback-function for function _doFilterEmail() to proceed search results
49
 * @param array results from preg_replace
50
 * @return string proceeded replacement string
51
 */
52
	function _cbDoExecuteFilter($match) {
53
		// check if required arguments are defined
54
		if(!( defined('OUTPUT_FILTER_MODE')
55
		      && defined('OUTPUT_FILTER_AT_REPLACEMENT')
56
		      && defined('OUTPUT_FILTER_MODE')
57
    	    ) ) {
58
			return $match[0];
59
		}
60
		$search = array('@', '.');
61
		$replace = array(OUTPUT_FILTER_AT_REPLACEMENT ,OUTPUT_FILTER_DOT_REPLACEMENT);
62
		// check if the match contains the expected number of subpatterns (6|8)
63
		switch (count($match)) {
64
			case 8:
65
			/** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT **/
66
			// 1.. text mails only, 3.. text mails + mailto (no JS), 7 text mails + mailto (JS)
67
				if(!in_array(OUTPUT_FILTER_MODE, array(1,3,7))) return $match[0];
68
				// do not filter mail addresses included in input tags (<input ... value = "test@mail)
69
				if (strpos($match[6], 'value') !== false) return $match[0];
70
				// filtering of non mailto email addresses enabled
71
				return str_replace($search, $replace, $match[0]);
72
			break;
73
			case 6:
74
			/** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS **/
75
			// 2.. mailto only (no JS), 3.. text mails + mailto (no JS), 6.. mailto only (JS), 7.. all filters active
76
				if(!in_array(OUTPUT_FILTER_MODE, array(2,3,6,7))) return $match[0];
77
				// check if last part of the a href link: >xxxx</a> contains a email address we need to filter
78
				$pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
79
				if(preg_match_all($pattern, $match[5], $matches)) {
80
					foreach($matches as $submatch) {
81
						foreach($submatch as $value) {
82
						// replace all . and all @ in email address parts by (dot) and (at) strings
83
							$match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
84
						}
85
					}
86
				}
87
				// check if Javascript encryption routine is enabled
88
				if(in_array(OUTPUT_FILTER_MODE, array(6,7))) {
89
				/** USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
90
				// extract possible class and id attribute from ahref link
91
					preg_match('/class\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $class_attr);
92
					$class_attr = empty($class_attr) ? '' : 'class="' . $class_attr[2] . '" ';
93
					preg_match('/id\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $id_attr);
94
					$id_attr = empty($id_attr) ? '' : 'id="' . $id_attr[2] . '" ';
95
				// preprocess mailto link parts for further usage
96
					$search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
97
					$email_address = str_replace($search, $replace, strtolower($match[2]));
98
					$email_subject = rawurlencode(html_entity_decode($match[3]));
99
				// create a random encryption key for the Caesar cipher
100
					mt_srand((double)microtime()*1000000);	// (PHP < 4.2.0)
101
					$shift = mt_rand(1, 25);
102
				// encrypt the email using an adapted Caesar cipher
103
					$encrypted_email = "";
104
					for($i = strlen($email_address) -1; $i > -1; $i--) {
105
						if(preg_match('#[FZXK0-9]#', $email_address[$i], $characters)) {
106
							$encrypted_email .= $email_address[$i];
107
						} else {
108
							$encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
109
						}
110
					}
111
					$encrypted_email .= chr($shift + 97);
112
				// build the encrypted Javascript mailto link
113
					$mailto_link  = "<a {$class_attr}{$id_attr}href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
114
					return $mailto_link;
115
				} else {
116
				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
117
				// as minimum protection, replace @ in the mailto part by (at)
118
				// dots are not transformed as this would transform my.name@domain.com into: my(dot)name(at)domain(dot)com
119
				// rebuild the mailto link from the subpatterns (at the missing characters " and </a>")
120
					return $match[1] .str_replace('@', OUTPUT_FILTER_AT_REPLACEMENT, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
121
				// if you want to protect both, @ and dots, comment out the line above and remove the comment from the line below
122
				// return $match[1] .str_replace($search, $replace, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
123
				}
124
			break;
125
			default:
126
		// number of subpatterns do not match the requirements ... do nothing
127
				return $match[0];
128
			break;
129
		}
130
	}
(3-3/6)