Project

General

Profile

1
<?php
2

    
3
// $Id: filter-routines.php 787 2008-04-02 17:26:45Z doc $
4

    
5
/*
6

    
7
 Website Baker Project <http://www.websitebaker.org/>
8
 Copyright (C) 2004-2008, Ryan Djurovich
9

    
10
 Website Baker is free software; you can redistribute it and/or modify
11
 it under the terms of the GNU General Public License as published by
12
 the Free Software Foundation; either version 2 of the License, or
13
 (at your option) any later version.
14

    
15
 Website Baker is distributed in the hope that it will be useful,
16
 but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 GNU General Public License for more details.
19

    
20
 You should have received a copy of the GNU General Public License
21
 along with Website Baker; if not, write to the Free Software
22
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23

    
24
*/
25

    
26
// prevent this file from being accessed directly
27
if(!defined('WB_PATH')) die(header('Location: ../index.php'));
28

    
29
// function to read the current filter settings
30
if (!function_exists('get_output_filter_settings')) {
31
	function get_output_filter_settings() {
32
		global $database, $admin;
33
		// connect to database and read out filter settings
34
		$result = $database->query("SELECT * FROM " .TABLE_PREFIX ."mod_output_filter");
35
		if($result->numRows() > 0) {
36
			// get all data
37
			$data = $result->fetchRow();
38
			$filter_settings['email_filter'] = $admin->strip_slashes($data['email_filter']);
39
			$filter_settings['mailto_filter'] = $admin->strip_slashes($data['mailto_filter']);
40
			$filter_settings['at_replacement'] = $admin->strip_slashes($data['at_replacement']);
41
			$filter_settings['dot_replacement'] = $admin->strip_slashes($data['dot_replacement']);
42
		} else {
43
			// something went wrong, use default values
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
		
61
		// work out the defined output filter mode: possible output filter modes: [0], 1, 2, 3, 6, 7
62
		// 2^0 * (0.. disable, 1.. enable) filtering of mail addresses in text
63
		// 2^1 * (0.. disable, 1.. enable) filtering of mail addresses in mailto links
64
		// 2^2 * (0.. disable, 1.. enable) Javascript mailto encryption (only if mailto filtering enabled)
65

    
66
		// only filter output if we are supposed to
67
		if($filter_settings['email_filter'] != '1' && $filter_settings['mailto_filter'] != '1'){
68
			// nothing to do ...
69
			return $content;
70
		}
71

    
72
		// check if non mailto mail addresses needs to be filtered
73
		$output_filter_mode = ($filter_settings['email_filter'] == '1') ? 1 : 0;		// 0|1
74
		
75
		// check if mailto mail addresses needs to be filtered
76
		if($filter_settings['mailto_filter'] == '1') {
77
			$output_filter_mode = $output_filter_mode + 2;														// 0|2
78
						
79
			// check if Javascript mailto encryption is enabled (call register_frontend_functions in the template)
80
			$search = '<script type="text/javascript" src="' .WB_URL .'/modules/output_filter/js/mdcr.js"></script>';
81
			if(strpos($content, $search) !== false) { 
82
				$output_filter_mode = $output_filter_mode + 4;													// 0|4
83
			}
84
		}
85
		
86
		// define some constants so we do not call the database in the callback function again
87
		define('OUTPUT_FILTER_MODE', (int) $output_filter_mode);
88
		define('OUTPUT_FILTER_AT_REPLACEMENT', $filter_settings['at_replacement']);
89
		define('OUTPUT_FILTER_DOT_REPLACEMENT', $filter_settings['dot_replacement']);
90
		
91
		// first search part to find all mailto email addresses
92
		$pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>';
93
		// second part to find all non mailto email addresses
94
		$pattern .= '|\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b#i';
95
		/*
96
		Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)			-->	"<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
97
		Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})			-->	the email address in the mailto: part of the mail link
98
		Sub 3:([^"]*?)"																					--> possible ?Subject&cc... stuff attached to the mail address
99
		Sub 4:([^>]*>)																					--> all class or id statements after the mailto but before closing ..>
100
		Sub 5:(.*?)</a>\b																				--> the mailto text; all characters between >xxxxx</a>
101
		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)
102
		*/
103
			
104
		// find all email addresses embedded in the content and filter them using a callback function
105
		$content = preg_replace_callback($pattern, 'filter_mail_addresses', $content);
106
		return $content;
107
	}
108
}		
109

    
110

    
111
// function to filter mail addresses embedded in text or mailto links before outputing them on the frontend
112
if (!function_exists('filter_mail_addresses')) {
113
	function filter_mail_addresses($match) { 
114
		
115
		// check if required output filter mode is defined
116
		if(!(defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE'))) {
117
			return $match[0];
118
		}
119
		
120
		$search = array('@', '.');
121
		$replace = array(OUTPUT_FILTER_AT_REPLACEMENT ,OUTPUT_FILTER_DOT_REPLACEMENT);
122
		
123
		// check if the match contains the expected number of subpatterns (6|7)
124
		if(count($match) == 7) {
125
			/**
126
				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT
127
			**/
128
			
129
			// 1.. text mails only, 3.. text mails + mailto (no JS), 7 text mails + mailto (JS)
130
			if(!in_array(OUTPUT_FILTER_MODE, array(1,3,7))) return $match[0];
131
			
132
			// filtering of non mailto email addresses enabled
133
			return str_replace($search, $replace, $match[0]);
134
				
135
		} elseif(count($match) == 6) {
136
			/**
137
				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS
138
			**/
139

    
140
			// 2.. mailto only (no JS), 3.. text mails + mailto (no JS), 6.. mailto only (JS), 7.. all filters active
141
			if(!in_array(OUTPUT_FILTER_MODE, array(2,3,6,7))) return $match[0];
142
			
143
			// check if last part of the a href link: >xxxx</a> contains a email address we need to filter
144
			$pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
145
			if(preg_match_all($pattern, $match[5], $matches)) {
146
				foreach($matches as $submatch) {
147
					foreach($submatch as $value) {
148
						// replace all . and all @ in email address parts by (dot) and (at) strings
149
						$match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
150
					}
151
				}
152
			}
153

    
154
			// check if Javascript encryption routine is enabled
155
			if(in_array(OUTPUT_FILTER_MODE, array(6,7))) {
156
				/** USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
157

    
158
				// preprocess mailto link parts for further usage
159
				$search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
160
				$email_address = str_replace($search, $replace, strtolower($match[2]));
161
				$email_subject = rawurlencode(html_entity_decode($match[3]));
162
				
163
				// create a random encryption key for the Caesar cipher
164
				mt_srand((double)microtime()*1000000);	// (PHP < 4.2.0)
165
				$shift = mt_rand(1, 25);
166
				
167
				// encrypt the email using an adapted Caesar cipher
168
		  	$encrypted_email = "";
169
				for($i = strlen($email_address) -1; $i > -1; $i--) {
170
					if(in_array($email_address[$i], array('F', 'Z', 'X', 'K'))) {
171
						$encrypted_email .= $email_address[$i];
172
					} else {
173
						$encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
174
					}
175
				}
176
				$encrypted_email .= chr($shift + 97);
177

    
178
				// build the encrypted Javascript mailto link
179
				$mailto_link  = "<a href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
180
				
181
				return $mailto_link;	
182

    
183
			} else {
184
				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
185

    
186
				// as minimum protection, replace replace @ in the mailto part by (at)
187
				// dots are not transformed as this would transform my.name@domain.com into: my(dot)name(at)domain(dot)com
188
				
189
				// rebuild the mailto link from the subpatterns (at the missing characters " and </a>")
190
				return $match[1] .str_replace('@', OUTPUT_FILTER_AT_REPLACEMENT, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
191
				// if you want to protect both, @ and dots, comment out the line above and remove the comment from the line below
192
				// return $match[1] .str_replace($search, $replace, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
193
			}
194
		
195
		}
196
		
197
		// number of subpatterns do not match the requirements ... do nothing
198
		return $match[0];
199
	}		
200
}
201

    
202
?>
(1-1/6)