Project

General

Profile

1
<?php
2
/**
3
 *
4
 * @category        modules
5
 * @package         output_filter
6
 * @author          WebsiteBaker Project
7
 * @copyright       2004-2009, Ryan Djurovich
8
 * @copyright       2009-2011, Website Baker Org. e.V.
9
 * @link			http://www.websitebaker2.org/
10
 * @license         http://www.gnu.org/licenses/gpl.html
11
 * @platform        WebsiteBaker 2.8.x
12
 * @requirements    PHP 5.2.2 and higher
13
 * @version         $Id: filter-routines.php 1513 2011-10-04 00:37:55Z Luisehahne $
14
 * @filesource		$HeadURL: svn://isteam.dynxs.de/wb-archiv/branches/2.8.x/wb/modules/output_filter/filter-routines.php $
15
 * @lastmodified    $Date: 2011-10-04 02:37:55 +0200 (Tue, 04 Oct 2011) $
16
 *
17
 */
18

    
19
// Must include code to stop this file being access directly
20
if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
21

    
22
// function to read the current filter settings
23
if (!function_exists('get_output_filter_settings')) {
24
	function get_output_filter_settings() {
25
		global $database, $admin;
26
	// be sure field is in table (suppresses strict warning)
27
		$table_name = TABLE_PREFIX .'mod_output_filter';
28
		$field_name = 'sys_rel';
29
		$description = 'VARCHAR(1) NOT NULL DEFAULT \'0\'';
30
		$msg_flag = ($database->field_add($table_name,$field_name,$description ));
31
		// connect to database and read out filter settings
32
		$result = $database->query("SELECT * FROM " .TABLE_PREFIX ."mod_output_filter");
33
		if($result && $result->numRows() > 0) {
34
			// get all data
35
			$data = $result->fetchRow();
36
			$filter_settings['sys_rel'] = $admin->strip_slashes($data['sys_rel']);
37
			$filter_settings['email_filter'] = $admin->strip_slashes($data['email_filter']);
38
			$filter_settings['mailto_filter'] = $admin->strip_slashes($data['mailto_filter']);
39
			$filter_settings['at_replacement'] = $admin->strip_slashes($data['at_replacement']);
40
			$filter_settings['dot_replacement'] = $admin->strip_slashes($data['dot_replacement']);
41
		} else {
42
			// something went wrong, use default values
43
			$filter_settings['sys_rel'] = '0';
44
			$filter_settings['email_filter'] = '0';
45
			$filter_settings['mailto_filter'] = '0';
46
			$filter_settings['at_replacement'] = '(at)';
47
			$filter_settings['dot_replacement'] = '(dot)';
48
		}
49
		
50
		// return array with filter settings
51
		return $filter_settings;
52
	}
53
}
54

    
55
// function to filter the output before displaying it on the frontend
56
if (!function_exists('filter_frontend_output')) {
57
	function filter_frontend_output($content) {
58
		// get output filter settings from database
59
		$filter_settings = get_output_filter_settings();
60
		$location = '';
61
		if($filter_settings['sys_rel'] == '1'){
62
			if( !isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off' ) {
63
				define('SYS_HTTPS', false);
64
				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '80') ? ':'.$_SERVER['SERVER_PORT'] : '') );
65
				define('SYS_PROTOCOL', 'http');
66
			} else {
67
				define('SYS_HTTPS', true);
68
				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '443') ? ':'.$_SERVER['SERVER_PORT'] : '') );
69
				define('SYS_PROTOCOL', 'https');
70
			}
71
			$tmp = '';
72
			if( isset($_SERVER['HTTP_HOST']) ) {
73
				$tmp = $_SERVER['HTTP_HOST'];
74
			} elseif( isset($_SERVER['SERVER_NAME']) ) {
75
				$tmp = $_SERVER['SERVER_NAME'];
76
			}
77

    
78
			define('WB_HOST', preg_replace('/:[0-9]*$/', '', $tmp));
79
			$location = SYS_PROTOCOL.'://'.WB_HOST.SYS_PORT;
