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 1477 2011-07-21 02:47:28Z 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-07-21 04:47:28 +0200 (Thu, 21 Jul 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
			{
64
				define('SYS_HTTPS', false);
65
				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '80') ? ':'.$_SERVER['SERVER_PORT'] : '') );
66
				define('SYS_PROTOCOL', 'http');
67
			}else
68
			{
69
				define('SYS_HTTPS', true);
70
				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '443') ? ':'.$_SERVER['SERVER_PORT'] : '') );
71
				define('SYS_PROTOCOL', 'https');
72
			}
73
			$tmp = '';
74
			if( isset($_SERVER['HTTP_HOST']) )
75
			{
76
				$tmp = $_SERVER['HTTP_HOST'];
77
			}elseif( isset($_SERVER['SERVER_NAME']) )
78
			{
79
				$tmp = $_SERVER['SERVER_NAME'];
80
			}
81

    
82
			define('WB_HOST', preg_replace('/:[0-9]*$/', '', $tmp));
83
	        $location = SYS_PROTOCOL.'://'.WB_HOST.SYS_PORT;
84

    
85
        }
86

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

    
92
		// only filter output if we are supposed to
93
		if($filter_settings['email_filter'] != '1' && $filter_settings['mailto_filter'] != '1'){
94
			$searchfor = '/(<.*?=\s*?\")(?:'.preg_quote($location, '/').')(.*?\".*?>)/i';
95
			$content = preg_replace($searchfor, '$1$2', $content);
96
			return $content;
97
		}
98

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

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

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

    
148

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

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

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

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

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

    
230
			} else {
231
				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
232

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