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 1475 2011-07-12 23:07:10Z 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-13 01:07:10 +0200 (Wed, 13 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
		// connect to database and read out filter settings
27
		$result = $database->query("SELECT * FROM " .TABLE_PREFIX ."mod_output_filter");
28
		if($result && $result->numRows() > 0) {
29
			// get all data
30
			$data = $result->fetchRow();
31
			$filter_settings['sys_rel'] = $admin->strip_slashes($data['sys_rel']);
32
			$filter_settings['email_filter'] = $admin->strip_slashes($data['email_filter']);
33
			$filter_settings['mailto_filter'] = $admin->strip_slashes($data['mailto_filter']);
34
			$filter_settings['at_replacement'] = $admin->strip_slashes($data['at_replacement']);
35
			$filter_settings['dot_replacement'] = $admin->strip_slashes($data['dot_replacement']);
36
		} else {
37
			// something went wrong, use default values
38
			$filter_settings['sys_rel'] = '0';
39
			$filter_settings['email_filter'] = '0';
40
			$filter_settings['mailto_filter'] = '0';
41
			$filter_settings['at_replacement'] = '(at)';
42
			$filter_settings['dot_replacement'] = '(dot)';
43
		}
44
		
45
		// return array with filter settings
46
		return $filter_settings;
47
	}
48
}
49

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

    
77
			define('WB_HOST', preg_replace('/:[0-9]*$/', '', $tmp));
78
	        $location = SYS_PROTOCOL.'://'.WB_HOST.SYS_PORT;
79

    
80
        }
81

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

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

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

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

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

    
143

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

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

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

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

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

    
225
			} else {
226
				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
227

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

    
244
?>
(2-2/8)