80
			$searchfor = '/(<.*?=\s*?\")(?:'.preg_quote($location, '/').'\/?)(.*?\".*?>)/i';
81
			$content = preg_replace($searchfor, '$1/$2', $content);
82
			$content = preg_replace('/(<.*?(?:href|src)\s*=\s*?\")(\".*?>)/i', '$1/$2', $content);
83

    
84
		}
85

    
86
		// work out the defined output filter mode: possible output filter modes: [0], 1, 2, 3, 6, 7
87
		// 2^0 * (0.. disable, 1.. enable) filtering of mail addresses in text
88
		// 2^1 * (0.. disable, 1.. enable) filtering of mail addresses in mailto links
89
		// 2^2 * (0.. disable, 1.. enable) Javascript mailto encryption (only if mailto filtering enabled)
90

    
91
		// only filter output if we are supposed to
92
		if($filter_settings['email_filter'] != '1' && $filter_settings['mailto_filter'] != '1'){
93
			// do nothing more
94
			return $content;
95
		}
96

    
97
		// check if non mailto mail addresses needs to be filtered
98
		$output_filter_mode = ($filter_settings['email_filter'] == '1') ? 1 : 0;		// 0|1
99

    
100
		// check if mailto mail addresses needs to be filtered
101
		if($filter_settings['mailto_filter'] == '1') {
102
			$output_filter_mode = $output_filter_mode + 2;								// 0|2
103

    
104
			// check if Javascript mailto encryption is enabled (call register_frontend_functions in the template)
105
           $search_pattern = '/<.*src=\".*\/mdcr.js.*>/iU';
106
           if(preg_match($search_pattern, $content))
107
           {
108
            $output_filter_mode = $output_filter_mode + 4;       // 0|4
109
           }
110
/*
111
			$search = '<script src="' .WB_URL .'/modules/output_filter/js/mdcr.js" type="text/javascript"></script>';
112
			$search_droplet = '<script src="' .WB_URL .'/modules/droplets/js/mdcr.js" type="text/javascript"></script>';
113
			if(strpos($content, $search) !== false || strpos($content, $search_droplet) !== false) {
114
				$output_filter_mode = $output_filter_mode + 4;							// 0|4
115
			}
116
*/
117
		}
118
		
119
		// define some constants so we do not call the database in the callback function again
120
		define('OUTPUT_FILTER_MODE', (int) $output_filter_mode);
121
		define('OUTPUT_FILTER_AT_REPLACEMENT', $filter_settings['at_replacement']);
122
		define('OUTPUT_FILTER_DOT_REPLACEMENT', $filter_settings['dot_replacement']);
123
		
124
		// first search part to find all mailto email addresses
125
		$pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>';
126
		// second part to find all non mailto email addresses
127
		$pattern .= '|(value\s*=\s*"|\')??\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b#i';
128
		/*
129
		Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)			-->	"<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
130
		Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})			-->	the email address in the mailto: part of the mail link
131
		Sub 3:([^"]*?)"												--> possible ?Subject&cc... stuff attached to the mail address
132
		Sub 4:([^>]*>)												--> all class or id statements after the mailto but before closing ..>
133
		Sub 5:(.*?)</a>\b											--> the mailto text; all characters between >xxxxx</a>
134
		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)
135
		*/
136
			
137
		// find all email addresses embedded in the content and filter them using a callback function
138
		$content = preg_replace_callback($pattern, 'filter_mail_addresses', $content);
139
		// href can't be empty
140
		$searchfor = '/(<.*?=\s*?\")(?:'.preg_quote($location, '/').')(.*?\".*?>)/i';
141
		$content = preg_replace($searchfor, '$1$2', $content);
142
		return $content;
143
	}
144
}		
145

    
146

    
147
// function to filter mail addresses embedded in text or mailto links before outputing them on the frontend
148
if (!function_exists('filter_mail_addresses')) {
149
	function filter_mail_addresses($match) { 
150
		
151
		// check if required output filter mode is defined
152
		if(!(defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE'))) {
153
			return $match[0];
154
		}
155
		
156
		$search = array('@', '.');
157
		$replace = array(OUTPUT_FILTER_AT_REPLACEMENT ,OUTPUT_FILTER_DOT_REPLACEMENT);
158
		
159
		// check if the match contains the expected number of subpatterns (6|8)
160
		if(count($match) == 8) {
161
			/**
162
				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT
163
			**/
164
			
165
			// 1.. text mails only, 3.. text mails + mailto (no JS), 7 text mails + mailto (JS)
166
			if(!in_array(OUTPUT_FILTER_MODE, array(1,3,7))) return $match[0];
167

    
168
			// do not filter mail addresses included in input tags (<input ... value = "test@mail)
169
			if (strpos($match[6], 'value') !== false) return $match[0];
170
			
171
			// filtering of non mailto email addresses enabled
172
			return str_replace($search, $replace, $match[0]);
173
				
174
		} elseif(count($match) == 6) {
175
			/**
176
				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS
177
			**/
178

    
179
			// 2.. mailto only (no JS), 3.. text mails + mailto (no JS), 6.. mailto only (JS), 7.. all filters active
180
			if(!in_array(OUTPUT_FILTER_MODE, array(2,3,6,7))) return $match[0];
181
			
182
			// check if last part of the a href link: >xxxx</a> contains a email address we need to filter
183
			$pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
184
			if(preg_match_all($pattern, $match[5], $matches)) {
185
				foreach($matches as $submatch) {
186
					foreach($submatch as $value) {
187
						// replace all . and all @ in email address parts by (dot) and (at) strings
188
						$match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
189
					}
190
				}
191
			}
192

    
193
			// check if Javascript encryption routine is enabled
194
			if(in_array(OUTPUT_FILTER_MODE, array(6,7))) {
195
				/** USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
196
				
197
				// extract possible class and id attribute from ahref link
198
				preg_match('/class\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $class_attr);
199
				$class_attr = empty($class_attr) ? '' : 'class="' . $class_attr[2] . '" ';
200
				preg_match('/id\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $id_attr);
201
				$id_attr = empty($id_attr) ? '' : 'id="' . $id_attr[2] . '" ';
202
				
203
				// preprocess mailto link parts for further usage
204
				$search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
205
				$email_address = str_replace($search, $replace, strtolower($match[2]));
206
				$email_subject = rawurlencode(html_entity_decode($match[3]));
207
				
208
				// create a random encryption key for the Caesar cipher
209
				mt_srand((double)microtime()*1000000);	// (PHP < 4.2.0)
210
				$shift = mt_rand(1, 25);
211
				
212
				// encrypt the email using an adapted Caesar cipher
213
		  		$encrypted_email = "";
214
				for($i = strlen($email_address) -1; $i > -1; $i--) {
215
					if(preg_match('#[FZXK0-9]#', $email_address[$i], $characters)) {
216
						$encrypted_email .= $email_address[$i];
217
					} else {	
218
						$encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
219
					}
220
				}
221
				$encrypted_email .= chr($shift + 97);
222

    
223
				// build the encrypted Javascript mailto link
224
				$mailto_link  = "<a {$class_attr}{$id_attr}href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
225
				
226
				return $mailto_link;	
227

    
228
			} else {
229
				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
230

    
231
				// as minimum protection, replace replace @ in the mailto part by (at)
232
				// dots are not transformed as this would transform my.name@domain.com into: my(dot)name(at)domain(dot)com
233
				
234
				// rebuild the mailto link from the subpatterns (at the missing characters " and </a>")
235
				return $match[1] .str_replace('@', OUTPUT_FILTER_AT_REPLACEMENT, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
236
				// if you want to protect both, @ and dots, comment out the line above and remove the comment from the line below
237
				// return $match[1] .str_replace($search, $replace, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
238
			}
239
		
240
		}
241
		
242
		// number of subpatterns do not match the requirements ... do nothing
243
		return $match[0];
244
	}		
245
}
(2-2/8)