Completed
Push — 1.10.x ( 0f48ee...7b08cd )
by Angel Fernando Quiroz
165:10 queued 123:19
created
main/inc/lib/kses-0.2.2/oop/php5.class.kses.php 1 patch
Indentation   +1140 added lines, -1140 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-	/*
3
+    /*
4 4
 	 * ==========================================================================================
5 5
 	 *
6 6
 	 * This program is free software and open source software; you can redistribute
@@ -21,1146 +21,1146 @@  discard block
 block discarded – undo
21 21
 	 * ==========================================================================================
22 22
 	 */
23 23
 
24
-	/**
25
-	*	Class file for PHP5 OOP version of kses
26
-	*
27
-	*	This is an updated version of kses to work with PHP5 that works under E_STRICT.
28
-	*
29
-	*	This version is a bit of a rewrite to match my own coding style and use some of the
30
-	*	capabilities allowed in PHP5.  Since this was a significant rewrite, but it still
31
-	*	maintains backward compatibility syntax-wise, the version number is now 1.0.0.  Any
32
-	*	minor changes that do not break compatibility will be indicated in the second or third
33
-	*	digits.  Anything that breaks compatibility will change the major version number.
34
-	*
35
-	*	PHP5 specific changes:
36
-	*	+ Private methods are now in place
37
-	*	+ __construct() is now used rather then the standard class name 'kses()'
38
-	*	+ Kses will not load in any version less that PHP5
39
-	*	Other modifications:
40
-	*	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
41
-	*	+ Method names have been changed to reflect status as verbs
42
-	*	+ One line methods have been folded into the code
43
-	*	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
44
-	*	+ Kses5 now works in E_STRICT
45
-	*	+ Version number is 1.0.0 to reflect serious code changes
46
-	*	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
47
-	*	+ Deprecated _hook(), Protocols()
48
-	*
49
-	*	@package    kses
50
-	*	@subpackage kses5
51
-	*/
52
-
53
-	if(substr(phpversion(), 0, 1) < 5)
54
-	{
55
-		die("Class kses requires PHP 5 or higher.");
56
-	}
57
-
58
-	/**
59
-	*	Only install KSES5 once
60
-	*/
61
-	if(!defined('KSES_CLASS_PHP5'))
62
-	{
63
-		define('KSES_CLASS_PHP5', true);
64
-
65
-	/**
66
-	*	Kses strips evil scripts!
67
-	*
68
-	*	This class provides the capability for removing unwanted HTML/XHTML, attributes from
69
-	*	tags, and protocols contained in links.  The net result is a much more powerful tool
70
-	*	than the PHP internal strip_tags()
71
-	*
72
-	*	This is a fork of a slick piece of procedural code called 'kses' written by Ulf Harnhammar.
73
-	*
74
-	*	The original class for PHP4 was basically a wrapper around all of the functions in
75
-	*	the procedural code written by Ulf, and was released 7/25/2003.
76
-	*
77
-	*	This version is a bit of a rewrite to match my own coding style and use some of the
78
-	*	capabilities allowed in PHP5.  Since this was a significant rewrite, but it still
79
-	*	maintains backward compatibility syntax-wise, the version number is now 1.0.0.  Any
80
-	*	minor changes that do not break compatibility will be indicated in the second or third
81
-	*	digits.  Anything that breaks compatibility will change the major version number.
82
-	*
83
-	*	PHP5 specific changes:
84
-	*	+ Private methods are now in place
85
-	*	+ __construct() is now used rather then the standard class name 'kses()'
86
-	*	+ Kses5 will not load in any version less that PHP5
87
-	*	Other modifications:
88
-	*	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
89
-	*	+ Method names have been changed to reflect status as verbs
90
-	*	+ One line methods have been folded into the code
91
-	*	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
92
-	*	+ Kses now works in E_STRICT
93
-	*	+ Initial Version number set to 1.0.0 to reflect serious code changes
94
-	*	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
95
-	*	+ Deprecated _hook(), Protocols()
96
-	*	+ Integrated code from kses 0.2.2 into class.
97
-	*	+ Added methods DumpProtocols(), DumpMethods()
98
-	*
99
-	*	@author     Richard R. V�squez, Jr. (Original procedural code by Ulf H�rnhammar)
100
-	*	@link       http://sourceforge.net/projects/kses/ Home Page for Kses
101
-	*	@link       http://chaos.org/contact/ Contact page with current email address for Richard Vasquez
102
-	*	@copyright  Richard R. V�squez, Jr. 2005
103
-	*	@version    PHP5 OOP 1.0.2
104
-	*	@license    http://www.gnu.org/licenses/gpl.html GNU Public License
105
-	*	@package    kses
106
-	*/
107
-		class kses5
108
-		{
109
-			/**#@+
24
+    /**
25
+     *	Class file for PHP5 OOP version of kses
26
+     *
27
+     *	This is an updated version of kses to work with PHP5 that works under E_STRICT.
28
+     *
29
+     *	This version is a bit of a rewrite to match my own coding style and use some of the
30
+     *	capabilities allowed in PHP5.  Since this was a significant rewrite, but it still
31
+     *	maintains backward compatibility syntax-wise, the version number is now 1.0.0.  Any
32
+     *	minor changes that do not break compatibility will be indicated in the second or third
33
+     *	digits.  Anything that breaks compatibility will change the major version number.
34
+     *
35
+     *	PHP5 specific changes:
36
+     *	+ Private methods are now in place
37
+     *	+ __construct() is now used rather then the standard class name 'kses()'
38
+     *	+ Kses will not load in any version less that PHP5
39
+     *	Other modifications:
40
+     *	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
41
+     *	+ Method names have been changed to reflect status as verbs
42
+     *	+ One line methods have been folded into the code
43
+     *	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
44
+     *	+ Kses5 now works in E_STRICT
45
+     *	+ Version number is 1.0.0 to reflect serious code changes
46
+     *	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
47
+     *	+ Deprecated _hook(), Protocols()
48
+     *
49
+     *	@package    kses
50
+     *	@subpackage kses5
51
+     */
52
+
53
+    if(substr(phpversion(), 0, 1) < 5)
54
+    {
55
+        die("Class kses requires PHP 5 or higher.");
56
+    }
57
+
58
+    /**
59
+     *	Only install KSES5 once
60
+     */
61
+    if(!defined('KSES_CLASS_PHP5'))
62
+    {
63
+        define('KSES_CLASS_PHP5', true);
64
+
65
+    /**
66
+     *	Kses strips evil scripts!
67
+     *
68
+     *	This class provides the capability for removing unwanted HTML/XHTML, attributes from
69
+     *	tags, and protocols contained in links.  The net result is a much more powerful tool
70
+     *	than the PHP internal strip_tags()
71
+     *
72
+     *	This is a fork of a slick piece of procedural code called 'kses' written by Ulf Harnhammar.
73
+     *
74
+     *	The original class for PHP4 was basically a wrapper around all of the functions in
75
+     *	the procedural code written by Ulf, and was released 7/25/2003.
76
+     *
77
+     *	This version is a bit of a rewrite to match my own coding style and use some of the
78
+     *	capabilities allowed in PHP5.  Since this was a significant rewrite, but it still
79
+     *	maintains backward compatibility syntax-wise, the version number is now 1.0.0.  Any
80
+     *	minor changes that do not break compatibility will be indicated in the second or third
81
+     *	digits.  Anything that breaks compatibility will change the major version number.
82
+     *
83
+     *	PHP5 specific changes:
84
+     *	+ Private methods are now in place
85
+     *	+ __construct() is now used rather then the standard class name 'kses()'
86
+     *	+ Kses5 will not load in any version less that PHP5
87
+     *	Other modifications:
88
+     *	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
89
+     *	+ Method names have been changed to reflect status as verbs
90
+     *	+ One line methods have been folded into the code
91
+     *	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
92
+     *	+ Kses now works in E_STRICT
93
+     *	+ Initial Version number set to 1.0.0 to reflect serious code changes
94
+     *	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
95
+     *	+ Deprecated _hook(), Protocols()
96
+     *	+ Integrated code from kses 0.2.2 into class.
97
+     *	+ Added methods DumpProtocols(), DumpMethods()
98
+     *
99
+     *	@author     Richard R. V�squez, Jr. (Original procedural code by Ulf H�rnhammar)
100
+     *	@link       http://sourceforge.net/projects/kses/ Home Page for Kses
101
+     *	@link       http://chaos.org/contact/ Contact page with current email address for Richard Vasquez
102
+     *	@copyright  Richard R. V�squez, Jr. 2005
103
+     *	@version    PHP5 OOP 1.0.2
104
+     *	@license    http://www.gnu.org/licenses/gpl.html GNU Public License
105
+     *	@package    kses
106
+     */
107
+        class kses5
108
+        {
109
+            /**#@+
110 110
 			 *	@access private
111 111
 			 *	@var array
112 112
 			 */
113
-			private $allowed_protocols;
114
-			private $allowed_html;
115
-			/**#@-*/
116
-
117
-			/**
118
-			 *	Constructor for kses.
119
-			 *
120
-			 *	This sets a default collection of protocols allowed in links, and creates an
121
-			 *	empty set of allowed HTML tags.
122
-			 *	@since PHP5 OOP 1.0.0
123
-			 */
124
-			public function __construct()
125
-			{
126
-				/**
127
-				 *	You could add protocols such as ftp, new, gopher, mailto, irc, etc.
128
-				 *
129
-				 *	The base values the original kses provided were:
130
-				 *		'http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto'
131
-				 */
132
-				$this->allowed_protocols = array('http', 'ftp', 'mailto');
133
-				$this->allowed_html      = array();
134
-			}
135
-
136
-			/**
137
-			 *	Basic task of kses - parses $string and strips it as required.
138
-			 *
139
-			 *	This method strips all the disallowed (X)HTML tags, attributes
140
-			 *	and protocols from the input $string.
141
-			 *
142
-			 *	@access public
143
-			 *	@param string $string String to be stripped of 'evil scripts'
144
-			 *	@return string The stripped string
145
-			 *	@since PHP4 OOP 0.0.1
146
-			 */
147
-			public function Parse($string = "")
148
-			{
149
-				if (get_magic_quotes_gpc())
150
-				{
151
-					$string = stripslashes($string);
152
-				}
153
-				$string = $this->removeNulls($string);
154
-				//	Remove JavaScript entities from early Netscape 4 versions
155
-				$string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
156
-				$string = $this->normalizeEntities($string);
157
-				$string = $this->filterKsesTextHook($string);
158
-				$string = preg_replace('%(<' . '[^>]*' . '(>|$)' . '|>)%e', "\$this->stripTags('\\1')", $string);
159
-				return $string;
160
-			}
161
-
162
-			/**
163
-			 *	Allows for single/batch addition of protocols
164
-			 *
165
-			 *	This method accepts one argument that can be either a string
166
-			 *	or an array of strings.  Invalid data will be ignored.
167
-			 *
168
-			 *	The argument will be processed, and each string will be added
169
-			 *	via AddProtocol().
170
-			 *
171
-			 *	@access public
172
-			 *	@param mixed , A string or array of protocols that will be added to the internal list of allowed protocols.
173
-			 *	@return bool Status of adding valid protocols.
174
-			 *	@see AddProtocol()
175
-			 *	@since PHP5 OOP 1.0.0
176
-			 */
177
-			public function AddProtocols()
178
-			{
179
-				$c_args = func_num_args();
180
-				if($c_args != 1)
181
-				{
182
-					trigger_error("kses5::AddProtocols() did not receive an argument.", E_USER_WARNING);
183
-					return false;
184
-				}
185
-
186
-				$protocol_data = func_get_arg(0);
187
-
188
-				if(is_array($protocol_data) && count($protocol_data) > 0)
189
-				{
190
-					foreach($protocol_data as $protocol)
191
-					{
192
-						$this->AddProtocol($protocol);
193
-					}
194
-					return true;
195
-				}
196
-				elseif(is_string($protocol_data))
197
-				{
198
-					$this->AddProtocol($protocol_data);
199
-					return true;
200
-				}
201
-				else
202
-				{
203
-					trigger_error("kses5::AddProtocols() did not receive a string or an array.", E_USER_WARNING);
204
-					return false;
205
-				}
206
-			}
207
-
208
-			/**
209
-			 *	Allows for single/batch addition of protocols
210
-			 *
211
-			 *	@deprecated Use AddProtocols()
212
-			 *	@see AddProtocols()
213
-			 *	@return bool
214
-			 *	@since PHP4 OOP 0.0.1
215
-			 */
216
-			public function Protocols()
217
-			{
218
-				$c_args = func_num_args();
219
-				if($c_args != 1)
220
-				{
221
-					trigger_error("kses5::Protocols() did not receive an argument.", E_USER_WARNING);
222
-					return false;
223
-				}
224
-
225
-				return $this->AddProtocols(func_get_arg(0));
226
-			}
227
-
228
-			/**
229
-			 *	Adds a single protocol to $this->allowed_protocols.
230
-			 *
231
-			 *	This method accepts a string argument and adds it to
232
-			 *	the list of allowed protocols to keep when performing
233
-			 *	Parse().
234
-			 *
235
-			 *	@access public
236
-			 *	@param string $protocol The name of the protocol to be added.
237
-			 *	@return bool Status of adding valid protocol.
238
-			 *	@since PHP4 OOP 0.0.1
239
-			 */
240
-			public function AddProtocol($protocol = "")
241
-			{
242
-				if(!is_string($protocol))
243
-				{
244
-					trigger_error("kses5::AddProtocol() requires a string.", E_USER_WARNING);
245
-					return false;
246
-				}
247
-
248
-				// Remove any inadvertent ':' at the end of the protocol.
249
-				if(substr($protocol, strlen($protocol) - 1, 1) == ":")
250
-				{
251
-					$protocol = substr($protocol, 0, strlen($protocol) - 1);
252
-				}
253
-
254
-				$protocol = strtolower(trim($protocol));
255
-				if($protocol == "")
256
-				{
257
-					trigger_error("kses5::AddProtocol() tried to add an empty/NULL protocol.", E_USER_WARNING);
258
-					return false;
259
-				}
260
-
261
-				//	prevent duplicate protocols from being added.
262
-				if(!in_array($protocol, $this->allowed_protocols))
263
-				{
264
-					array_push($this->allowed_protocols, $protocol);
265
-					sort($this->allowed_protocols);
266
-				}
267
-				return true;
268
-			}
269
-
270
-			/**
271
-			 *	Removes a single protocol from $this->allowed_protocols.
272
-			 *
273
-			 *	This method accepts a string argument and removes it from
274
-			 *	the list of allowed protocols to keep when performing
275
-			 *	Parse().
276
-			 *
277
-			 *	@access public
278
-			 *	@param string $protocol The name of the protocol to be removed.
279
-			 *	@return bool Status of removing valid protocol.
280
-			 *	@since PHP5 OOP 1.0.0
281
-			 */
282
-			public function RemoveProtocol($protocol = "")
283
-			{
284
-				if(!is_string($protocol))
285
-				{
286
-					trigger_error("kses5::RemoveProtocol() requires a string.", E_USER_WARNING);
287
-					return false;
288
-				}
289
-
290
-				// Remove any inadvertent ':' at the end of the protocol.
291
-				if(substr($protocol, strlen($protocol) - 1, 1) == ":")
292
-				{
293
-					$protocol = substr($protocol, 0, strlen($protocol) - 1);
294
-				}
295
-
296
-				$protocol = strtolower(trim($protocol));
297
-				if($protocol == "")
298
-				{
299
-					trigger_error("kses5::RemoveProtocol() tried to remove an empty/NULL protocol.", E_USER_WARNING);
300
-					return false;
301
-				}
302
-
303
-				//	Ensures that the protocol exists before removing it.
304
-				if(in_array($protocol, $this->allowed_protocols))
305
-				{
306
-					$this->allowed_protocols = array_diff($this->allowed_protocols, array($protocol));
307
-					sort($this->allowed_protocols);
308
-				}
309
-
310
-				return true;
311
-			}
312
-
313
-			/**
314
-			 *	Allows for single/batch removal of protocols
315
-			 *
316
-			 *	This method accepts one argument that can be either a string
317
-			 *	or an array of strings.  Invalid data will be ignored.
318
-			 *
319
-			 *	The argument will be processed, and each string will be removed
320
-			 *	via RemoveProtocol().
321
-			 *
322
-			 *	@access public
323
-			 *	@param mixed , A string or array of protocols that will be removed from the internal list of allowed protocols.
324
-			 *	@return bool Status of removing valid protocols.
325
-			 *	@see RemoveProtocol()
326
-			 *	@since PHP5 OOP 1.0.0
327
-			 */
328
-			public function RemoveProtocols()
329
-			{
330
-				$c_args = func_num_args();
331
-				if($c_args != 1)
332
-				{
333
-					return false;
334
-				}
335
-
336
-				$protocol_data = func_get_arg(0);
337
-
338
-				if(is_array($protocol_data) && count($protocol_data) > 0)
339
-				{
340
-					foreach($protocol_data as $protocol)
341
-					{
342
-						$this->RemoveProtocol($protocol);
343
-					}
344
-				}
345
-				elseif(is_string($protocol_data))
346
-				{
347
-					$this->RemoveProtocol($protocol_data);
348
-					return true;
349
-				}
350
-				else
351
-				{
352
-					trigger_error("kses5::RemoveProtocols() did not receive a string or an array.", E_USER_WARNING);
353
-					return false;
354
-				}
355
-			}
356
-
357
-			/**
358
-			 *	Allows for single/batch replacement of protocols
359
-			 *
360
-			 *	This method accepts one argument that can be either a string
361
-			 *	or an array of strings.  Invalid data will be ignored.
362
-			 *
363
-			 *	Existing protocols will be removed, then the argument will be
364
-			 *	processed, and each string will be added via AddProtocol().
365
-			 *
366
-			 *	@access public
367
-			 *	@param mixed , A string or array of protocols that will be the new internal list of allowed protocols.
368
-			 *	@return bool Status of replacing valid protocols.
369
-			 *	@since PHP5 OOP 1.0.1
370
-			 *	@see AddProtocol()
371
-			 */
372
-			public function SetProtocols()
373
-			{
374
-				$c_args = func_num_args();
375
-				if($c_args != 1)
376
-				{
377
-					trigger_error("kses5::SetProtocols() did not receive an argument.", E_USER_WARNING);
378
-					return false;
379
-				}
380
-
381
-				$protocol_data = func_get_arg(0);
382
-
383
-				if(is_array($protocol_data) && count($protocol_data) > 0)
384
-				{
385
-					$this->allowed_protocols = array();
386
-					foreach($protocol_data as $protocol)
387
-					{
388
-						$this->AddProtocol($protocol);
389
-					}
390
-					return true;
391
-				}
392
-				elseif(is_string($protocol_data))
393
-				{
394
-					$this->allowed_protocols = array();
395
-					$this->AddProtocol($protocol_data);
396
-					return true;
397
-				}
398
-				else
399
-				{
400
-					trigger_error("kses5::SetProtocols() did not receive a string or an array.", E_USER_WARNING);
401
-					return false;
402
-				}
403
-			}
404
-
405
-			/**
406
-			 *	Raw dump of allowed protocols
407
-			 *
408
-			 *	This returns an indexed array of allowed protocols for a particular KSES
409
-			 *	instantiation.
410
-			 *
411
-			 *	@access public
412
-			 *	@return array The list of allowed protocols.
413
-			 *	@since PHP5 OOP 1.0.2
414
-			 */
415
-			public function DumpProtocols()
416
-			{
417
-				return $this->allowed_protocols;
418
-			}
419
-
420
-			/**
421
-			 *	Raw dump of allowed (X)HTML elements
422
-			 *
423
-			 *	This returns an indexed array of allowed (X)HTML elements and attributes
424
-			 *	for a particular KSES instantiation.
425
-			 *
426
-			 *	@access public
427
-			 *	@return array The list of allowed elements.
428
-			 *	@since PHP5 OOP 1.0.2
429
-			 */
430
-			public function DumpElements()
431
-			{
432
-				return $this->allowed_html;
433
-			}
434
-
435
-
436
-			/**
437
-			 *	Adds valid (X)HTML with corresponding attributes that will be kept when stripping 'evil scripts'.
438
-			 *
439
-			 *	This method accepts one argument that can be either a string
440
-			 *	or an array of strings.  Invalid data will be ignored.
441
-			 *
442
-			 *	@access public
443
-			 *	@param string $tag (X)HTML tag that will be allowed after stripping text.
444
-			 *	@param array $attribs Associative array of allowed attributes - key => attribute name - value => attribute parameter
445
-			 *	@return bool Status of Adding (X)HTML and attributes.
446
-			 *	@since PHP4 OOP 0.0.1
447
-			 */
448
-			public function AddHTML($tag = "", $attribs = array())
449
-			{
450
-				if(!is_string($tag))
451
-				{
452
-					trigger_error("kses5::AddHTML() requires the tag to be a string", E_USER_WARNING);
453
-					return false;
454
-				}
455
-
456
-				$tag = strtolower(trim($tag));
457
-				if($tag == "")
458
-				{
459
-					trigger_error("kses5::AddHTML() tried to add an empty/NULL tag", E_USER_WARNING);
460
-					return false;
461
-				}
462
-
463
-				if(!is_array($attribs))
464
-				{
465
-					trigger_error("kses5::AddHTML() requires an array (even an empty one) of attributes for '$tag'", E_USER_WARNING);
466
-					return false;
467
-				}
468
-
469
-				$new_attribs = array();
470
-				if(is_array($attribs) && count($attribs) > 0)
471
-				{
472
-					foreach($attribs as $idx1 => $val1)
473
-					{
474
-						$new_idx1 = strtolower($idx1);
475
-						$new_val1 = $attribs[$idx1];
476
-
477
-						if(is_array($new_val1) && count($attribs) > 0)
478
-						{
479
-							$tmp_val = array();
480
-							foreach($new_val1 as $idx2 => $val2)
481
-							{
482
-								$new_idx2 = strtolower($idx2);
483
-								$tmp_val[$new_idx2] = $val2;
484
-							}
485
-							$new_val1 = $tmp_val;
486
-						}
487
-
488
-						$new_attribs[$new_idx1] = $new_val1;
489
-					}
490
-				}
491
-
492
-				$this->allowed_html[$tag] = $new_attribs;
493
-				return true;
494
-			}
495
-
496
-			/**
497
-			 *	This method removes any NULL characters in $string.
498
-			 *
499
-			 *	@access private
500
-			 *	@param string $string
501
-			 *	@return string String without any NULL/chr(173)
502
-			 *	@since PHP4 OOP 0.0.1
503
-			 */
504
-			private function removeNulls($string)
505
-			{
506
-				$string = preg_replace('/\0+/', '', $string);
507
-				$string = preg_replace('/(\\\\0)+/', '', $string);
508
-				return $string;
509
-			}
510
-
511
-			/**
512
-			 *	Normalizes HTML entities
513
-			 *
514
-			 *	This function normalizes HTML entities. It will convert "AT&T" to the correct
515
-			 *	"AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
516
-			 *
517
-			 *	@access private
518
-			 *	@param string $string
519
-			 *	@return string String with normalized entities
520
-			 *	@since PHP4 OOP 0.0.1
521
-			 */
522
-			private function normalizeEntities($string)
523
-			{
524
-				# Disarm all entities by converting & to &amp;
525
-				$string = str_replace('&', '&amp;', $string);
526
-
527
-				#	TODO: Change back (Keep?) the allowed entities in our entity white list
528
-
529
-				#	Keeps entities that start with [A-Za-z]
530
-				$string = preg_replace(
531
-					'/&amp;([A-Za-z][A-Za-z0-9]{0,19});/',
532
-					'&\\1;',
533
-					$string
534
-				);
535
-
536
-				#	Change numeric entities to valid 16 bit values
537
-
538
-				$string = preg_replace(
539
-					'/&amp;#0*([0-9]{1,5});/e',
540
-					'\$this->normalizeEntities16bit("\\1")',
541
-					$string
542
-				);
543
-
544
-				#	Change &XHHHHHHH (Hex digits) to 16 bit hex values
545
-				$string = preg_replace(
546
-					'/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/',
547
-					'&#\\1\\2;',
548
-					$string
549
-				);
550
-
551
-				return $string;
552
-			}
553
-
554
-			/**
555
-			 *	Helper method used by normalizeEntites()
556
-			 *
557
-			 *	This method helps normalizeEntities() to only accept 16 bit values
558
-			 *	and nothing more for &#number; entities.
559
-			 *
560
-			 *	This method helps normalize_entities() during a preg_replace()
561
-			 *	where a &#(0)*XXXXX; occurs.  The '(0)*XXXXXX' value is converted to
562
-			 *	a number and the result is returned as a numeric entity if the number
563
-			 *	is less than 65536.  Otherwise, the value is returned 'as is'.
564
-			 *
565
-			 *	@access private
566
-			 *	@param string $i
567
-			 *	@return string Normalized numeric entity
568
-			 *	@see normalizeEntities()
569
-			 *	@since PHP4 OOP 0.0.1
570
-			 */
571
-			private function normalizeEntities16bit($i)
572
-			{
573
-			  return (($i > 65535) ? "&amp;#$i;" : "&#$i;");
574
-			}
575
-
576
-			/**
577
-			 *	Allows for additional user defined modifications to text.
578
-			 *
579
-			 *	This method allows for additional modifications to be performed on
580
-			 *	a string that's being run through Parse().  Currently, it returns the
581
-			 *	input string 'as is'.
582
-			 *
583
-			 *	This method is provided for users to extend the kses class for their own
584
-			 *	requirements.
585
-			 *
586
-			 *	@access public
587
-			 *	@param string $string String to perfrom additional modifications on.
588
-			 *	@return string User modified string.
589
-			 *	@see Parse()
590
-			 *	@since PHP5 OOP 1.0.0
591
-			 */
592
-			private function filterKsesTextHook($string)
593
-			{
594
-			  return $string;
595
-			}
596
-
597
-			/**
598
-			 *	Allows for additional user defined modifications to text.
599
-			 *
600
-			 *	@deprecated use filterKsesTextHook()
601
-			 *	@param string $string
602
-			 *	@return string
603
-			 *	@see filterKsesTextHook()
604
-			 *	@since PHP4 OOP 0.0.1
605
-			 */
606
-			private function _hook($string)
607
-			{
608
-				return $this->filterKsesTextHook($string);
609
-			}
610
-
611
-			/**
612
-			 *	This method goes through an array, and changes the keys to all lower case.
613
-			 *
614
-			 *	@access private
615
-			 *	@param array $in_array Associative array
616
-			 *	@return array Modified array
617
-			 *	@since PHP4 OOP 0.0.1
618
-			 */
619
-			private function makeArrayKeysLowerCase($in_array)
620
-			{
621
-				$out_array = array();
622
-
623
-				if(is_array($in_array) && count($in_array) > 0)
624
-				{
625
-					foreach ($in_array as $in_key => $in_val)
626
-					{
627
-						$out_key = strtolower($in_key);
628
-						$out_array[$out_key] = array();
629
-
630
-						if(is_array($in_val) && count($in_val) > 0)
631
-						{
632
-							foreach ($in_val as $in_key2 => $in_val2)
633
-							{
634
-								$out_key2 = strtolower($in_key2);
635
-								$out_array[$out_key][$out_key2] = $in_val2;
636
-							}
637
-						}
638
-					}
639
-				}
640
-
641
-				return $out_array;
642
-			}
643
-
644
-			/**
645
-			 *	This method strips out disallowed and/or mangled (X)HTML tags along with assigned attributes.
646
-			 *
647
-			 *	This method does a lot of work. It rejects some very malformed things
648
-			 *	like <:::>. It returns an empty string if the element isn't allowed (look
649
-			 *	ma, no strip_tags()!). Otherwise it splits the tag into an element and an
650
-			 *	allowed attribute list.
651
-			 *
652
-			 *	@access private
653
-			 *	@param string $string
654
-			 *	@return string Modified string minus disallowed/mangled (X)HTML and attributes
655
-			 *	@since PHP4 OOP 0.0.1
656
-			 */
657
-			private function stripTags($string)
658
-			{
659
-				$string = preg_replace('%\\\\"%', '"', $string);
660
-
661
-				if (substr($string, 0, 1) != '<')
662
-				{
663
-					# It matched a ">" character
664
-					return '&gt;';
665
-				}
666
-
667
-				if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
668
-				{
669
-					# It's seriously malformed
670
-					return '';
671
-				}
672
-
673
-				$slash    = trim($matches[1]);
674
-				$elem     = $matches[2];
675
-				$attrlist = $matches[3];
676
-
677
-				if (
678
-					!isset($this->allowed_html[strtolower($elem)]) ||
679
-					!is_array($this->allowed_html[strtolower($elem)]))
680
-				{
681
-					#	Found an HTML element not in the white list
682
-					return '';
683
-				}
684
-
685
-				if ($slash != '')
686
-				{
687
-					return "<$slash$elem>";
688
-				}
689
-				# No attributes are allowed for closing elements
690
-
691
-				return $this->stripAttributes("$slash$elem", $attrlist);
692
-			}
693
-
694
-			/**
695
-			 *	This method strips out disallowed attributes for (X)HTML tags.
696
-			 *
697
-			 *	This method removes all attributes if none are allowed for this element.
698
-			 *	If some are allowed it calls combAttributes() to split them further, and then it
699
-			 *	builds up new HTML code from the data that combAttributes() returns. It also
700
-			 *	removes "<" and ">" characters, if there are any left. One more thing it
701
-			 *	does is to check if the tag has a closing XHTML slash, and if it does,
702
-			 *	it puts one in the returned code as well.
703
-			 *
704
-			 *	@access private
705
-			 *	@param string $element (X)HTML tag to check
706
-			 *	@param string $attr Text containing attributes to check for validity.
707
-			 *	@return string Resulting valid (X)HTML or ''
708
-			 *	@see combAttributes()
709
-			 *	@since PHP4 OOP 0.0.1
710
-			 */
711
-			private function stripAttributes($element, $attr)
712
-			{
713
-				# Is there a closing XHTML slash at the end of the attributes?
714
-				$xhtml_slash = '';
715
-				if (preg_match('%\s/\s*$%', $attr))
716
-				{
717
-					$xhtml_slash = ' /';
718
-				}
719
-
720
-				# Are any attributes allowed at all for this element?
721
-				if (
722
-					!isset($this->allowed_html[strtolower($element)]) ||
723
-					count($this->allowed_html[strtolower($element)]) == 0
724
-				)
725
-				{
726
-					return "<$element$xhtml_slash>";
727
-				}
728
-
729
-				# Split it
730
-				$attrarr = $this->combAttributes($attr);
731
-
732
-				# Go through $attrarr, and save the allowed attributes for this element
733
-				# in $attr2
734
-				$attr2 = '';
735
-				if(is_array($attrarr) && count($attrarr) > 0)
736
-				{
737
-					foreach ($attrarr as $arreach)
738
-					{
739
-						if(!isset($this->allowed_html[strtolower($element)][strtolower($arreach['name'])]))
740
-						{
741
-							continue;
742
-						}
743
-
744
-						$current = $this->allowed_html[strtolower($element)][strtolower($arreach['name'])];
745
-
746
-						if (!is_array($current))
747
-						{
748
-							# there are no checks
749
-							$attr2 .= ' '.$arreach['whole'];
750
-						}
751
-						else
752
-						{
753
-							# there are some checks
754
-							$ok = true;
755
-							if(is_array($current) && count($current) > 0)
756
-							{
757
-								foreach ($current as $currkey => $currval)
758
-								{
759
-									if (!$this->checkAttributeValue($arreach['value'], $arreach['vless'], $currkey, $currval))
760
-									{
761
-										$ok = false;
762
-										break;
763
-									}
764
-								}
765
-							}
766
-
767
-							if ($ok)
768
-							{
769
-								# it passed them
770
-								$attr2 .= ' '.$arreach['whole'];
771
-							}
772
-						}
773
-					}
774
-				}
775
-
776
-				# Remove any "<" or ">" characters
777
-				$attr2 = preg_replace('/[<>]/', '', $attr2);
778
-				return "<$element$attr2$xhtml_slash>";
779
-			}
780
-
781
-			/**
782
-			 *	This method combs through an attribute list string and returns an associative array of attributes and values.
783
-			 *
784
-			 *	This method does a lot of work. It parses an attribute list into an array
785
-			 *	with attribute data, and tries to do the right thing even if it gets weird
786
-			 *	input. It will add quotes around attribute values that don't have any quotes
787
-			 *	or apostrophes around them, to make it easier to produce HTML code that will
788
-			 *	conform to W3C's HTML specification. It will also remove bad URL protocols
789
-			 *	from attribute values.
790
-			 *
791
-			 *	@access private
792
-			 *	@param string $attr Text containing tag attributes for parsing
793
-			 *	@return array Associative array containing data on attribute and value
794
-			 *	@since PHP4 OOP 0.0.1
795
-			 */
796
-			private function combAttributes($attr)
797
-			{
798
-				$attrarr  = array();
799
-				$mode     = 0;
800
-				$attrname = '';
801
-
802
-				# Loop through the whole attribute list
803
-
804
-				while (strlen($attr) != 0)
805
-				{
806
-					# Was the last operation successful?
807
-					$working = 0;
808
-
809
-					switch ($mode)
810
-					{
811
-						case 0:	# attribute name, href for instance
812
-							if (preg_match('/^([-a-zA-Z]+)/', $attr, $match))
813
-							{
814
-								$attrname = $match[1];
815
-								$working = $mode = 1;
816
-								$attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
817
-							}
818
-							break;
819
-						case 1:	# equals sign or valueless ("selected")
820
-							if (preg_match('/^\s*=\s*/', $attr)) # equals sign
821
-							{
822
-								$working = 1;
823
-								$mode    = 2;
824
-								$attr    = preg_replace('/^\s*=\s*/', '', $attr);
825
-								break;
826
-							}
827
-							if (preg_match('/^\s+/', $attr)) # valueless
828
-							{
829
-								$working   = 1;
830
-								$mode      = 0;
831
-								$attrarr[] = array(
832
-									'name'  => $attrname,
833
-									'value' => '',
834
-									'whole' => $attrname,
835
-									'vless' => 'y'
836
-								);
837
-								$attr      = preg_replace('/^\s+/', '', $attr);
838
-							}
839
-							break;
840
-						case 2: # attribute value, a URL after href= for instance
841
-							if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value"
842
-							{
843
-								$thisval   = $this->removeBadProtocols($match[1]);
844
-								$attrarr[] = array(
845
-									'name'  => $attrname,
846
-									'value' => $thisval,
847
-									'whole' => $attrname . '="' . $thisval . '"',
848
-									'vless' => 'n'
849
-								);
850
-								$working   = 1;
851
-								$mode      = 0;
852
-								$attr      = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
853
-								break;
854
-							}
855
-							if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value'
856
-							{
857
-								$thisval   = $this->removeBadProtocols($match[1]);
858
-								$attrarr[] = array(
859
-									'name'  => $attrname,
860
-									'value' => $thisval,
861
-									'whole' => "$attrname='$thisval'",
862
-									'vless' => 'n'
863
-								);
864
-								$working   = 1;
865
-								$mode      = 0;
866
-								$attr      = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
867
-								break;
868
-							}
869
-							if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value
870
-							{
871
-								$thisval   = $this->removeBadProtocols($match[1]);
872
-								$attrarr[] = array(
873
-									'name'  => $attrname,
874
-									'value' => $thisval,
875
-									'whole' => $attrname . '="' . $thisval . '"',
876
-									'vless' => 'n'
877
-								);
878
-								# We add quotes to conform to W3C's HTML spec.
879
-								$working   = 1;
880
-								$mode      = 0;
881
-								$attr      = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
882
-							}
883
-							break;
884
-					}
885
-
886
-					if ($working == 0) # not well formed, remove and try again
887
-					{
888
-						$attr = preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $attr);
889
-						$mode = 0;
890
-					}
891
-				}
892
-
893
-				# special case, for when the attribute list ends with a valueless
894
-				# attribute like "selected"
895
-				if ($mode == 1)
896
-				{
897
-					$attrarr[] = array(
898
-						'name'  => $attrname,
899
-						'value' => '',
900
-						'whole' => $attrname,
901
-						'vless' => 'y'
902
-					);
903
-				}
904
-
905
-				return $attrarr;
906
-			}
907
-
908
-			/**
909
-			 *	This method removes disallowed protocols.
910
-			 *
911
-			 *	This method removes all non-allowed protocols from the beginning of
912
-			 *	$string. It ignores whitespace and the case of the letters, and it does
913
-			 *	understand HTML entities. It does its work in a while loop, so it won't be
914
-			 *	fooled by a string like "javascript:javascript:alert(57)".
915
-			 *
916
-			 *	@access private
917
-			 *	@param string $string String to check for protocols
918
-			 *	@return string String with removed protocols
919
-			 *	@since PHP4 OOP 0.0.1
920
-			 */
921
-			private function removeBadProtocols($string)
922
-			{
923
-				$string  = $this->RemoveNulls($string);
924
-				$string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
925
-				$string2 = $string . 'a';
926
-
927
-				$string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
928
-				if(isset($string2[1]) && !preg_match('%/\?%',$string2[0]))
929
-				{
930
-					$string = $this->filterProtocols($string2[0]).trim($string2[1]);
931
-				}
932
-				return $string;
933
-			}
934
-
935
-			/**
936
-			 *	Helper method used by removeBadProtocols()
937
-			 *
938
-			 *	This function processes URL protocols, checks to see if they're in the white-
939
-			 *	list or not, and returns different data depending on the answer.
940
-			 *
941
-			 *	@access private
942
-			 *	@param string $string String to check for protocols
943
-			 *	@return string String with removed protocols
944
-			 *	@see removeBadProtocols()
945
-			 *	@since PHP4 OOP 0.0.1
946
-			 */
947
-			private function filterProtocols($string)
948
-			{
949
-				$string = $this->decodeEntities($string);
950
-				$string = preg_replace('/\s/', '', $string);
951
-				$string = $this->removeNulls($string);
952
-				$string = preg_replace('/\xad+/', '', $string2); # deals with Opera "feature"
953
-				$string = strtolower($string);
954
-
955
-				if(is_array($this->allowed_protocols) && count($this->allowed_protocols) > 0)
956
-				{
957
-					foreach ($this->allowed_protocols as $one_protocol)
958
-					{
959
-						if (strtolower($one_protocol) == $string)
960
-						{
961
-							return "$string:";
962
-						}
963
-					}
964
-				}
965
-
966
-				return '';
967
-			}
968
-
969
-			/**
970
-			 *	Controller method for performing checks on attribute values.
971
-			 *
972
-			 *	This method calls the appropriate method as specified by $checkname with
973
-			 *	the parameters $value, $vless, and $checkvalue, and returns the result
974
-			 *	of the call.
975
-			 *
976
-			 *	This method's functionality can be expanded by creating new methods
977
-			 *	that would match checkAttributeValue[$checkname].
978
-			 *
979
-			 *	Current checks implemented are: "maxlen", "minlen", "maxval", "minval" and "valueless"
980
-			 *
981
-			 *	@access private
982
-			 *	@param string $value The value of the attribute to be checked.
983
-			 *	@param string $vless Indicates whether the the value is supposed to be valueless
984
-			 *	@param string $checkname The check to be performed
985
-			 *	@param string $checkvalue The value that is to be checked against
986
-			 *	@return bool Indicates whether the check passed or not
987
-			 *	@since PHP5 OOP 1.0.0
988
-			 */
989
-			private function checkAttributeValue($value, $vless, $checkname, $checkvalue)
990
-			{
991
-				$ok = true;
992
-				$check_attribute_method_name  = 'checkAttributeValue' . ucfirst(strtolower($checkname));
993
-				if(method_exists($this, $check_attribute_method_name))
994
-				{
995
-					$ok = $this->$check_attribute_method_name($value, $checkvalue, $vless);
996
-				}
997
-
998
-				return $ok;
999
-			}
1000
-
1001
-			/**
1002
-			 *	Helper method invoked by checkAttributeValue().
1003
-			 *
1004
-			 *	The maxlen check makes sure that the attribute value has a length not
1005
-			 *	greater than the given value. This can be used to avoid Buffer Overflows
1006
-			 *	in WWW clients and various Internet servers.
1007
-			 *
1008
-			 *	@access private
1009
-			 *	@param string $value The value of the attribute to be checked.
1010
-			 *	@param int $checkvalue The maximum value allowed
1011
-			 *	@return bool Indicates whether the check passed or not
1012
-			 *	@see checkAttributeValue()
1013
-			 *	@since PHP5 OOP 1.0.0
1014
-			 */
1015
-			private function checkAttributeValueMaxlen($value, $checkvalue)
1016
-			{
1017
-				if (strlen($value) > intval($checkvalue))
1018
-				{
1019
-					return false;
1020
-				}
1021
-				return true;
1022
-			}
1023
-
1024
-			/**
1025
-			 *	Helper method invoked by checkAttributeValue().
1026
-			 *
1027
-			 *	The minlen check makes sure that the attribute value has a length not
1028
-			 *	smaller than the given value.
1029
-			 *
1030
-			 *	@access private
1031
-			 *	@param string $value The value of the attribute to be checked.
1032
-			 *	@param int $checkvalue The minimum value allowed
1033
-			 *	@return bool Indicates whether the check passed or not
1034
-			 *	@see checkAttributeValue()
1035
-			 *	@since PHP5 OOP 1.0.0
1036
-			 */
1037
-			private function checkAttributeValueMinlen($value, $checkvalue)
1038
-			{
1039
-				if (strlen($value) < intval($checkvalue))
1040
-				{
1041
-					return false;
1042
-				}
1043
-				return true;
1044
-			}
1045
-
1046
-			/**
1047
-			 *	Helper method invoked by checkAttributeValue().
1048
-			 *
1049
-			 *	The maxval check does two things: it checks that the attribute value is
1050
-			 *	an integer from 0 and up, without an excessive amount of zeroes or
1051
-			 *	whitespace (to avoid Buffer Overflows). It also checks that the attribute
1052
-			 *	value is not greater than the given value.
1053
-			 *
1054
-			 *	This check can be used to avoid Denial of Service attacks.
1055
-			 *
1056
-			 *	@access private
1057
-			 *	@param int $value The value of the attribute to be checked.
1058
-			 *	@param int $checkvalue The maximum numeric value allowed
1059
-			 *	@return bool Indicates whether the check passed or not
1060
-			 *	@see checkAttributeValue()
1061
-			 *	@since PHP5 OOP 1.0.0
1062
-			 */
1063
-			private function checkAttributeValueMaxval($value, $checkvalue)
1064
-			{
1065
-				if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1066
-				{
1067
-					return false;
1068
-				}
1069
-				if (intval($value) > intval($checkvalue))
1070
-				{
1071
-					return false;
1072
-				}
1073
-				return true;
1074
-			}
1075
-
1076
-			/**
1077
-			 *	Helper method invoked by checkAttributeValue().
1078
-			 *
1079
-			 *	The minval check checks that the attribute value is a positive integer,
1080
-			 *	and that it is not smaller than the given value.
1081
-			 *
1082
-			 *	@access private
1083
-			 *	@param int $value The value of the attribute to be checked.
1084
-			 *	@param int $checkvalue The minimum numeric value allowed
1085
-			 *	@return bool Indicates whether the check passed or not
1086
-			 *	@see checkAttributeValue()
1087
-			 *	@since PHP5 OOP 1.0.0
1088
-			 */
1089
-			private function checkAttributeValueMinval($value, $checkvalue)
1090
-			{
1091
-				if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1092
-				{
1093
-					return false;
1094
-				}
1095
-				if (intval($value) < ($checkvalue))
1096
-				{
1097
-					return false;
1098
-				}
1099
-				return true;
1100
-			}
1101
-
1102
-			/**
1103
-			 *	Helper method invoked by checkAttributeValue().
1104
-			 *
1105
-			 *	The valueless check checks if the attribute has a value
1106
-			 *	(like <a href="blah">) or not (<option selected>). If the given value
1107
-			 *	is a "y" or a "Y", the attribute must not have a value.
1108
-			 *
1109
-			 *	If the given value is an "n" or an "N", the attribute must have one.
1110
-			 *
1111
-			 *	@access private
1112
-			 *	@param int $value The value of the attribute to be checked.
1113
-			 *	@param mixed $checkvalue This variable is ignored for this test
1114
-			 *	@param string $vless Flag indicating if this attribute is not supposed to have an attribute
1115
-			 *	@return bool Indicates whether the check passed or not
1116
-			 *	@see checkAttributeValue()
1117
-			 *	@since PHP5 OOP 1.0.0
1118
-			 */
1119
-			private function checkAttributeValueValueless($value, $checkvalue, $vless)
1120
-			{
1121
-				if (strtolower($checkvalue) != $vless)
1122
-				{
1123
-					return false;
1124
-				}
1125
-				return true;
1126
-			}
1127
-
1128
-			/**
1129
-			 *	Decodes numeric HTML entities
1130
-			 *
1131
-			 *	This method decodes numeric HTML entities (&#65; and &#x41;). It doesn't
1132
-			 *	do anything with other entities like &auml;, but we don't need them in the
1133
-			 *	URL protocol white listing system anyway.
1134
-			 *
1135
-			 *	@access private
1136
-			 *	@param string $value The entitiy to be decoded.
1137
-			 *	@return string Decoded entity
1138
-			 *	@since PHP4 OOP 0.0.1
1139
-			 */
1140
-			private function decodeEntities($string)
1141
-			{
1142
-				$string = preg_replace('/&#([0-9]+);/e', 'chr("\\1")', $string);
1143
-				$string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', 'chr(hexdec("\\1"))', $string);
1144
-				return $string;
1145
-			}
1146
-
1147
-			/**
1148
-			 *	Returns PHP5 OOP version # of kses.
1149
-			 *
1150
-			 *	Since this class has been refactored and documented and proven to work,
1151
-			 *	I'm fixing the version number at 1.0.0.
1152
-			 *
1153
-			 *	This version is syntax compatible with the PHP4 OOP version 0.0.2.  Future
1154
-			 *	versions may not be syntax compatible.
1155
-			 *
1156
-			 *	@access public
1157
-			 *	@return string Version number
1158
-			 *	@since PHP4 OOP 0.0.1
1159
-			 */
1160
-			public function Version()
1161
-			{
1162
-				return 'PHP5 OOP 1.0.2';
1163
-			}
1164
-		}
1165
-	}
113
+            private $allowed_protocols;
114
+            private $allowed_html;
115
+            /**#@-*/
116
+
117
+            /**
118
+             *	Constructor for kses.
119
+             *
120
+             *	This sets a default collection of protocols allowed in links, and creates an
121
+             *	empty set of allowed HTML tags.
122
+             *	@since PHP5 OOP 1.0.0
123
+             */
124
+            public function __construct()
125
+            {
126
+                /**
127
+                 *	You could add protocols such as ftp, new, gopher, mailto, irc, etc.
128
+                 *
129
+                 *	The base values the original kses provided were:
130
+                 *		'http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto'
131
+                 */
132
+                $this->allowed_protocols = array('http', 'ftp', 'mailto');
133
+                $this->allowed_html      = array();
134
+            }
135
+
136
+            /**
137
+             *	Basic task of kses - parses $string and strips it as required.
138
+             *
139
+             *	This method strips all the disallowed (X)HTML tags, attributes
140
+             *	and protocols from the input $string.
141
+             *
142
+             *	@access public
143
+             *	@param string $string String to be stripped of 'evil scripts'
144
+             *	@return string The stripped string
145
+             *	@since PHP4 OOP 0.0.1
146
+             */
147
+            public function Parse($string = "")
148
+            {
149
+                if (get_magic_quotes_gpc())
150
+                {
151
+                    $string = stripslashes($string);
152
+                }
153
+                $string = $this->removeNulls($string);
154
+                //	Remove JavaScript entities from early Netscape 4 versions
155
+                $string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
156
+                $string = $this->normalizeEntities($string);
157
+                $string = $this->filterKsesTextHook($string);
158
+                $string = preg_replace('%(<' . '[^>]*' . '(>|$)' . '|>)%e', "\$this->stripTags('\\1')", $string);
159
+                return $string;
160
+            }
161
+
162
+            /**
163
+             *	Allows for single/batch addition of protocols
164
+             *
165
+             *	This method accepts one argument that can be either a string
166
+             *	or an array of strings.  Invalid data will be ignored.
167
+             *
168
+             *	The argument will be processed, and each string will be added
169
+             *	via AddProtocol().
170
+             *
171
+             *	@access public
172
+             *	@param mixed , A string or array of protocols that will be added to the internal list of allowed protocols.
173
+             *	@return bool Status of adding valid protocols.
174
+             *	@see AddProtocol()
175
+             *	@since PHP5 OOP 1.0.0
176
+             */
177
+            public function AddProtocols()
178
+            {
179
+                $c_args = func_num_args();
180
+                if($c_args != 1)
181
+                {
182
+                    trigger_error("kses5::AddProtocols() did not receive an argument.", E_USER_WARNING);
183
+                    return false;
184
+                }
185
+
186
+                $protocol_data = func_get_arg(0);
187
+
188
+                if(is_array($protocol_data) && count($protocol_data) > 0)
189
+                {
190
+                    foreach($protocol_data as $protocol)
191
+                    {
192
+                        $this->AddProtocol($protocol);
193
+                    }
194
+                    return true;
195
+                }
196
+                elseif(is_string($protocol_data))
197
+                {
198
+                    $this->AddProtocol($protocol_data);
199
+                    return true;
200
+                }
201
+                else
202
+                {
203
+                    trigger_error("kses5::AddProtocols() did not receive a string or an array.", E_USER_WARNING);
204
+                    return false;
205
+                }
206
+            }
207
+
208
+            /**
209
+             *	Allows for single/batch addition of protocols
210
+             *
211
+             *	@deprecated Use AddProtocols()
212
+             *	@see AddProtocols()
213
+             *	@return bool
214
+             *	@since PHP4 OOP 0.0.1
215
+             */
216
+            public function Protocols()
217
+            {
218
+                $c_args = func_num_args();
219
+                if($c_args != 1)
220
+                {
221
+                    trigger_error("kses5::Protocols() did not receive an argument.", E_USER_WARNING);
222
+                    return false;
223
+                }
224
+
225
+                return $this->AddProtocols(func_get_arg(0));
226
+            }
227
+
228
+            /**
229
+             *	Adds a single protocol to $this->allowed_protocols.
230
+             *
231
+             *	This method accepts a string argument and adds it to
232
+             *	the list of allowed protocols to keep when performing
233
+             *	Parse().
234
+             *
235
+             *	@access public
236
+             *	@param string $protocol The name of the protocol to be added.
237
+             *	@return bool Status of adding valid protocol.
238
+             *	@since PHP4 OOP 0.0.1
239
+             */
240
+            public function AddProtocol($protocol = "")
241
+            {
242
+                if(!is_string($protocol))
243
+                {
244
+                    trigger_error("kses5::AddProtocol() requires a string.", E_USER_WARNING);
245
+                    return false;
246
+                }
247
+
248
+                // Remove any inadvertent ':' at the end of the protocol.
249
+                if(substr($protocol, strlen($protocol) - 1, 1) == ":")
250
+                {
251
+                    $protocol = substr($protocol, 0, strlen($protocol) - 1);
252
+                }
253
+
254
+                $protocol = strtolower(trim($protocol));
255
+                if($protocol == "")
256
+                {
257
+                    trigger_error("kses5::AddProtocol() tried to add an empty/NULL protocol.", E_USER_WARNING);
258
+                    return false;
259
+                }
260
+
261
+                //	prevent duplicate protocols from being added.
262
+                if(!in_array($protocol, $this->allowed_protocols))
263
+                {
264
+                    array_push($this->allowed_protocols, $protocol);
265
+                    sort($this->allowed_protocols);
266
+                }
267
+                return true;
268
+            }
269
+
270
+            /**
271
+             *	Removes a single protocol from $this->allowed_protocols.
272
+             *
273
+             *	This method accepts a string argument and removes it from
274
+             *	the list of allowed protocols to keep when performing
275
+             *	Parse().
276
+             *
277
+             *	@access public
278
+             *	@param string $protocol The name of the protocol to be removed.
279
+             *	@return bool Status of removing valid protocol.
280
+             *	@since PHP5 OOP 1.0.0
281
+             */
282
+            public function RemoveProtocol($protocol = "")
283
+            {
284
+                if(!is_string($protocol))
285
+                {
286
+                    trigger_error("kses5::RemoveProtocol() requires a string.", E_USER_WARNING);
287
+                    return false;
288
+                }
289
+
290
+                // Remove any inadvertent ':' at the end of the protocol.
291
+                if(substr($protocol, strlen($protocol) - 1, 1) == ":")
292
+                {
293
+                    $protocol = substr($protocol, 0, strlen($protocol) - 1);
294
+                }
295
+
296
+                $protocol = strtolower(trim($protocol));
297
+                if($protocol == "")
298
+                {
299
+                    trigger_error("kses5::RemoveProtocol() tried to remove an empty/NULL protocol.", E_USER_WARNING);
300
+                    return false;
301
+                }
302
+
303
+                //	Ensures that the protocol exists before removing it.
304
+                if(in_array($protocol, $this->allowed_protocols))
305
+                {
306
+                    $this->allowed_protocols = array_diff($this->allowed_protocols, array($protocol));
307
+                    sort($this->allowed_protocols);
308
+                }
309
+
310
+                return true;
311
+            }
312
+
313
+            /**
314
+             *	Allows for single/batch removal of protocols
315
+             *
316
+             *	This method accepts one argument that can be either a string
317
+             *	or an array of strings.  Invalid data will be ignored.
318
+             *
319
+             *	The argument will be processed, and each string will be removed
320
+             *	via RemoveProtocol().
321
+             *
322
+             *	@access public
323
+             *	@param mixed , A string or array of protocols that will be removed from the internal list of allowed protocols.
324
+             *	@return bool Status of removing valid protocols.
325
+             *	@see RemoveProtocol()
326
+             *	@since PHP5 OOP 1.0.0
327
+             */
328
+            public function RemoveProtocols()
329
+            {
330
+                $c_args = func_num_args();
331
+                if($c_args != 1)
332
+                {
333
+                    return false;
334
+                }
335
+
336
+                $protocol_data = func_get_arg(0);
337
+
338
+                if(is_array($protocol_data) && count($protocol_data) > 0)
339
+                {
340
+                    foreach($protocol_data as $protocol)
341
+                    {
342
+                        $this->RemoveProtocol($protocol);
343
+                    }
344
+                }
345
+                elseif(is_string($protocol_data))
346
+                {
347
+                    $this->RemoveProtocol($protocol_data);
348
+                    return true;
349
+                }
350
+                else
351
+                {
352
+                    trigger_error("kses5::RemoveProtocols() did not receive a string or an array.", E_USER_WARNING);
353
+                    return false;
354
+                }
355
+            }
356
+
357
+            /**
358
+             *	Allows for single/batch replacement of protocols
359
+             *
360
+             *	This method accepts one argument that can be either a string
361
+             *	or an array of strings.  Invalid data will be ignored.
362
+             *
363
+             *	Existing protocols will be removed, then the argument will be
364
+             *	processed, and each string will be added via AddProtocol().
365
+             *
366
+             *	@access public
367
+             *	@param mixed , A string or array of protocols that will be the new internal list of allowed protocols.
368
+             *	@return bool Status of replacing valid protocols.
369
+             *	@since PHP5 OOP 1.0.1
370
+             *	@see AddProtocol()
371
+             */
372
+            public function SetProtocols()
373
+            {
374
+                $c_args = func_num_args();
375
+                if($c_args != 1)
376
+                {
377
+                    trigger_error("kses5::SetProtocols() did not receive an argument.", E_USER_WARNING);
378
+                    return false;
379
+                }
380
+
381
+                $protocol_data = func_get_arg(0);
382
+
383
+                if(is_array($protocol_data) && count($protocol_data) > 0)
384
+                {
385
+                    $this->allowed_protocols = array();
386
+                    foreach($protocol_data as $protocol)
387
+                    {
388
+                        $this->AddProtocol($protocol);
389
+                    }
390
+                    return true;
391
+                }
392
+                elseif(is_string($protocol_data))
393
+                {
394
+                    $this->allowed_protocols = array();
395
+                    $this->AddProtocol($protocol_data);
396
+                    return true;
397
+                }
398
+                else
399
+                {
400
+                    trigger_error("kses5::SetProtocols() did not receive a string or an array.", E_USER_WARNING);
401
+                    return false;
402
+                }
403
+            }
404
+
405
+            /**
406
+             *	Raw dump of allowed protocols
407
+             *
408
+             *	This returns an indexed array of allowed protocols for a particular KSES
409
+             *	instantiation.
410
+             *
411
+             *	@access public
412
+             *	@return array The list of allowed protocols.
413
+             *	@since PHP5 OOP 1.0.2
414
+             */
415
+            public function DumpProtocols()
416
+            {
417
+                return $this->allowed_protocols;
418
+            }
419
+
420
+            /**
421
+             *	Raw dump of allowed (X)HTML elements
422
+             *
423
+             *	This returns an indexed array of allowed (X)HTML elements and attributes
424
+             *	for a particular KSES instantiation.
425
+             *
426
+             *	@access public
427
+             *	@return array The list of allowed elements.
428
+             *	@since PHP5 OOP 1.0.2
429
+             */
430
+            public function DumpElements()
431
+            {
432
+                return $this->allowed_html;
433
+            }
434
+
435
+
436
+            /**
437
+             *	Adds valid (X)HTML with corresponding attributes that will be kept when stripping 'evil scripts'.
438
+             *
439
+             *	This method accepts one argument that can be either a string
440
+             *	or an array of strings.  Invalid data will be ignored.
441
+             *
442
+             *	@access public
443
+             *	@param string $tag (X)HTML tag that will be allowed after stripping text.
444
+             *	@param array $attribs Associative array of allowed attributes - key => attribute name - value => attribute parameter
445
+             *	@return bool Status of Adding (X)HTML and attributes.
446
+             *	@since PHP4 OOP 0.0.1
447
+             */
448
+            public function AddHTML($tag = "", $attribs = array())
449
+            {
450
+                if(!is_string($tag))
451
+                {
452
+                    trigger_error("kses5::AddHTML() requires the tag to be a string", E_USER_WARNING);
453
+                    return false;
454
+                }
455
+
456
+                $tag = strtolower(trim($tag));
457
+                if($tag == "")
458
+                {
459
+                    trigger_error("kses5::AddHTML() tried to add an empty/NULL tag", E_USER_WARNING);
460
+                    return false;
461
+                }
462
+
463
+                if(!is_array($attribs))
464
+                {
465
+                    trigger_error("kses5::AddHTML() requires an array (even an empty one) of attributes for '$tag'", E_USER_WARNING);
466
+                    return false;
467
+                }
468
+
469
+                $new_attribs = array();
470
+                if(is_array($attribs) && count($attribs) > 0)
471
+                {
472
+                    foreach($attribs as $idx1 => $val1)
473
+                    {
474
+                        $new_idx1 = strtolower($idx1);
475
+                        $new_val1 = $attribs[$idx1];
476
+
477
+                        if(is_array($new_val1) && count($attribs) > 0)
478
+                        {
479
+                            $tmp_val = array();
480
+                            foreach($new_val1 as $idx2 => $val2)
481
+                            {
482
+                                $new_idx2 = strtolower($idx2);
483
+                                $tmp_val[$new_idx2] = $val2;
484
+                            }
485
+                            $new_val1 = $tmp_val;
486
+                        }
487
+
488
+                        $new_attribs[$new_idx1] = $new_val1;
489
+                    }
490
+                }
491
+
492
+                $this->allowed_html[$tag] = $new_attribs;
493
+                return true;
494
+            }
495
+
496
+            /**
497
+             *	This method removes any NULL characters in $string.
498
+             *
499
+             *	@access private
500
+             *	@param string $string
501
+             *	@return string String without any NULL/chr(173)
502
+             *	@since PHP4 OOP 0.0.1
503
+             */
504
+            private function removeNulls($string)
505
+            {
506
+                $string = preg_replace('/\0+/', '', $string);
507
+                $string = preg_replace('/(\\\\0)+/', '', $string);
508
+                return $string;
509
+            }
510
+
511
+            /**
512
+             *	Normalizes HTML entities
513
+             *
514
+             *	This function normalizes HTML entities. It will convert "AT&T" to the correct
515
+             *	"AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
516
+             *
517
+             *	@access private
518
+             *	@param string $string
519
+             *	@return string String with normalized entities
520
+             *	@since PHP4 OOP 0.0.1
521
+             */
522
+            private function normalizeEntities($string)
523
+            {
524
+                # Disarm all entities by converting & to &amp;
525
+                $string = str_replace('&', '&amp;', $string);
526
+
527
+                #	TODO: Change back (Keep?) the allowed entities in our entity white list
528
+
529
+                #	Keeps entities that start with [A-Za-z]
530
+                $string = preg_replace(
531
+                    '/&amp;([A-Za-z][A-Za-z0-9]{0,19});/',
532
+                    '&\\1;',
533
+                    $string
534
+                );
535
+
536
+                #	Change numeric entities to valid 16 bit values
537
+
538
+                $string = preg_replace(
539
+                    '/&amp;#0*([0-9]{1,5});/e',
540
+                    '\$this->normalizeEntities16bit("\\1")',
541
+                    $string
542
+                );
543
+
544
+                #	Change &XHHHHHHH (Hex digits) to 16 bit hex values
545
+                $string = preg_replace(
546
+                    '/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/',
547
+                    '&#\\1\\2;',
548
+                    $string
549
+                );
550
+
551
+                return $string;
552
+            }
553
+
554
+            /**
555
+             *	Helper method used by normalizeEntites()
556
+             *
557
+             *	This method helps normalizeEntities() to only accept 16 bit values
558
+             *	and nothing more for &#number; entities.
559
+             *
560
+             *	This method helps normalize_entities() during a preg_replace()
561
+             *	where a &#(0)*XXXXX; occurs.  The '(0)*XXXXXX' value is converted to
562
+             *	a number and the result is returned as a numeric entity if the number
563
+             *	is less than 65536.  Otherwise, the value is returned 'as is'.
564
+             *
565
+             *	@access private
566
+             *	@param string $i
567
+             *	@return string Normalized numeric entity
568
+             *	@see normalizeEntities()
569
+             *	@since PHP4 OOP 0.0.1
570
+             */
571
+            private function normalizeEntities16bit($i)
572
+            {
573
+                return (($i > 65535) ? "&amp;#$i;" : "&#$i;");
574
+            }
575
+
576
+            /**
577
+             *	Allows for additional user defined modifications to text.
578
+             *
579
+             *	This method allows for additional modifications to be performed on
580
+             *	a string that's being run through Parse().  Currently, it returns the
581
+             *	input string 'as is'.
582
+             *
583
+             *	This method is provided for users to extend the kses class for their own
584
+             *	requirements.
585
+             *
586
+             *	@access public
587
+             *	@param string $string String to perfrom additional modifications on.
588
+             *	@return string User modified string.
589
+             *	@see Parse()
590
+             *	@since PHP5 OOP 1.0.0
591
+             */
592
+            private function filterKsesTextHook($string)
593
+            {
594
+                return $string;
595
+            }
596
+
597
+            /**
598
+             *	Allows for additional user defined modifications to text.
599
+             *
600
+             *	@deprecated use filterKsesTextHook()
601
+             *	@param string $string
602
+             *	@return string
603
+             *	@see filterKsesTextHook()
604
+             *	@since PHP4 OOP 0.0.1
605
+             */
606
+            private function _hook($string)
607
+            {
608
+                return $this->filterKsesTextHook($string);
609
+            }
610
+
611
+            /**
612
+             *	This method goes through an array, and changes the keys to all lower case.
613
+             *
614
+             *	@access private
615
+             *	@param array $in_array Associative array
616
+             *	@return array Modified array
617
+             *	@since PHP4 OOP 0.0.1
618
+             */
619
+            private function makeArrayKeysLowerCase($in_array)
620
+            {
621
+                $out_array = array();
622
+
623
+                if(is_array($in_array) && count($in_array) > 0)
624
+                {
625
+                    foreach ($in_array as $in_key => $in_val)
626
+                    {
627
+                        $out_key = strtolower($in_key);
628
+                        $out_array[$out_key] = array();
629
+
630
+                        if(is_array($in_val) && count($in_val) > 0)
631
+                        {
632
+                            foreach ($in_val as $in_key2 => $in_val2)
633
+                            {
634
+                                $out_key2 = strtolower($in_key2);
635
+                                $out_array[$out_key][$out_key2] = $in_val2;
636
+                            }
637
+                        }
638
+                    }
639
+                }
640
+
641
+                return $out_array;
642
+            }
643
+
644
+            /**
645
+             *	This method strips out disallowed and/or mangled (X)HTML tags along with assigned attributes.
646
+             *
647
+             *	This method does a lot of work. It rejects some very malformed things
648
+             *	like <:::>. It returns an empty string if the element isn't allowed (look
649
+             *	ma, no strip_tags()!). Otherwise it splits the tag into an element and an
650
+             *	allowed attribute list.
651
+             *
652
+             *	@access private
653
+             *	@param string $string
654
+             *	@return string Modified string minus disallowed/mangled (X)HTML and attributes
655
+             *	@since PHP4 OOP 0.0.1
656
+             */
657
+            private function stripTags($string)
658
+            {
659
+                $string = preg_replace('%\\\\"%', '"', $string);
660
+
661
+                if (substr($string, 0, 1) != '<')
662
+                {
663
+                    # It matched a ">" character
664
+                    return '&gt;';
665
+                }
666
+
667
+                if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
668
+                {
669
+                    # It's seriously malformed
670
+                    return '';
671
+                }
672
+
673
+                $slash    = trim($matches[1]);
674
+                $elem     = $matches[2];
675
+                $attrlist = $matches[3];
676
+
677
+                if (
678
+                    !isset($this->allowed_html[strtolower($elem)]) ||
679
+                    !is_array($this->allowed_html[strtolower($elem)]))
680
+                {
681
+                    #	Found an HTML element not in the white list
682
+                    return '';
683
+                }
684
+
685
+                if ($slash != '')
686
+                {
687
+                    return "<$slash$elem>";
688
+                }
689
+                # No attributes are allowed for closing elements
690
+
691
+                return $this->stripAttributes("$slash$elem", $attrlist);
692
+            }
693
+
694
+            /**
695
+             *	This method strips out disallowed attributes for (X)HTML tags.
696
+             *
697
+             *	This method removes all attributes if none are allowed for this element.
698
+             *	If some are allowed it calls combAttributes() to split them further, and then it
699
+             *	builds up new HTML code from the data that combAttributes() returns. It also
700
+             *	removes "<" and ">" characters, if there are any left. One more thing it
701
+             *	does is to check if the tag has a closing XHTML slash, and if it does,
702
+             *	it puts one in the returned code as well.
703
+             *
704
+             *	@access private
705
+             *	@param string $element (X)HTML tag to check
706
+             *	@param string $attr Text containing attributes to check for validity.
707
+             *	@return string Resulting valid (X)HTML or ''
708
+             *	@see combAttributes()
709
+             *	@since PHP4 OOP 0.0.1
710
+             */
711
+            private function stripAttributes($element, $attr)
712
+            {
713
+                # Is there a closing XHTML slash at the end of the attributes?
714
+                $xhtml_slash = '';
715
+                if (preg_match('%\s/\s*$%', $attr))
716
+                {
717
+                    $xhtml_slash = ' /';
718
+                }
719
+
720
+                # Are any attributes allowed at all for this element?
721
+                if (
722
+                    !isset($this->allowed_html[strtolower($element)]) ||
723
+                    count($this->allowed_html[strtolower($element)]) == 0
724
+                )
725
+                {
726
+                    return "<$element$xhtml_slash>";
727
+                }
728
+
729
+                # Split it
730
+                $attrarr = $this->combAttributes($attr);
731
+
732
+                # Go through $attrarr, and save the allowed attributes for this element
733
+                # in $attr2
734
+                $attr2 = '';
735
+                if(is_array($attrarr) && count($attrarr) > 0)
736
+                {
737
+                    foreach ($attrarr as $arreach)
738
+                    {
739
+                        if(!isset($this->allowed_html[strtolower($element)][strtolower($arreach['name'])]))
740
+                        {
741
+                            continue;
742
+                        }
743
+
744
+                        $current = $this->allowed_html[strtolower($element)][strtolower($arreach['name'])];
745
+
746
+                        if (!is_array($current))
747
+                        {
748
+                            # there are no checks
749
+                            $attr2 .= ' '.$arreach['whole'];
750
+                        }
751
+                        else
752
+                        {
753
+                            # there are some checks
754
+                            $ok = true;
755
+                            if(is_array($current) && count($current) > 0)
756
+                            {
757
+                                foreach ($current as $currkey => $currval)
758
+                                {
759
+                                    if (!$this->checkAttributeValue($arreach['value'], $arreach['vless'], $currkey, $currval))
760
+                                    {
761
+                                        $ok = false;
762
+                                        break;
763
+                                    }
764
+                                }
765
+                            }
766
+
767
+                            if ($ok)
768
+                            {
769
+                                # it passed them
770
+                                $attr2 .= ' '.$arreach['whole'];
771
+                            }
772
+                        }
773
+                    }
774
+                }
775
+
776
+                # Remove any "<" or ">" characters
777
+                $attr2 = preg_replace('/[<>]/', '', $attr2);
778
+                return "<$element$attr2$xhtml_slash>";
779
+            }
780
+
781
+            /**
782
+             *	This method combs through an attribute list string and returns an associative array of attributes and values.
783
+             *
784
+             *	This method does a lot of work. It parses an attribute list into an array
785
+             *	with attribute data, and tries to do the right thing even if it gets weird
786
+             *	input. It will add quotes around attribute values that don't have any quotes
787
+             *	or apostrophes around them, to make it easier to produce HTML code that will
788
+             *	conform to W3C's HTML specification. It will also remove bad URL protocols
789
+             *	from attribute values.
790
+             *
791
+             *	@access private
792
+             *	@param string $attr Text containing tag attributes for parsing
793
+             *	@return array Associative array containing data on attribute and value
794
+             *	@since PHP4 OOP 0.0.1
795
+             */
796
+            private function combAttributes($attr)
797
+            {
798
+                $attrarr  = array();
799
+                $mode     = 0;
800
+                $attrname = '';
801
+
802
+                # Loop through the whole attribute list
803
+
804
+                while (strlen($attr) != 0)
805
+                {
806
+                    # Was the last operation successful?
807
+                    $working = 0;
808
+
809
+                    switch ($mode)
810
+                    {
811
+                        case 0:	# attribute name, href for instance
812
+                            if (preg_match('/^([-a-zA-Z]+)/', $attr, $match))
813
+                            {
814
+                                $attrname = $match[1];
815
+                                $working = $mode = 1;
816
+                                $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
817
+                            }
818
+                            break;
819
+                        case 1:	# equals sign or valueless ("selected")
820
+                            if (preg_match('/^\s*=\s*/', $attr)) # equals sign
821
+                            {
822
+                                $working = 1;
823
+                                $mode    = 2;
824
+                                $attr    = preg_replace('/^\s*=\s*/', '', $attr);
825
+                                break;
826
+                            }
827
+                            if (preg_match('/^\s+/', $attr)) # valueless
828
+                            {
829
+                                $working   = 1;
830
+                                $mode      = 0;
831
+                                $attrarr[] = array(
832
+                                    'name'  => $attrname,
833
+                                    'value' => '',
834
+                                    'whole' => $attrname,
835
+                                    'vless' => 'y'
836
+                                );
837
+                                $attr      = preg_replace('/^\s+/', '', $attr);
838
+                            }
839
+                            break;
840
+                        case 2: # attribute value, a URL after href= for instance
841
+                            if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value"
842
+                            {
843
+                                $thisval   = $this->removeBadProtocols($match[1]);
844
+                                $attrarr[] = array(
845
+                                    'name'  => $attrname,
846
+                                    'value' => $thisval,
847
+                                    'whole' => $attrname . '="' . $thisval . '"',
848
+                                    'vless' => 'n'
849
+                                );
850
+                                $working   = 1;
851
+                                $mode      = 0;
852
+                                $attr      = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
853
+                                break;
854
+                            }
855
+                            if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value'
856
+                            {
857
+                                $thisval   = $this->removeBadProtocols($match[1]);
858
+                                $attrarr[] = array(
859
+                                    'name'  => $attrname,
860
+                                    'value' => $thisval,
861
+                                    'whole' => "$attrname='$thisval'",
862
+                                    'vless' => 'n'
863
+                                );
864
+                                $working   = 1;
865
+                                $mode      = 0;
866
+                                $attr      = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
867
+                                break;
868
+                            }
869
+                            if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value
870
+                            {
871
+                                $thisval   = $this->removeBadProtocols($match[1]);
872
+                                $attrarr[] = array(
873
+                                    'name'  => $attrname,
874
+                                    'value' => $thisval,
875
+                                    'whole' => $attrname . '="' . $thisval . '"',
876
+                                    'vless' => 'n'
877
+                                );
878
+                                # We add quotes to conform to W3C's HTML spec.
879
+                                $working   = 1;
880
+                                $mode      = 0;
881
+                                $attr      = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
882
+                            }
883
+                            break;
884
+                    }
885
+
886
+                    if ($working == 0) # not well formed, remove and try again
887
+                    {
888
+                        $attr = preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $attr);
889
+                        $mode = 0;
890
+                    }
891
+                }
892
+
893
+                # special case, for when the attribute list ends with a valueless
894
+                # attribute like "selected"
895
+                if ($mode == 1)
896
+                {
897
+                    $attrarr[] = array(
898
+                        'name'  => $attrname,
899
+                        'value' => '',
900
+                        'whole' => $attrname,
901
+                        'vless' => 'y'
902
+                    );
903
+                }
904
+
905
+                return $attrarr;
906
+            }
907
+
908
+            /**
909
+             *	This method removes disallowed protocols.
910
+             *
911
+             *	This method removes all non-allowed protocols from the beginning of
912
+             *	$string. It ignores whitespace and the case of the letters, and it does
913
+             *	understand HTML entities. It does its work in a while loop, so it won't be
914
+             *	fooled by a string like "javascript:javascript:alert(57)".
915
+             *
916
+             *	@access private
917
+             *	@param string $string String to check for protocols
918
+             *	@return string String with removed protocols
919
+             *	@since PHP4 OOP 0.0.1
920
+             */
921
+            private function removeBadProtocols($string)
922
+            {
923
+                $string  = $this->RemoveNulls($string);
924
+                $string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
925
+                $string2 = $string . 'a';
926
+
927
+                $string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
928
+                if(isset($string2[1]) && !preg_match('%/\?%',$string2[0]))
929
+                {
930
+                    $string = $this->filterProtocols($string2[0]).trim($string2[1]);
931
+                }
932
+                return $string;
933
+            }
934
+
935
+            /**
936
+             *	Helper method used by removeBadProtocols()
937
+             *
938
+             *	This function processes URL protocols, checks to see if they're in the white-
939
+             *	list or not, and returns different data depending on the answer.
940
+             *
941
+             *	@access private
942
+             *	@param string $string String to check for protocols
943
+             *	@return string String with removed protocols
944
+             *	@see removeBadProtocols()
945
+             *	@since PHP4 OOP 0.0.1
946
+             */
947
+            private function filterProtocols($string)
948
+            {
949
+                $string = $this->decodeEntities($string);
950
+                $string = preg_replace('/\s/', '', $string);
951
+                $string = $this->removeNulls($string);
952
+                $string = preg_replace('/\xad+/', '', $string2); # deals with Opera "feature"
953
+                $string = strtolower($string);
954
+
955
+                if(is_array($this->allowed_protocols) && count($this->allowed_protocols) > 0)
956
+                {
957
+                    foreach ($this->allowed_protocols as $one_protocol)
958
+                    {
959
+                        if (strtolower($one_protocol) == $string)
960
+                        {
961
+                            return "$string:";
962
+                        }
963
+                    }
964
+                }
965
+
966
+                return '';
967
+            }
968
+
969
+            /**
970
+             *	Controller method for performing checks on attribute values.
971
+             *
972
+             *	This method calls the appropriate method as specified by $checkname with
973
+             *	the parameters $value, $vless, and $checkvalue, and returns the result
974
+             *	of the call.
975
+             *
976
+             *	This method's functionality can be expanded by creating new methods
977
+             *	that would match checkAttributeValue[$checkname].
978
+             *
979
+             *	Current checks implemented are: "maxlen", "minlen", "maxval", "minval" and "valueless"
980
+             *
981
+             *	@access private
982
+             *	@param string $value The value of the attribute to be checked.
983
+             *	@param string $vless Indicates whether the the value is supposed to be valueless
984
+             *	@param string $checkname The check to be performed
985
+             *	@param string $checkvalue The value that is to be checked against
986
+             *	@return bool Indicates whether the check passed or not
987
+             *	@since PHP5 OOP 1.0.0
988
+             */
989
+            private function checkAttributeValue($value, $vless, $checkname, $checkvalue)
990
+            {
991
+                $ok = true;
992
+                $check_attribute_method_name  = 'checkAttributeValue' . ucfirst(strtolower($checkname));
993
+                if(method_exists($this, $check_attribute_method_name))
994
+                {
995
+                    $ok = $this->$check_attribute_method_name($value, $checkvalue, $vless);
996
+                }
997
+
998
+                return $ok;
999
+            }
1000
+
1001
+            /**
1002
+             *	Helper method invoked by checkAttributeValue().
1003
+             *
1004
+             *	The maxlen check makes sure that the attribute value has a length not
1005
+             *	greater than the given value. This can be used to avoid Buffer Overflows
1006
+             *	in WWW clients and various Internet servers.
1007
+             *
1008
+             *	@access private
1009
+             *	@param string $value The value of the attribute to be checked.
1010
+             *	@param int $checkvalue The maximum value allowed
1011
+             *	@return bool Indicates whether the check passed or not
1012
+             *	@see checkAttributeValue()
1013
+             *	@since PHP5 OOP 1.0.0
1014
+             */
1015
+            private function checkAttributeValueMaxlen($value, $checkvalue)
1016
+            {
1017
+                if (strlen($value) > intval($checkvalue))
1018
+                {
1019
+                    return false;
1020
+                }
1021
+                return true;
1022
+            }
1023
+
1024
+            /**
1025
+             *	Helper method invoked by checkAttributeValue().
1026
+             *
1027
+             *	The minlen check makes sure that the attribute value has a length not
1028
+             *	smaller than the given value.
1029
+             *
1030
+             *	@access private
1031
+             *	@param string $value The value of the attribute to be checked.
1032
+             *	@param int $checkvalue The minimum value allowed
1033
+             *	@return bool Indicates whether the check passed or not
1034
+             *	@see checkAttributeValue()
1035
+             *	@since PHP5 OOP 1.0.0
1036
+             */
1037
+            private function checkAttributeValueMinlen($value, $checkvalue)
1038
+            {
1039
+                if (strlen($value) < intval($checkvalue))
1040
+                {
1041
+                    return false;
1042
+                }
1043
+                return true;
1044
+            }
1045
+
1046
+            /**
1047
+             *	Helper method invoked by checkAttributeValue().
1048
+             *
1049
+             *	The maxval check does two things: it checks that the attribute value is
1050
+             *	an integer from 0 and up, without an excessive amount of zeroes or
1051
+             *	whitespace (to avoid Buffer Overflows). It also checks that the attribute
1052
+             *	value is not greater than the given value.
1053
+             *
1054
+             *	This check can be used to avoid Denial of Service attacks.
1055
+             *
1056
+             *	@access private
1057
+             *	@param int $value The value of the attribute to be checked.
1058
+             *	@param int $checkvalue The maximum numeric value allowed
1059
+             *	@return bool Indicates whether the check passed or not
1060
+             *	@see checkAttributeValue()
1061
+             *	@since PHP5 OOP 1.0.0
1062
+             */
1063
+            private function checkAttributeValueMaxval($value, $checkvalue)
1064
+            {
1065
+                if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1066
+                {
1067
+                    return false;
1068
+                }
1069
+                if (intval($value) > intval($checkvalue))
1070
+                {
1071
+                    return false;
1072
+                }
1073
+                return true;
1074
+            }
1075
+
1076
+            /**
1077
+             *	Helper method invoked by checkAttributeValue().
1078
+             *
1079
+             *	The minval check checks that the attribute value is a positive integer,
1080
+             *	and that it is not smaller than the given value.
1081
+             *
1082
+             *	@access private
1083
+             *	@param int $value The value of the attribute to be checked.
1084
+             *	@param int $checkvalue The minimum numeric value allowed
1085
+             *	@return bool Indicates whether the check passed or not
1086
+             *	@see checkAttributeValue()
1087
+             *	@since PHP5 OOP 1.0.0
1088
+             */
1089
+            private function checkAttributeValueMinval($value, $checkvalue)
1090
+            {
1091
+                if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1092
+                {
1093
+                    return false;
1094
+                }
1095
+                if (intval($value) < ($checkvalue))
1096
+                {
1097
+                    return false;
1098
+                }
1099
+                return true;
1100
+            }
1101
+
1102
+            /**
1103
+             *	Helper method invoked by checkAttributeValue().
1104
+             *
1105
+             *	The valueless check checks if the attribute has a value
1106
+             *	(like <a href="blah">) or not (<option selected>). If the given value
1107
+             *	is a "y" or a "Y", the attribute must not have a value.
1108
+             *
1109
+             *	If the given value is an "n" or an "N", the attribute must have one.
1110
+             *
1111
+             *	@access private
1112
+             *	@param int $value The value of the attribute to be checked.
1113
+             *	@param mixed $checkvalue This variable is ignored for this test
1114
+             *	@param string $vless Flag indicating if this attribute is not supposed to have an attribute
1115
+             *	@return bool Indicates whether the check passed or not
1116
+             *	@see checkAttributeValue()
1117
+             *	@since PHP5 OOP 1.0.0
1118
+             */
1119
+            private function checkAttributeValueValueless($value, $checkvalue, $vless)
1120
+            {
1121
+                if (strtolower($checkvalue) != $vless)
1122
+                {
1123
+                    return false;
1124
+                }
1125
+                return true;
1126
+            }
1127
+
1128
+            /**
1129
+             *	Decodes numeric HTML entities
1130
+             *
1131
+             *	This method decodes numeric HTML entities (&#65; and &#x41;). It doesn't
1132
+             *	do anything with other entities like &auml;, but we don't need them in the
1133
+             *	URL protocol white listing system anyway.
1134
+             *
1135
+             *	@access private
1136
+             *	@param string $value The entitiy to be decoded.
1137
+             *	@return string Decoded entity
1138
+             *	@since PHP4 OOP 0.0.1
1139
+             */
1140
+            private function decodeEntities($string)
1141
+            {
1142
+                $string = preg_replace('/&#([0-9]+);/e', 'chr("\\1")', $string);
1143
+                $string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', 'chr(hexdec("\\1"))', $string);
1144
+                return $string;
1145
+            }
1146
+
1147
+            /**
1148
+             *	Returns PHP5 OOP version # of kses.
1149
+             *
1150
+             *	Since this class has been refactored and documented and proven to work,
1151
+             *	I'm fixing the version number at 1.0.0.
1152
+             *
1153
+             *	This version is syntax compatible with the PHP4 OOP version 0.0.2.  Future
1154
+             *	versions may not be syntax compatible.
1155
+             *
1156
+             *	@access public
1157
+             *	@return string Version number
1158
+             *	@since PHP4 OOP 0.0.1
1159
+             */
1160
+            public function Version()
1161
+            {
1162
+                return 'PHP5 OOP 1.0.2';
1163
+            }
1164
+        }
1165
+    }
1166 1166
 ?>
1167 1167
\ No newline at end of file
Please login to merge, or discard this patch.
main/inc/lib/kses-0.2.2/oop/test.oop.kses.php 1 patch
Indentation   +503 added lines, -503 removed lines patch added patch discarded remove patch
@@ -1,507 +1,507 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-	//	This is a q&d program that shows some of the results of
4
-	//	running KSES.  If you have further questions, check the
5
-	//	current valid email address at http://chaos.org/contact/
6
-
7
-	//	Make sure we're in a usable PHP environment
8
-	if(substr(phpversion(), 0, 1) < 4)
9
-	{
10
-		define('KSESTEST_VER', 0);
11
-	}
12
-	elseif(substr(phpversion(), 0, 1) >= 5)
13
-	{
14
-		define('KSESTEST_VER', 5);
15
-	}
16
-	else
17
-	{
18
-		define('KSESTEST_VER', 4);
19
-	}
20
-
21
-	//	See if we're in command line or web
22
-	if($_SERVER["DOCUMENT_ROOT"] == "")
23
-	{
24
-		define('KSESTEST_ENV', 'CLI');
25
-	}
26
-	else
27
-	{
28
-		define('KSESTEST_ENV', 'WEB');
29
-	}
30
-
31
-	if(KSESTEST_VER == 0)
32
-	{
33
-		$message = array(
34
-			"Error: Not using a current version of PHP!",
35
-			"You are using PHP version " . phpversion() . ".",
36
-			"KSES Class version requires PHP4 or better.",
37
-			"KSES test program ending."
38
-			);
39
-
40
-		displayPage(
41
-			array("title" => "Error running KSES test", "message" => $message)
42
-		);
43
-
44
-		exit();
45
-	}
46
-
47
-	$include_file = "php" . KSESTEST_VER . ".class.kses.php";
48
-	if(file_exists($include_file) && is_readable($include_file))
49
-	{
50
-		include_once($include_file);
51
-	}
52
-	else
53
-	{
54
-		$message = array(
55
-			"Error:  Unable to find '" . $include_file . "'.",
56
-			"Please check your include path and make sure the file is available.",
57
-			"Path: " . ini_get('include_path')
58
-		);
59
-
60
-		displayPage(
61
-			array('title' => 'Unable to include ' . $include_file, 'message' => $message)
62
-		);
63
-
64
-		exit();
65
-	}
66
-
67
-	$kses_type = "kses" . KSESTEST_VER;
68
-	$myKses = new $kses_type;
69
-
70
-	$test_text = array();
71
-	$test_text = test1_protocols($myKses);
72
-	$test_text = array_merge($test_text, test1_html($myKses));
73
-	$test_text = array_merge($test_text, test1_kses($myKses));
74
-
75
-	displayPage(
76
-		array('title' => 'New Test', 'message' => $test_text)
77
-	);
78
-
79
-	function test1_kses(&$myKses)
80
-	{
81
-		$out = array(output_hr(), "Testing current configuration");
82
-
83
-		$test_tags = array(
84
-			'<a href="http://www.chaos.org/">www.chaos.org</a>',
85
-			'<a name="X">Short \'a name\' tag</a>',
86
-			'<td colspan="3" rowspan="5">Foo</td>',
87
-			'<td rowspan="2" class="mugwump" style="background-color: rgb(255, 204 204);">Bar</td>',
88
-			'<td nowrap>Very Long String running to 1000 characters...</td>',
89
-			'<td bgcolor="#00ff00" nowrap>Very Long String with a blue background</td>',
90
-			'<a href="proto1://www.foo.com">New protocol test</a>',
91
-			'<img src="proto2://www.foo.com" />',
92
-			'<a href="javascript:javascript:javascript:javascript:javascript:alert(\'Boo!\');">bleep</a>',
93
-			'<a href="proto4://abc.xyz.foo.com">Another new protocol</a>',
94
-			'<a href="proto9://foo.foo.foo.foo.foo.org/">Test of "proto9"</a>',
95
-			'<td width="75">Bar!</td>',
96
-			'<td width="200">Long Cell</td>'
97
-		);
98
-
99
-		$out_li = array();
100
-		// Keep only allowed HTML from the presumed 'form'.
101
-		foreach($test_tags as $tag)
102
-		{
103
-			$temp  = $myKses->Parse($tag);
104
-			$check = ($temp == $tag) ? true : false;
105
-			$text  = ($temp == $tag) ? 'pass' : 'fail';
106
-
107
-			$li_text  = output_testresult($check, $text) . output_newline();
108
-			$li_text .= "Input: &nbsp;" . output_translate($tag) . output_newline();
109
-			$li_text .= "Output: " . output_translate($temp);
110
-			if(KSESTEST_ENV == 'CLI')
111
-			{
112
-				$li_text .= output_newline();
113
-			}
114
-
115
-			array_push($out_li, output_code_wrap($li_text));
116
-		}
117
-
118
-		$out = array_merge($out, array(output_ul($out_li)));
119
-		array_push($out, output_hr());
120
-		array_push($out, "Testing is now finished.");
121
-		return $out;
122
-	}
123
-
124
-	function output_code_wrap($text)
125
-	{
126
-		if(KSESTEST_ENV == 'CLI')
127
-		{
128
-			return $text;
129
-		}
130
-		else
131
-		{
132
-			return "<code>\n$text<code>\n";
133
-		}
134
-	}
135
-
136
-	function output_translate($text)
137
-	{
138
-		if(KSESTEST_ENV == 'CLI')
139
-		{
140
-			return $text;
141
-		}
142
-		else
143
-		{
144
-			return htmlentities($text);
145
-		}
146
-	}
147
-
148
-	function output_testresult($pass = false, $text = "")
149
-	{
150
-		if(KSESTEST_ENV == 'CLI')
151
-		{
152
-			return '[' . $text . ']';
153
-		}
154
-		else
155
-		{
156
-			if($pass == true)
157
-			{
158
-				return '<span style="color: green;">[' . $text . ']</span>';
159
-			}
160
-			else
161
-			{
162
-				return '<span style="color: red;">[' . $text . ']</span>';
163
-			}
164
-		}
165
-	}
166
-
167
-	function output_spaces()
168
-	{
169
-		if(KSESTEST_ENV == 'WEB')
170
-		{
171
-			$out = "&nbsp;&nbsp;&nbsp;";
172
-		}
173
-		else
174
-		{
175
-			$out = "   ";
176
-		}
177
-
178
-		return $out;
179
-	}
180
-
181
-	function output_newline()
182
-	{
183
-		if(KSESTEST_ENV == 'WEB')
184
-		{
185
-			$out = "<br />\n";
186
-		}
187
-		else
188
-		{
189
-			$out = "\n";
190
-		}
191
-
192
-		return $out;
193
-	}
194
-
195
-	function displayPage($data = array())
196
-	{
197
-		$title   = ($data['title'] == '') ? 'No title' : $data['title'];
198
-		$message = ($data['message'] == '') ? array('No message') : $data['message'];
199
-
200
-		$out = "";
201
-
202
-		foreach($message as $text)
203
-		{
204
-			if(KSESTEST_ENV == 'WEB')
205
-			{
206
-				$header = "\t\t<h1>$title</h1>\n\t\t<hr />\n";
207
-				$out .= "\t\t<p>\n";
208
-				$out .= "\t\t\t$text\n";
209
-				$out .= "\t\t</p>\n";
210
-			}
211
-			else
212
-			{
213
-				$header = "$title\n" . str_repeat('-', 60) . "\n\n";
214
-				$out .= "\t$text\n\n";
215
-			}
216
-		}
217
-
218
-		if(KSESTEST_ENV == 'WEB')
219
-		{
220
-			echo "<html>\n";
221
-			echo "\t<head>\n";
222
-			echo "\t\t<title>$title</title>\n";
223
-			echo "\t</head>\n";
224
-			echo "\t<body>\n";
225
-			echo $header;
226
-			echo $out;
227
-			echo "\t</body>\n";
228
-			echo "</html>\n";
229
-		}
230
-		else
231
-		{
232
-			echo $header;
233
-			echo $out;
234
-		}
235
-	}
236
-
237
-	function output_hr()
238
-	{
239
-		if(KSESTEST_ENV == 'WEB')
240
-		{
241
-			return "\t\t\t<hr />\n";
242
-		}
243
-		else
244
-		{
245
-			return str_repeat(60, '-') . "\n";
246
-		}
247
-	}
248
-
249
-	function output_ul($data = array(), $padding = "")
250
-	{
251
-		if(!is_array($data) || count($data) < 1)
252
-		{
253
-			return "";
254
-		}
255
-
256
-		$text = "";
257
-		if(KSESTEST_ENV == 'WEB')
258
-		{
259
-			$text = "\t\t\t<ul>\n";
260
-			foreach($data as $li)
261
-			{
262
-				$text .= "\t\t\t\t<li>$li</li>\n";
263
-			}
264
-			$text .= "\t\t\t</ul>\n";
265
-		}
266
-		else
267
-		{
268
-			foreach($data as $li)
269
-			{
270
-				$text .= $padding . "   * $li\n";
271
-			}
272
-		}
273
-
274
-		return $text;
275
-	}
276
-
277
-	function test1_protocols(&$myKses)
278
-	{
279
-		$default_prots = $myKses->dumpProtocols();
280
-		$out_text = array();
281
-		if(count($default_prots) > 0)
282
-		{
283
-			array_push($out_text, "Initial protocols from KSES" . KSESTEST_VER . ":");
284
-			array_push($out_text, output_ul($default_prots));
285
-			array_push($out_text, output_hr());
286
-		}
287
-
288
-		$myKses->AddProtocols(array("proto1", "proto2:", "proto3"));   // Add a list of protocols
289
-		$myKses->AddProtocols("proto4:");  // Add a single protocol (Note ':' is optional at end)
290
-		$myKses->AddProtocol("proto9", "mystery:", "anarchy");
291
-		$myKses->AddProtocol("alpha", "beta", "gamma:");
292
-
293
-		$add_protocol  = "\t\t\t<ol>\n";
294
-		$add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols(array("proto1", "proto2:", "proto3"));</li>' . "\n";
295
-		$add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols("proto4:");</li>' . "\n";
296
-		$add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols("proto4:");</li>' . "\n";
297
-		$add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocol("proto9", "mystery:", "anarchy");</li>' . "\n";
298
-		$add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocol("alpha", "beta", "gamma:");</li>' . "\n";
299
-		$add_protocol .= "\t\t\t</ol>\n";
300
-
301
-		array_push($out_text, $add_protocol);
302
-
303
-		$new_prots = $myKses->dumpProtocols();
304
-		if(count($new_prots) > 0)
305
-		{
306
-			array_push($out_text, "New protocols from KSES" . KSESTEST_VER . " after using AddProtocol(s):");
307
-			array_push($out_text, output_ul($new_prots));
308
-			array_push($out_text, output_hr());
309
-		}
310
-
311
-		$myKses->RemoveProtocols(array("mystery", "anarchy:"));
312
-		$myKses->RemoveProtocols("alpha:");
313
-		$myKses->RemoveProtocol("beta:");
314
-		$myKses->RemoveProtocol("gamma");
315
-
316
-		$remove_protocol  = "\t\t\t<ol>\n";
317
-		$remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocols(array("mystery", "anarchy:"));</li>' . "\n";
318
-		$remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocols("alpha:");</li>' . "\n";
319
-		$remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocol("beta:");</li>' . "\n";
320
-		$remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocol("gamma");</li>' . "\n";
321
-		$remove_protocol .= "\t\t\t</ol>\n";
322
-		array_push($out_text, $remove_protocol);
323
-
324
-		$new_prots = $myKses->dumpProtocols();
325
-		if(count($new_prots) > 0)
326
-		{
327
-			array_push($out_text, "Resulting protocols from KSES" . KSESTEST_VER . " after using RemoveProtocol(s):");
328
-			array_push($out_text, output_ul($new_prots));
329
-			array_push($out_text, output_hr());
330
-		}
331
-
332
-		$myKses->SetProtocols(array("https", "gopher", "news"));
333
-		$set_protocol  = "\t\t\t<ol>\n";
334
-		$set_protocol .= "\t\t\t\t" . '<li>$myKses->SetProtocols(array("https", "gopher", "news"));</li>' . "\n";
335
-		$set_protocol .= "\t\t\t</ol>\n";
336
-		array_push($out_text, $set_protocol);
337
-
338
-		$new_prots = $myKses->dumpProtocols();
339
-		if(count($new_prots) > 0)
340
-		{
341
-			array_push($out_text, "Resulting protocols from KSES" . KSESTEST_VER . " after using SetProtocols:");
342
-			array_push($out_text, output_ul($new_prots));
343
-			array_push($out_text, output_hr());
344
-		}
345
-
346
-		//	Invisible reset
347
-		$myKses->SetProtocols(array("http", "proto1", "proto2", "proto9"));
348
-
349
-		return $out_text;
350
-	}
351
-
352
-	function test1_html(&$myKses)
353
-	{
354
-		$out = array();
355
-
356
-		//	Allows <p>|</p> tag
357
-		$myKses->AddHTML("p");
358
-
359
-		//	Allows 'a' tag with href|name attributes,
360
-		//	href has minlen of 10 chars, and maxlen of 25 chars
361
-		//	name has minlen of  2 chars
362
-		$myKses->AddHTML(
363
-			"a",
364
-			array(
365
-				"href" => array('maxlen' => 25, 'minlen' => 10),
366
-				"name" => array('minlen' => 2)
367
-			)
368
-		);
369
-
370
-		//	Allows 'td' tag with colspan|rowspan|class|style|width|nowrap attributes,
371
-		//		colspan has minval of   2       and maxval of 5
372
-		//		rowspan has minval of   3       and maxval of 6
373
-		//		class   has minlen of   1 char  and maxlen of   10 chars
374
-		//		style   has minlen of  10 chars and maxlen of 100 chars
375
-		//		width   has maxval of 100
376
-		//		nowrap  is valueless
377
-		$myKses->AddHTML(
378
-			"td",
379
-			array(
380
-				"colspan" => array('minval' =>   2, 'maxval' =>   5),
381
-				"rowspan" => array('minval' =>   3, 'maxval' =>   6),
382
-				"class"   => array("minlen" =>   1, 'maxlen' =>  10),
383
-				"width"   => array("maxval" => 100),
384
-				"style"   => array('minlen' =>  10, 'maxlen' => 100),
385
-				"nowrap"  => array('valueless' => 'y')
386
-			)
387
-		);
388
-
389
-		array_push($out, "Modifying HTML Tests:");
390
-		$code_text  = "<pre>\n";
391
-		$code_text .= "      //   Allows &lt;p&gt;|&lt;/p&gt; tag\n";
392
-		$code_text .= "      \$myKses-&gt;AddHTML(\"p\");\n";
393
-		$code_text .= "\n";
394
-		$code_text .= "      //   Allows 'a' tag with href|name attributes,\n";
395
-		$code_text .= "      //   href has minlen of 10 chars, and maxlen of 25 chars\n";
396
-		$code_text .= "      //   name has minlen of  2 chars\n";
397
-		$code_text .= "      \$myKses-&gt;AddHTML(\n";
398
-		$code_text .= "         \"a\",\n";
399
-		$code_text .= "         array(\n";
400
-		$code_text .= "            \"href\" =&gt; array('maxlen' =&gt; 25, 'minlen' =&gt; 10),\n";
401
-		$code_text .= "            \"name\" =&gt; array('minlen' =&gt; 2)\n";
402
-		$code_text .= "         )\n";
403
-		$code_text .= "      );\n";
404
-		$code_text .= "\n";
405
-		$code_text .= "      //   Allows 'td' tag with colspan|rowspan|class|style|width|nowrap attributes,\n";
406
-		$code_text .= "      //      colspan has minval of   2       and maxval of 5\n";
407
-		$code_text .= "      //      rowspan has minval of   3       and maxval of 6\n";
408
-		$code_text .= "      //      class   has minlen of   1 char  and maxlen of   10 chars\n";
409
-		$code_text .= "      //      style   has minlen of  10 chars and maxlen of 100 chars\n";
410
-		$code_text .= "      //      width   has maxval of 100\n";
411
-		$code_text .= "      //      nowrap  is valueless\n";
412
-		$code_text .= "      \$myKses-&gt;AddHTML(\n";
413
-		$code_text .= "         \"td\",\n";
414
-		$code_text .= "         array(\n";
415
-		$code_text .= "            \"colspan\" =&gt; array('minval' =&gt;   2, 'maxval' =&gt;   5),\n";
416
-		$code_text .= "            \"rowspan\" =&gt; array('minval' =&gt;   3, 'maxval' =&gt;   6),\n";
417
-		$code_text .= "            \"class\"   =&gt; array(\"minlen\" =&gt;   1, 'maxlen' =&gt;  10),\n";
418
-		$code_text .= "            \"width\"   =&gt; array(\"maxval\" =&gt; 100),\n";
419
-		$code_text .= "            \"style\"   =&gt; array('minlen' =&gt;  10, 'maxlen' =&gt; 100),\n";
420
-		$code_text .= "            \"nowrap\"  =&gt; array('valueless' =&gt; 'y')\n";
421
-		$code_text .= "         )\n";
422
-		$code_text .= "      );\n";
423
-		$code_text .= "</pre>\n";
424
-
425
-		array_push($out, $code_text);
426
-		array_push($out, output_hr());
427
-		array_push($out, "Net results:");
428
-
429
-		$out_elems = $myKses->DumpElements();
430
-		if(count($out_elems) > 0)
431
-		{
432
-			//array_push($out, "\t\t\t<ul>\n");
433
-			foreach($out_elems as $tag => $attr_data)
434
-			{
435
-				$out_li_elems = array();
436
-				$elem_text = "(X)HTML element $tag";
437
-				$allow = "";
438
-				if(isset($attr_data) && is_array($attr_data) && count($attr_data) > 0)
439
-				{
440
-					$allow = " allows attribute";
441
-					if(count($attr_data) > 1)
442
-					{
443
-						$allow .= "s";
444
-					}
445
-					$allow .= ":\n";
446
-				}
447
-
448
-				array_push($out_li_elems, "$elem_text$allow");
449
-
450
-				$attr_test_li = array();
451
-				if(isset($attr_data) && is_array($attr_data) && count($attr_data) > 0)
452
-				{
453
-					foreach($attr_data as $attr_name => $attr_tests)
454
-					{
455
-						$li_text = $attr_name;
456
-						if(isset($attr_tests) && count($attr_tests) > 0)
457
-						{
458
-							foreach($attr_tests as $test_name => $test_val)
459
-							{
460
-								switch($test_name)
461
-								{
462
-									case "maxlen":
463
-										$li_text .= " - maximum length of '" . $test_val . "' characters";
464
-										break;
465
-									case "minlen":
466
-										$li_text .= " - minimum length of '" . $test_val . "' characters";
467
-										break;
468
-									case "minval":
469
-										$li_text .= " - minimum value of '" . $test_val . "'";
470
-										break;
471
-									case "maxval":
472
-										$li_text .= " - maximum value of '" . $test_val . "'";
473
-										break;
474
-									case "valueless":
475
-										switch(strtolower($test_val))
476
-										{
477
-											case 'n':
478
-												$li_text .= " - must not be valueless";
479
-												break;
480
-											case 'y':
481
-												$li_text .= " - must be valueless";
482
-												break;
483
-											default:
484
-												break;
485
-										}
486
-										break;
487
-									default:
488
-										break;
489
-								}
490
-							}
491
-						}
492
-						array_push($attr_test_li, $li_text);
493
-					}
494
-					if(count($attr_test_li) > 0)
495
-					{
496
-						$attr_test_li = output_ul($attr_test_li, "   ");
497
-						$out_li_elems = array("$elem_text$allow$attr_test_li");
498
-					}
499
-				}
500
-				$out = array_merge($out, $out_li_elems);
501
-			}
502
-		}
503
-
504
-		return $out;
505
-	}
3
+    //	This is a q&d program that shows some of the results of
4
+    //	running KSES.  If you have further questions, check the
5
+    //	current valid email address at http://chaos.org/contact/
6
+
7
+    //	Make sure we're in a usable PHP environment
8
+    if(substr(phpversion(), 0, 1) < 4)
9
+    {
10
+        define('KSESTEST_VER', 0);
11
+    }
12
+    elseif(substr(phpversion(), 0, 1) >= 5)
13
+    {
14
+        define('KSESTEST_VER', 5);
15
+    }
16
+    else
17
+    {
18
+        define('KSESTEST_VER', 4);
19
+    }
20
+
21
+    //	See if we're in command line or web
22
+    if($_SERVER["DOCUMENT_ROOT"] == "")
23
+    {
24
+        define('KSESTEST_ENV', 'CLI');
25
+    }
26
+    else
27
+    {
28
+        define('KSESTEST_ENV', 'WEB');
29
+    }
30
+
31
+    if(KSESTEST_VER == 0)
32
+    {
33
+        $message = array(
34
+            "Error: Not using a current version of PHP!",
35
+            "You are using PHP version " . phpversion() . ".",
36
+            "KSES Class version requires PHP4 or better.",
37
+            "KSES test program ending."
38
+            );
39
+
40
+        displayPage(
41
+            array("title" => "Error running KSES test", "message" => $message)
42
+        );
43
+
44
+        exit();
45
+    }
46
+
47
+    $include_file = "php" . KSESTEST_VER . ".class.kses.php";
48
+    if(file_exists($include_file) && is_readable($include_file))
49
+    {
50
+        include_once($include_file);
51
+    }
52
+    else
53
+    {
54
+        $message = array(
55
+            "Error:  Unable to find '" . $include_file . "'.",
56
+            "Please check your include path and make sure the file is available.",
57
+            "Path: " . ini_get('include_path')
58
+        );
59
+
60
+        displayPage(
61
+            array('title' => 'Unable to include ' . $include_file, 'message' => $message)
62
+        );
63
+
64
+        exit();
65
+    }
66
+
67
+    $kses_type = "kses" . KSESTEST_VER;
68
+    $myKses = new $kses_type;
69
+
70
+    $test_text = array();
71
+    $test_text = test1_protocols($myKses);
72
+    $test_text = array_merge($test_text, test1_html($myKses));
73
+    $test_text = array_merge($test_text, test1_kses($myKses));
74
+
75
+    displayPage(
76
+        array('title' => 'New Test', 'message' => $test_text)
77
+    );
78
+
79
+    function test1_kses(&$myKses)
80
+    {
81
+        $out = array(output_hr(), "Testing current configuration");
82
+
83
+        $test_tags = array(
84
+            '<a href="http://www.chaos.org/">www.chaos.org</a>',
85
+            '<a name="X">Short \'a name\' tag</a>',
86
+            '<td colspan="3" rowspan="5">Foo</td>',
87
+            '<td rowspan="2" class="mugwump" style="background-color: rgb(255, 204 204);">Bar</td>',
88
+            '<td nowrap>Very Long String running to 1000 characters...</td>',
89
+            '<td bgcolor="#00ff00" nowrap>Very Long String with a blue background</td>',
90
+            '<a href="proto1://www.foo.com">New protocol test</a>',
91
+            '<img src="proto2://www.foo.com" />',
92
+            '<a href="javascript:javascript:javascript:javascript:javascript:alert(\'Boo!\');">bleep</a>',
93
+            '<a href="proto4://abc.xyz.foo.com">Another new protocol</a>',
94
+            '<a href="proto9://foo.foo.foo.foo.foo.org/">Test of "proto9"</a>',
95
+            '<td width="75">Bar!</td>',
96
+            '<td width="200">Long Cell</td>'
97
+        );
98
+
99
+        $out_li = array();
100
+        // Keep only allowed HTML from the presumed 'form'.
101
+        foreach($test_tags as $tag)
102
+        {
103
+            $temp  = $myKses->Parse($tag);
104
+            $check = ($temp == $tag) ? true : false;
105
+            $text  = ($temp == $tag) ? 'pass' : 'fail';
106
+
107
+            $li_text  = output_testresult($check, $text) . output_newline();
108
+            $li_text .= "Input: &nbsp;" . output_translate($tag) . output_newline();
109
+            $li_text .= "Output: " . output_translate($temp);
110
+            if(KSESTEST_ENV == 'CLI')
111
+            {
112
+                $li_text .= output_newline();
113
+            }
114
+
115
+            array_push($out_li, output_code_wrap($li_text));
116
+        }
117
+
118
+        $out = array_merge($out, array(output_ul($out_li)));
119
+        array_push($out, output_hr());
120
+        array_push($out, "Testing is now finished.");
121
+        return $out;
122
+    }
123
+
124
+    function output_code_wrap($text)
125
+    {
126
+        if(KSESTEST_ENV == 'CLI')
127
+        {
128
+            return $text;
129
+        }
130
+        else
131
+        {
132
+            return "<code>\n$text<code>\n";
133
+        }
134
+    }
135
+
136
+    function output_translate($text)
137
+    {
138
+        if(KSESTEST_ENV == 'CLI')
139
+        {
140
+            return $text;
141
+        }
142
+        else
143
+        {
144
+            return htmlentities($text);
145
+        }
146
+    }
147
+
148
+    function output_testresult($pass = false, $text = "")
149
+    {
150
+        if(KSESTEST_ENV == 'CLI')
151
+        {
152
+            return '[' . $text . ']';
153
+        }
154
+        else
155
+        {
156
+            if($pass == true)
157
+            {
158
+                return '<span style="color: green;">[' . $text . ']</span>';
159
+            }
160
+            else
161
+            {
162
+                return '<span style="color: red;">[' . $text . ']</span>';
163
+            }
164
+        }
165
+    }
166
+
167
+    function output_spaces()
168
+    {
169
+        if(KSESTEST_ENV == 'WEB')
170
+        {
171
+            $out = "&nbsp;&nbsp;&nbsp;";
172
+        }
173
+        else
174
+        {
175
+            $out = "   ";
176
+        }
177
+
178
+        return $out;
179
+    }
180
+
181
+    function output_newline()
182
+    {
183
+        if(KSESTEST_ENV == 'WEB')
184
+        {
185
+            $out = "<br />\n";
186
+        }
187
+        else
188
+        {
189
+            $out = "\n";
190
+        }
191
+
192
+        return $out;
193
+    }
194
+
195
+    function displayPage($data = array())
196
+    {
197
+        $title   = ($data['title'] == '') ? 'No title' : $data['title'];
198
+        $message = ($data['message'] == '') ? array('No message') : $data['message'];
199
+
200
+        $out = "";
201
+
202
+        foreach($message as $text)
203
+        {
204
+            if(KSESTEST_ENV == 'WEB')
205
+            {
206
+                $header = "\t\t<h1>$title</h1>\n\t\t<hr />\n";
207
+                $out .= "\t\t<p>\n";
208
+                $out .= "\t\t\t$text\n";
209
+                $out .= "\t\t</p>\n";
210
+            }
211
+            else
212
+            {
213
+                $header = "$title\n" . str_repeat('-', 60) . "\n\n";
214
+                $out .= "\t$text\n\n";
215
+            }
216
+        }
217
+
218
+        if(KSESTEST_ENV == 'WEB')
219
+        {
220
+            echo "<html>\n";
221
+            echo "\t<head>\n";
222
+            echo "\t\t<title>$title</title>\n";
223
+            echo "\t</head>\n";
224
+            echo "\t<body>\n";
225
+            echo $header;
226
+            echo $out;
227
+            echo "\t</body>\n";
228
+            echo "</html>\n";
229
+        }
230
+        else
231
+        {
232
+            echo $header;
233
+            echo $out;
234
+        }
235
+    }
236
+
237
+    function output_hr()
238
+    {
239
+        if(KSESTEST_ENV == 'WEB')
240
+        {
241
+            return "\t\t\t<hr />\n";
242
+        }
243
+        else
244
+        {
245
+            return str_repeat(60, '-') . "\n";
246
+        }
247
+    }
248
+
249
+    function output_ul($data = array(), $padding = "")
250
+    {
251
+        if(!is_array($data) || count($data) < 1)
252
+        {
253
+            return "";
254
+        }
255
+
256
+        $text = "";
257
+        if(KSESTEST_ENV == 'WEB')
258
+        {
259
+            $text = "\t\t\t<ul>\n";
260
+            foreach($data as $li)
261
+            {
262
+                $text .= "\t\t\t\t<li>$li</li>\n";
263
+            }
264
+            $text .= "\t\t\t</ul>\n";
265
+        }
266
+        else
267
+        {
268
+            foreach($data as $li)
269
+            {
270
+                $text .= $padding . "   * $li\n";
271
+            }
272
+        }
273
+
274
+        return $text;
275
+    }
276
+
277
+    function test1_protocols(&$myKses)
278
+    {
279
+        $default_prots = $myKses->dumpProtocols();
280
+        $out_text = array();
281
+        if(count($default_prots) > 0)
282
+        {
283
+            array_push($out_text, "Initial protocols from KSES" . KSESTEST_VER . ":");
284
+            array_push($out_text, output_ul($default_prots));
285
+            array_push($out_text, output_hr());
286
+        }
287
+
288
+        $myKses->AddProtocols(array("proto1", "proto2:", "proto3"));   // Add a list of protocols
289
+        $myKses->AddProtocols("proto4:");  // Add a single protocol (Note ':' is optional at end)
290
+        $myKses->AddProtocol("proto9", "mystery:", "anarchy");
291
+        $myKses->AddProtocol("alpha", "beta", "gamma:");
292
+
293
+        $add_protocol  = "\t\t\t<ol>\n";
294
+        $add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols(array("proto1", "proto2:", "proto3"));</li>' . "\n";
295
+        $add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols("proto4:");</li>' . "\n";
296
+        $add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocols("proto4:");</li>' . "\n";
297
+        $add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocol("proto9", "mystery:", "anarchy");</li>' . "\n";
298
+        $add_protocol .= "\t\t\t\t" . '<li>$myKses->AddProtocol("alpha", "beta", "gamma:");</li>' . "\n";
299
+        $add_protocol .= "\t\t\t</ol>\n";
300
+
301
+        array_push($out_text, $add_protocol);
302
+
303
+        $new_prots = $myKses->dumpProtocols();
304
+        if(count($new_prots) > 0)
305
+        {
306
+            array_push($out_text, "New protocols from KSES" . KSESTEST_VER . " after using AddProtocol(s):");
307
+            array_push($out_text, output_ul($new_prots));
308
+            array_push($out_text, output_hr());
309
+        }
310
+
311
+        $myKses->RemoveProtocols(array("mystery", "anarchy:"));
312
+        $myKses->RemoveProtocols("alpha:");
313
+        $myKses->RemoveProtocol("beta:");
314
+        $myKses->RemoveProtocol("gamma");
315
+
316
+        $remove_protocol  = "\t\t\t<ol>\n";
317
+        $remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocols(array("mystery", "anarchy:"));</li>' . "\n";
318
+        $remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocols("alpha:");</li>' . "\n";
319
+        $remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocol("beta:");</li>' . "\n";
320
+        $remove_protocol .= "\t\t\t\t" . '<li>$myKses->RemoveProtocol("gamma");</li>' . "\n";
321
+        $remove_protocol .= "\t\t\t</ol>\n";
322
+        array_push($out_text, $remove_protocol);
323
+
324
+        $new_prots = $myKses->dumpProtocols();
325
+        if(count($new_prots) > 0)
326
+        {
327
+            array_push($out_text, "Resulting protocols from KSES" . KSESTEST_VER . " after using RemoveProtocol(s):");
328
+            array_push($out_text, output_ul($new_prots));
329
+            array_push($out_text, output_hr());
330
+        }
331
+
332
+        $myKses->SetProtocols(array("https", "gopher", "news"));
333
+        $set_protocol  = "\t\t\t<ol>\n";
334
+        $set_protocol .= "\t\t\t\t" . '<li>$myKses->SetProtocols(array("https", "gopher", "news"));</li>' . "\n";
335
+        $set_protocol .= "\t\t\t</ol>\n";
336
+        array_push($out_text, $set_protocol);
337
+
338
+        $new_prots = $myKses->dumpProtocols();
339
+        if(count($new_prots) > 0)
340
+        {
341
+            array_push($out_text, "Resulting protocols from KSES" . KSESTEST_VER . " after using SetProtocols:");
342
+            array_push($out_text, output_ul($new_prots));
343
+            array_push($out_text, output_hr());
344
+        }
345
+
346
+        //	Invisible reset
347
+        $myKses->SetProtocols(array("http", "proto1", "proto2", "proto9"));
348
+
349
+        return $out_text;
350
+    }
351
+
352
+    function test1_html(&$myKses)
353
+    {
354
+        $out = array();
355
+
356
+        //	Allows <p>|</p> tag
357
+        $myKses->AddHTML("p");
358
+
359
+        //	Allows 'a' tag with href|name attributes,
360
+        //	href has minlen of 10 chars, and maxlen of 25 chars
361
+        //	name has minlen of  2 chars
362
+        $myKses->AddHTML(
363
+            "a",
364
+            array(
365
+                "href" => array('maxlen' => 25, 'minlen' => 10),
366
+                "name" => array('minlen' => 2)
367
+            )
368
+        );
369
+
370
+        //	Allows 'td' tag with colspan|rowspan|class|style|width|nowrap attributes,
371
+        //		colspan has minval of   2       and maxval of 5
372
+        //		rowspan has minval of   3       and maxval of 6
373
+        //		class   has minlen of   1 char  and maxlen of   10 chars
374
+        //		style   has minlen of  10 chars and maxlen of 100 chars
375
+        //		width   has maxval of 100
376
+        //		nowrap  is valueless
377
+        $myKses->AddHTML(
378
+            "td",
379
+            array(
380
+                "colspan" => array('minval' =>   2, 'maxval' =>   5),
381
+                "rowspan" => array('minval' =>   3, 'maxval' =>   6),
382
+                "class"   => array("minlen" =>   1, 'maxlen' =>  10),
383
+                "width"   => array("maxval" => 100),
384
+                "style"   => array('minlen' =>  10, 'maxlen' => 100),
385
+                "nowrap"  => array('valueless' => 'y')
386
+            )
387
+        );
388
+
389
+        array_push($out, "Modifying HTML Tests:");
390
+        $code_text  = "<pre>\n";
391
+        $code_text .= "      //   Allows &lt;p&gt;|&lt;/p&gt; tag\n";
392
+        $code_text .= "      \$myKses-&gt;AddHTML(\"p\");\n";
393
+        $code_text .= "\n";
394
+        $code_text .= "      //   Allows 'a' tag with href|name attributes,\n";
395
+        $code_text .= "      //   href has minlen of 10 chars, and maxlen of 25 chars\n";
396
+        $code_text .= "      //   name has minlen of  2 chars\n";
397
+        $code_text .= "      \$myKses-&gt;AddHTML(\n";
398
+        $code_text .= "         \"a\",\n";
399
+        $code_text .= "         array(\n";
400
+        $code_text .= "            \"href\" =&gt; array('maxlen' =&gt; 25, 'minlen' =&gt; 10),\n";
401
+        $code_text .= "            \"name\" =&gt; array('minlen' =&gt; 2)\n";
402
+        $code_text .= "         )\n";
403
+        $code_text .= "      );\n";
404
+        $code_text .= "\n";
405
+        $code_text .= "      //   Allows 'td' tag with colspan|rowspan|class|style|width|nowrap attributes,\n";
406
+        $code_text .= "      //      colspan has minval of   2       and maxval of 5\n";
407
+        $code_text .= "      //      rowspan has minval of   3       and maxval of 6\n";
408
+        $code_text .= "      //      class   has minlen of   1 char  and maxlen of   10 chars\n";
409
+        $code_text .= "      //      style   has minlen of  10 chars and maxlen of 100 chars\n";
410
+        $code_text .= "      //      width   has maxval of 100\n";
411
+        $code_text .= "      //      nowrap  is valueless\n";
412
+        $code_text .= "      \$myKses-&gt;AddHTML(\n";
413
+        $code_text .= "         \"td\",\n";
414
+        $code_text .= "         array(\n";
415
+        $code_text .= "            \"colspan\" =&gt; array('minval' =&gt;   2, 'maxval' =&gt;   5),\n";
416
+        $code_text .= "            \"rowspan\" =&gt; array('minval' =&gt;   3, 'maxval' =&gt;   6),\n";
417
+        $code_text .= "            \"class\"   =&gt; array(\"minlen\" =&gt;   1, 'maxlen' =&gt;  10),\n";
418
+        $code_text .= "            \"width\"   =&gt; array(\"maxval\" =&gt; 100),\n";
419
+        $code_text .= "            \"style\"   =&gt; array('minlen' =&gt;  10, 'maxlen' =&gt; 100),\n";
420
+        $code_text .= "            \"nowrap\"  =&gt; array('valueless' =&gt; 'y')\n";
421
+        $code_text .= "         )\n";
422
+        $code_text .= "      );\n";
423
+        $code_text .= "</pre>\n";
424
+
425
+        array_push($out, $code_text);
426
+        array_push($out, output_hr());
427
+        array_push($out, "Net results:");
428
+
429
+        $out_elems = $myKses->DumpElements();
430
+        if(count($out_elems) > 0)
431
+        {
432
+            //array_push($out, "\t\t\t<ul>\n");
433
+            foreach($out_elems as $tag => $attr_data)
434
+            {
435
+                $out_li_elems = array();
436
+                $elem_text = "(X)HTML element $tag";
437
+                $allow = "";
438
+                if(isset($attr_data) && is_array($attr_data) && count($attr_data) > 0)
439
+                {
440
+                    $allow = " allows attribute";
441
+                    if(count($attr_data) > 1)
442
+                    {
443
+                        $allow .= "s";
444
+                    }
445
+                    $allow .= ":\n";
446
+                }
447
+
448
+                array_push($out_li_elems, "$elem_text$allow");
449
+
450
+                $attr_test_li = array();
451
+                if(isset($attr_data) && is_array($attr_data) && count($attr_data) > 0)
452
+                {
453
+                    foreach($attr_data as $attr_name => $attr_tests)
454
+                    {
455
+                        $li_text = $attr_name;
456
+                        if(isset($attr_tests) && count($attr_tests) > 0)
457
+                        {
458
+                            foreach($attr_tests as $test_name => $test_val)
459
+                            {
460
+                                switch($test_name)
461
+                                {
462
+                                    case "maxlen":
463
+                                        $li_text .= " - maximum length of '" . $test_val . "' characters";
464
+                                        break;
465
+                                    case "minlen":
466
+                                        $li_text .= " - minimum length of '" . $test_val . "' characters";
467
+                                        break;
468
+                                    case "minval":
469
+                                        $li_text .= " - minimum value of '" . $test_val . "'";
470
+                                        break;
471
+                                    case "maxval":
472
+                                        $li_text .= " - maximum value of '" . $test_val . "'";
473
+                                        break;
474
+                                    case "valueless":
475
+                                        switch(strtolower($test_val))
476
+                                        {
477
+                                            case 'n':
478
+                                                $li_text .= " - must not be valueless";
479
+                                                break;
480
+                                            case 'y':
481
+                                                $li_text .= " - must be valueless";
482
+                                                break;
483
+                                            default:
484
+                                                break;
485
+                                        }
486
+                                        break;
487
+                                    default:
488
+                                        break;
489
+                                }
490
+                            }
491
+                        }
492
+                        array_push($attr_test_li, $li_text);
493
+                    }
494
+                    if(count($attr_test_li) > 0)
495
+                    {
496
+                        $attr_test_li = output_ul($attr_test_li, "   ");
497
+                        $out_li_elems = array("$elem_text$allow$attr_test_li");
498
+                    }
499
+                }
500
+                $out = array_merge($out, $out_li_elems);
501
+            }
502
+        }
503
+
504
+        return $out;
505
+    }
506 506
 
507 507
 ?>
508 508
\ No newline at end of file
Please login to merge, or discard this patch.
main/inc/lib/kses-0.2.2/oop/php4.class.kses.php 1 patch
Indentation   +1137 added lines, -1137 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-	/*
2
+    /*
3 3
 	 * ==========================================================================================
4 4
 	 *
5 5
 	 * This program is free software and open source software; you can redistribute
@@ -20,1143 +20,1143 @@  discard block
 block discarded – undo
20 20
 	 * ==========================================================================================
21 21
 	 */
22 22
 
23
-	/**
24
-	*	Class file for PHP4 OOP version of kses
25
-	*
26
-	*	This is an updated version of kses to work with PHP4 that works under E_STRICT.
27
-	*
28
-	*	This upgrade provides the following:
29
-	*	+ Version number synced to procedural version number
30
-	*	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
31
-	*	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
32
-	*	+ Kses4 now works in E_STRICT
33
-	*	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol() and RemoveProtocols()
34
-	*	+ Deprecated _hook(), Protocols()
35
-	*	+ Integrated code from kses 0.2.2 into class.
36
-	*	+ Added methods DumpProtocols(), DumpMethods()
37
-	*
38
-	*	@package    kses
39
-	*	@subpackage kses4
40
-	*/
41
-
42
-	if(substr(phpversion(), 0, 1) < 4)
43
-	{
44
-		die("Class kses requires PHP 4 or higher.");
45
-	}
46
-
47
-	/**
48
-	*	Only install KSES4 once
49
-	*/
50
-	if(!defined('KSES_CLASS_PHP4'))
51
-	{
52
-		define('KSES_CLASS_PHP4', true);
53
-
54
-	/**
55
-	*	Kses strips evil scripts!
56
-	*
57
-	*	This class provides the capability for removing unwanted HTML/XHTML, attributes from
58
-	*	tags, and protocols contained in links.  The net result is a much more powerful tool
59
-	*	than the PHP internal strip_tags()
60
-	*
61
-	*	This is a fork of a slick piece of procedural code called 'kses' written by Ulf Harnhammar
62
-	*	The entire set of functions was wrapped in a PHP object with some internal modifications
63
-	*	by Richard Vasquez (http://www.chaos.org/) 7/25/2003
64
-	*
65
-	*	This upgrade provides the following:
66
-	*	+ Version number synced to procedural version number
67
-	*	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
68
-	*	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
69
-	*	+ Kses4 now works in E_STRICT
70
-	*	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
71
-	*	+ Deprecated _hook(), Protocols()
72
-	*	+ Integrated code from kses 0.2.2 into class.
73
-	*
74
-	*	@author     Richard R. V�squez, Jr. (Original procedural code by Ulf H�rnhammar)
75
-	*	@link       http://sourceforge.net/projects/kses/ Home Page for Kses
76
-	*	@link       http://chaos.org/contact/ Contact page with current email address for Richard Vasquez
77
-	*	@copyright  Richard R. V�squez, Jr. 2003-2005
78
-	*	@version    PHP4 OOP 0.2.2
79
-	*	@license    http://www.gnu.org/licenses/gpl.html GNU Public License
80
-	*	@package    kses
81
-	*/
82
-		class kses4
83
-		{
84
-			/**#@+
23
+    /**
24
+     *	Class file for PHP4 OOP version of kses
25
+     *
26
+     *	This is an updated version of kses to work with PHP4 that works under E_STRICT.
27
+     *
28
+     *	This upgrade provides the following:
29
+     *	+ Version number synced to procedural version number
30
+     *	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
31
+     *	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
32
+     *	+ Kses4 now works in E_STRICT
33
+     *	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol() and RemoveProtocols()
34
+     *	+ Deprecated _hook(), Protocols()
35
+     *	+ Integrated code from kses 0.2.2 into class.
36
+     *	+ Added methods DumpProtocols(), DumpMethods()
37
+     *
38
+     *	@package    kses
39
+     *	@subpackage kses4
40
+     */
41
+
42
+    if(substr(phpversion(), 0, 1) < 4)
43
+    {
44
+        die("Class kses requires PHP 4 or higher.");
45
+    }
46
+
47
+    /**
48
+     *	Only install KSES4 once
49
+     */
50
+    if(!defined('KSES_CLASS_PHP4'))
51
+    {
52
+        define('KSES_CLASS_PHP4', true);
53
+
54
+    /**
55
+     *	Kses strips evil scripts!
56
+     *
57
+     *	This class provides the capability for removing unwanted HTML/XHTML, attributes from
58
+     *	tags, and protocols contained in links.  The net result is a much more powerful tool
59
+     *	than the PHP internal strip_tags()
60
+     *
61
+     *	This is a fork of a slick piece of procedural code called 'kses' written by Ulf Harnhammar
62
+     *	The entire set of functions was wrapped in a PHP object with some internal modifications
63
+     *	by Richard Vasquez (http://www.chaos.org/) 7/25/2003
64
+     *
65
+     *	This upgrade provides the following:
66
+     *	+ Version number synced to procedural version number
67
+     *	+ PHPdoc style documentation has been added to the class.  See http://www.phpdoc.org/ for more info.
68
+     *	+ Some methods are now deprecated due to nomenclature style change.  See method documentation for specifics.
69
+     *	+ Kses4 now works in E_STRICT
70
+     *	+ Addition of methods AddProtocols(), filterKsestextHook(), RemoveProtocol(), RemoveProtocols() and SetProtocols()
71
+     *	+ Deprecated _hook(), Protocols()
72
+     *	+ Integrated code from kses 0.2.2 into class.
73
+     *
74
+     *	@author     Richard R. V�squez, Jr. (Original procedural code by Ulf H�rnhammar)
75
+     *	@link       http://sourceforge.net/projects/kses/ Home Page for Kses
76
+     *	@link       http://chaos.org/contact/ Contact page with current email address for Richard Vasquez
77
+     *	@copyright  Richard R. V�squez, Jr. 2003-2005
78
+     *	@version    PHP4 OOP 0.2.2
79
+     *	@license    http://www.gnu.org/licenses/gpl.html GNU Public License
80
+     *	@package    kses
81
+     */
82
+        class kses4
83
+        {
84
+            /**#@+
85 85
 			 *	@access private
86 86
 			 *	@var array
87 87
 			 */
88
-			var $allowed_protocols = array();
89
-			var $allowed_html      = array();
90
-			/**#@-*/
91
-
92
-			/**
93
-			 *	Constructor for kses.
94
-			 *
95
-			 *	This sets a default collection of protocols allowed in links, and creates an
96
-			 *	empty set of allowed HTML tags.
97
-			 *	@since PHP4 OOP 0.0.1
98
-			 */
99
-			function kses4()
100
-			{
101
-				/**
102
-				 *	You could add protocols such as ftp, new, gopher, mailto, irc, etc.
103
-				 *
104
-				 *	The base values the original kses provided were:
105
-				 *		'http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto'
106
-				 */
107
-				$this->allowed_protocols = array('http', 'ftp', 'mailto');
108
-				$this->allowed_html      = array();
109
-			}
110
-
111
-			/**
112
-			 *	Basic task of kses - parses $string and strips it as required.
113
-			 *
114
-			 *	This method strips all the disallowed (X)HTML tags, attributes
115
-			 *	and protocols from the input $string.
116
-			 *
117
-			 *	@access public
118
-			 *	@param string $string String to be stripped of 'evil scripts'
119
-			 *	@return string The stripped string
120
-			 *	@since PHP4 OOP 0.2.1
121
-			 */
122
-			function Parse($string = "")
123
-			{
124
-				if (get_magic_quotes_gpc())
125
-				{
126
-					$string = stripslashes($string);
127
-				}
128
-				$string = $this->_no_null($string);
129
-				$string = $this->_js_entities($string);
130
-				$string = $this->_normalize_entities($string);
131
-				$string = $this->filterKsesTextHook($string);
132
-				return    $this->_split($string);
133
-			}
134
-
135
-			/**
136
-			 *	Allows for single/batch addition of protocols
137
-			 *
138
-			 *	This method accepts one argument that can be either a string
139
-			 *	or an array of strings.  Invalid data will be ignored.
140
-			 *
141
-			 *	The argument will be processed, and each string will be added
142
-			 *	via AddProtocol().
143
-			 *
144
-			 *	@access public
145
-			 *	@param mixed , A string or array of protocols that will be added to the internal list of allowed protocols.
146
-			 *	@return bool Status of adding valid protocols.
147
-			 *	@see AddProtocol()
148
-			 *	@since PHP4 OOP 0.2.1
149
-			 */
150
-			function AddProtocols()
151
-			{
152
-				$c_args = func_num_args();
153
-				if($c_args != 1)
154
-				{
155
-					trigger_error("kses4::AddProtocols() did not receive an argument.", E_USER_WARNING);
156
-					return false;
157
-				}
158
-
159
-				$protocol_data = func_get_arg(0);
160
-
161
-				if(is_array($protocol_data) && count($protocol_data) > 0)
162
-				{
163
-					foreach($protocol_data as $protocol)
164
-					{
165
-						$this->AddProtocol($protocol);
166
-					}
167
-					return true;
168
-				}
169
-				elseif(is_string($protocol_data))
170
-				{
171
-					$this->AddProtocol($protocol_data);
172
-					return true;
173
-				}
174
-				else
175
-				{
176
-					trigger_error("kses4::AddProtocols() did not receive a string or an array.", E_USER_WARNING);
177
-					return false;
178
-				}
179
-			}
180
-
181
-			/**
182
-			 *	Allows for single/batch addition of protocols
183
-			 *
184
-			 *	@deprecated Use AddProtocols()
185
-			 *	@see AddProtocols()
186
-			 *	@return bool
187
-			 *	@since PHP4 OOP 0.0.1
188
-			 */
189
-			function Protocols()
190
-			{
191
-				$c_args = func_num_args();
192
-				if($c_args != 1)
193
-				{
194
-					trigger_error("kses4::Protocols() did not receive an argument.", E_USER_WARNING);
195
-					return false;
196
-				}
197
-
198
-				return $this->AddProtocols(func_get_arg(0));
199
-			}
200
-
201
-			/**
202
-			 *	Adds a single protocol to $this->allowed_protocols.
203
-			 *
204
-			 *	This method accepts a string argument and adds it to
205
-			 *	the list of allowed protocols to keep when performing
206
-			 *	Parse().
207
-			 *
208
-			 *	@access public
209
-			 *	@param string $protocol The name of the protocol to be added.
210
-			 *	@return bool Status of adding valid protocol.
211
-			 *	@since PHP4 OOP 0.0.1
212
-			 */
213
-			function AddProtocol($protocol = "")
214
-			{
215
-				if(!is_string($protocol))
216
-				{
217
-					trigger_error("kses4::AddProtocol() requires a string.", E_USER_WARNING);
218
-					return false;
219
-				}
220
-
221
-				$protocol = strtolower(trim($protocol));
222
-				if($protocol == "")
223
-				{
224
-					trigger_error("kses4::AddProtocol() tried to add an empty/NULL protocol.", E_USER_WARNING);
225
-					return false;
226
-				}
227
-
228
-				// Remove any inadvertent ':' at the end of the protocol.
229
-				if(substr($protocol, strlen($protocol) - 1, 1) == ":")
230
-				{
231
-					$protocol = substr($protocol, 0, strlen($protocol) - 1);
232
-				}
233
-
234
-				if(!in_array($protocol, $this->allowed_protocols))
235
-				{
236
-					array_push($this->allowed_protocols, $protocol);
237
-					sort($this->allowed_protocols);
238
-				}
239
-				return true;
240
-			}
241
-
242
-			/**
243
-			 *	Allows for single/batch replacement of protocols
244
-			 *
245
-			 *	This method accepts one argument that can be either a string
246
-			 *	or an array of strings.  Invalid data will be ignored.
247
-			 *
248
-			 *	Existing protocols will be removed, then the argument will be
249
-			 *	processed, and each string will be added via AddProtocol().
250
-			 *
251
-			 *	@access public
252
-			 *	@param mixed , A string or array of protocols that will be the new internal list of allowed protocols.
253
-			 *	@return bool Status of replacing valid protocols.
254
-			 *	@since PHP4 OOP 0.2.2
255
-			 *	@see AddProtocol()
256
-			 */
257
-			function SetProtocols()
258
-			{
259
-				$c_args = func_num_args();
260
-				if($c_args != 1)
261
-				{
262
-					trigger_error("kses4::SetProtocols() did not receive an argument.", E_USER_WARNING);
263
-					return false;
264
-				}
265
-
266
-				$protocol_data = func_get_arg(0);
267
-
268
-				if(is_array($protocol_data) && count($protocol_data) > 0)
269
-				{
270
-					$this->allowed_protocols = array();
271
-					foreach($protocol_data as $protocol)
272
-					{
273
-						$this->AddProtocol($protocol);
274
-					}
275
-					return true;
276
-				}
277
-				elseif(is_string($protocol_data))
278
-				{
279
-					$this->allowed_protocols = array();
280
-					$this->AddProtocol($protocol_data);
281
-					return true;
282
-				}
283
-				else
284
-				{
285
-					trigger_error("kses4::SetProtocols() did not receive a string or an array.", E_USER_WARNING);
286
-					return false;
287
-				}
288
-			}
289
-
290
-			/**
291
-			 *	Raw dump of allowed protocols
292
-			 *
293
-			 *	This returns an indexed array of allowed protocols for a particular KSES
294
-			 *	instantiation.
295
-			 *
296
-			 *	@access public
297
-			 *	@return array The list of allowed protocols.
298
-			 *	@since PHP4 OOP 0.2.2
299
-			 */
300
-			function DumpProtocols()
301
-			{
302
-				return $this->allowed_protocols;
303
-			}
304
-
305
-			/**
306
-			 *	Raw dump of allowed (X)HTML elements
307
-			 *
308
-			 *	This returns an indexed array of allowed (X)HTML elements and attributes
309
-			 *	for a particular KSES instantiation.
310
-			 *
311
-			 *	@access public
312
-			 *	@return array The list of allowed elements.
313
-			 *	@since PHP4 OOP 0.2.2
314
-			 */
315
-			function DumpElements()
316
-			{
317
-				return $this->allowed_html;
318
-			}
319
-
320
-			/**
321
-			 *	Adds valid (X)HTML with corresponding attributes that will be kept when stripping 'evil scripts'.
322
-			 *
323
-			 *	This method accepts one argument that can be either a string
324
-			 *	or an array of strings.  Invalid data will be ignored.
325
-			 *
326
-			 *	@access public
327
-			 *	@param string $tag (X)HTML tag that will be allowed after stripping text.
328
-			 *	@param array $attribs Associative array of allowed attributes - key => attribute name - value => attribute parameter
329
-			 *	@return bool Status of Adding (X)HTML and attributes.
330
-			 *	@since PHP4 OOP 0.0.1
331
-			 */
332
-			function AddHTML($tag = "", $attribs = array())
333
-			{
334
-				if(!is_string($tag))
335
-				{
336
-					trigger_error("kses4::AddHTML() requires the tag to be a string", E_USER_WARNING);
337
-					return false;
338
-				}
339
-
340
-				$tag = strtolower(trim($tag));
341
-				if($tag == "")
342
-				{
343
-					trigger_error("kses4::AddHTML() tried to add an empty/NULL tag", E_USER_WARNING);
344
-					return false;
345
-				}
346
-
347
-				if(!is_array($attribs))
348
-				{
349
-					trigger_error("kses4::AddHTML() requires an array (even an empty one) of attributes for '$tag'", E_USER_WARNING);
350
-					return false;
351
-				}
352
-
353
-				$new_attribs = array();
354
-				if(is_array($attribs) && count($attribs) > 0)
355
-				{
356
-					foreach($attribs as $idx1 => $val1)
357
-					{
358
-						$new_idx1 = strtolower($idx1);
359
-						$new_val1 = $attribs[$idx1];
360
-
361
-						if(is_array($new_val1) && count($new_val1) > 0)
362
-						{
363
-							$tmp_val = array();
364
-							foreach($new_val1 as $idx2 => $val2)
365
-							{
366
-								$new_idx2 = strtolower($idx2);
367
-								$tmp_val[$new_idx2] = $val2;
368
-							}
369
-							$new_val1 = $tmp_val;
370
-						}
371
-
372
-						$new_attribs[$new_idx1] = $new_val1;
373
-					}
374
-				}
375
-
376
-				$this->allowed_html[$tag] = $new_attribs;
377
-				return true;
378
-			}
379
-
380
-			/**
381
-			 *	Removes a single protocol from $this->allowed_protocols.
382
-			 *
383
-			 *	This method accepts a string argument and removes it from
384
-			 *	the list of allowed protocols to keep when performing
385
-			 *	Parse().
386
-			 *
387
-			 *	@access public
388
-			 *	@param string $protocol The name of the protocol to be removed.
389
-			 *	@return bool Status of removing valid protocol.
390
-			 *	@since PHP4 OOP 0.2.1
391
-			 */
392
-			function RemoveProtocol($protocol = "")
393
-			{
394
-				if(!is_string($protocol))
395
-				{
396
-					trigger_error("kses4::RemoveProtocol() requires a string.", E_USER_WARNING);
397
-					return false;
398
-				}
399
-
400
-				// Remove any inadvertent ':' at the end of the protocol.
401
-				if(substr($protocol, strlen($protocol) - 1, 1) == ":")
402
-				{
403
-					$protocol = substr($protocol, 0, strlen($protocol) - 1);
404
-				}
405
-
406
-				$protocol = strtolower(trim($protocol));
407
-				if($protocol == "")
408
-				{
409
-					trigger_error("kses4::RemoveProtocol() tried to remove an empty/NULL protocol.", E_USER_WARNING);
410
-					return false;
411
-				}
412
-
413
-				//	Ensures that the protocol exists before removing it.
414
-				if(in_array($protocol, $this->allowed_protocols))
415
-				{
416
-					$this->allowed_protocols = array_diff($this->allowed_protocols, array($protocol));
417
-					sort($this->allowed_protocols);
418
-				}
419
-
420
-				return true;
421
-			}
422
-
423
-			/**
424
-			 *	Allows for single/batch removal of protocols
425
-			 *
426
-			 *	This method accepts one argument that can be either a string
427
-			 *	or an array of strings.  Invalid data will be ignored.
428
-			 *
429
-			 *	The argument will be processed, and each string will be removed
430
-			 *	via RemoveProtocol().
431
-			 *
432
-			 *	@access public
433
-			 *	@param mixed , A string or array of protocols that will be removed from the internal list of allowed protocols.
434
-			 *	@return bool Status of removing valid protocols.
435
-			 *	@see RemoveProtocol()
436
-			 *	@since PHP5 OOP 0.2.1
437
-			 */
438
-			function RemoveProtocols()
439
-			{
440
-				$c_args = func_num_args();
441
-				if($c_args != 1)
442
-				{
443
-					return false;
444
-				}
445
-
446
-				$protocol_data = func_get_arg(0);
447
-
448
-				if(is_array($protocol_data) && count($protocol_data) > 0)
449
-				{
450
-					foreach($protocol_data as $protocol)
451
-					{
452
-						$this->RemoveProtocol($protocol);
453
-					}
454
-				}
455
-				elseif(is_string($protocol_data))
456
-				{
457
-					$this->RemoveProtocol($protocol_data);
458
-					return true;
459
-				}
460
-				else
461
-				{
462
-					trigger_error("kses4::RemoveProtocols() did not receive a string or an array.", E_USER_WARNING);
463
-					return false;
464
-				}
465
-			}
466
-
467
-			/**
468
-			 *	This method removes any NULL or characters in $string.
469
-			 *
470
-			 *	@access private
471
-			 *	@param string $string
472
-			 *	@return string String without any NULL/chr(173)
473
-			 *	@since PHP4 OOP 0.0.1
474
-			 */
475
-			function _no_null($string)
476
-			{
477
-				$string = preg_replace('/\0+/', '', $string);
478
-				$string = preg_replace('/(\\\\0)+/', '', $string);
479
-				return $string;
480
-			}
481
-
482
-			/**
483
-			 *	This function removes the HTML JavaScript entities found in early versions of
484
-			 *	Netscape 4.
485
-			 *
486
-			 *	@access private
487
-			 *	@param string $string
488
-			 *	@return string String without any NULL/chr(173)
489
-			 *	@since PHP4 OOP 0.0.1
490
-			 */
491
-			function _js_entities($string)
492
-			{
493
-			  return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
494
-			}
495
-
496
-			/**
497
-			 *	Normalizes HTML entities
498
-			 *
499
-			 *	This function normalizes HTML entities. It will convert "AT&T" to the correct
500
-			 *	"AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
501
-			 *
502
-			 *	@access private
503
-			 *	@param string $string
504
-			 *	@return string String with normalized entities
505
-			 *	@since PHP4 OOP 0.0.1
506
-			 */
507
-			function _normalize_entities($string)
508
-			{
509
-				# Disarm all entities by converting & to &amp;
510
-			  $string = str_replace('&', '&amp;', $string);
511
-
512
-				# Change back the allowed entities in our entity white list
513
-
514
-			  $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string);
515
-			  $string = preg_replace('/&amp;#0*([0-9]{1,5});/e', '\$this->_normalize_entities2("\\1")', $string);
516
-			  $string = preg_replace('/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', '&#\\1\\2;', $string);
517
-
518
-			  return $string;
519
-			}
520
-
521
-			/**
522
-			 *	Helper method used by normalizeEntites()
523
-			 *
524
-			 *	This method helps normalizeEntities() to only accept 16 bit values
525
-			 *	and nothing more for &#number; entities.
526
-			 *
527
-			 *	This method helps normalize_entities() during a preg_replace()
528
-			 *	where a &#(0)*XXXXX; occurs.  The '(0)*XXXXXX' value is converted to
529
-			 *	a number and the result is returned as a numeric entity if the number
530
-			 *	is less than 65536.  Otherwise, the value is returned 'as is'.
531
-			 *
532
-			 *	@access private
533
-			 *	@param string $i
534
-			 *	@return string Normalized numeric entity
535
-			 *	@see _normalize_entities()
536
-			 *	@since PHP4 OOP 0.0.1
537
-			 */
538
-			function _normalize_entities2($i)
539
-			{
540
-			  return (($i > 65535) ? "&amp;#$i;" : "&#$i;");
541
-			}
542
-
543
-			/**
544
-			 *	Allows for additional user defined modifications to text.
545
-			 *
546
-			 *	@deprecated use filterKsesTextHook()
547
-			 *	@param string $string
548
-			 *	@see filterKsesTextHook()
549
-			 *	@return string
550
-			 *	@since PHP4 OOP 0.0.1
551
-			 */
552
-			function _hook($string)
553
-			{
554
-			  return $this->filterKsesTextHook($string);
555
-			}
556
-
557
-			/**
558
-			 *	Allows for additional user defined modifications to text.
559
-			 *
560
-			 *	This method allows for additional modifications to be performed on
561
-			 *	a string that's being run through Parse().  Currently, it returns the
562
-			 *	input string 'as is'.
563
-			 *
564
-			 *	This method is provided for users to extend the kses class for their own
565
-			 *	requirements.
566
-			 *
567
-			 *	@access public
568
-			 *	@param string $string String to perfrom additional modifications on.
569
-			 *	@return string User modified string.
570
-			 *	@see Parse()
571
-			 *	@since PHP5 OOP 1.0.0
572
-			 */
573
-			function filterKsesTextHook($string)
574
-			{
575
-			  return $string;
576
-			}
577
-
578
-			/**
579
-			 *	This method goes through an array, and changes the keys to all lower case.
580
-			 *
581
-			 *	@access private
582
-			 *	@param array $in_array Associative array
583
-			 *	@return array Modified array
584
-			 *	@since PHP4 OOP 0.0.1
585
-			 */
586
-			function _array_lc($inarray)
587
-			{
588
-			  $outarray = array();
589
-
590
-				if(is_array($inarray) && count($inarray) > 0)
591
-				{
592
-					foreach ($inarray as $inkey => $inval)
593
-					{
594
-						$outkey = strtolower($inkey);
595
-						$outarray[$outkey] = array();
596
-
597
-						if(is_array($inval) && count($inval) > 0)
598
-						{
599
-							foreach ($inval as $inkey2 => $inval2)
600
-							{
601
-								$outkey2 = strtolower($inkey2);
602
-								$outarray[$outkey][$outkey2] = $inval2;
603
-							}
604
-						}
605
-					}
606
-				}
607
-
608
-			  return $outarray;
609
-			}
610
-
611
-			/**
612
-			 *	This method searched for HTML tags, no matter how malformed.  It also
613
-			 *	matches stray ">" characters.
614
-			 *
615
-			 *	@access private
616
-			 *	@param string $string
617
-			 *	@return string HTML tags
618
-			 *	@since PHP4 OOP 0.0.1
619
-			 */
620
-			function _split($string)
621
-			{
622
-				return preg_replace(
623
-					'%(<'.   # EITHER: <
624
-					'[^>]*'. # things that aren't >
625
-					'(>|$)'. # > or end of string
626
-					'|>)%e', # OR: just a >
627
-					"\$this->_split2('\\1')",
628
-					$string);
629
-			}
630
-
631
-			/**
632
-			 *	This method strips out disallowed and/or mangled (X)HTML tags along with assigned attributes.
633
-			 *
634
-			 *	This method does a lot of work. It rejects some very malformed things
635
-			 *	like <:::>. It returns an empty string if the element isn't allowed (look
636
-			 *	ma, no strip_tags()!). Otherwise it splits the tag into an element and an
637
-			 *	allowed attribute list.
638
-			 *
639
-			 *	@access private
640
-			 *	@param string $string
641
-			 *	@return string Modified string minus disallowed/mangled (X)HTML and attributes
642
-			 *	@since PHP4 OOP 0.0.1
643
-			 */
644
-			function _split2($string)
645
-			{
646
-				$string = $this->_stripslashes($string);
647
-
648
-				if (substr($string, 0, 1) != '<')
649
-				{
650
-					# It matched a ">" character
651
-					return '&gt;';
652
-				}
653
-
654
-				if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
655
-				{
656
-					# It's seriously malformed
657
-					return '';
658
-				}
659
-
660
-				$slash    = trim($matches[1]);
661
-				$elem     = $matches[2];
662
-				$attrlist = $matches[3];
663
-
664
-				if (
665
-					!isset($this->allowed_html[strtolower($elem)]) ||
666
-					!is_array($this->allowed_html[strtolower($elem)])
667
-				)
668
-				{
669
-					# They are using a not allowed HTML element
670
-					return '';
671
-				}
672
-
673
-				if ($slash != '')
674
-				{
675
-					return "<$slash$elem>";
676
-				}
677
-				# No attributes are allowed for closing elements
678
-
679
-				return $this->_attr("$slash$elem", $attrlist);
680
-			}
681
-
682
-			/**
683
-			 *	This method strips out disallowed attributes for (X)HTML tags.
684
-			 *
685
-			 *	This method removes all attributes if none are allowed for this element.
686
-			 *	If some are allowed it calls $this->_hair() to split them further, and then it
687
-			 *	builds up new HTML code from the data that $this->_hair() returns. It also
688
-			 *	removes "<" and ">" characters, if there are any left. One more thing it
689
-			 *	does is to check if the tag has a closing XHTML slash, and if it does,
690
-			 *	it puts one in the returned code as well.
691
-			 *
692
-			 *	@access private
693
-			 *	@param string $element (X)HTML tag to check
694
-			 *	@param string $attr Text containing attributes to check for validity.
695
-			 *	@return string Resulting valid (X)HTML or ''
696
-			 *	@see _hair()
697
-			 *	@since PHP4 OOP 0.0.1
698
-			 */
699
-			function _attr($element, $attr)
700
-			{
701
-				# Is there a closing XHTML slash at the end of the attributes?
702
-				$xhtml_slash = '';
703
-				if (preg_match('%\s/\s*$%', $attr))
704
-				{
705
-					$xhtml_slash = ' /';
706
-				}
707
-
708
-				# Are any attributes allowed at all for this element?
709
-				if (
710
-					!isset($this->allowed_html[strtolower($element)]) ||
711
-					count($this->allowed_html[strtolower($element)]) == 0
712
-				)
713
-				{
714
-					return "<$element$xhtml_slash>";
715
-				}
716
-
717
-				# Split it
718
-				$attrarr = $this->_hair($attr);
719
-
720
-				# Go through $attrarr, and save the allowed attributes for this element
721
-				# in $attr2
722
-				$attr2 = '';
723
-				if(is_array($attrarr) && count($attrarr) > 0)
724
-				{
725
-					foreach ($attrarr as $arreach)
726
-					{
727
-						if(!isset($this->allowed_html[strtolower($element)][strtolower($arreach['name'])]))
728
-						{
729
-							continue;
730
-						}
731
-
732
-						$current = $this->allowed_html[strtolower($element)][strtolower($arreach['name'])];
733
-						if ($current == '')
734
-						{
735
-							# the attribute is not allowed
736
-							continue;
737
-						}
738
-
739
-						if (!is_array($current))
740
-						{
741
-							# there are no checks
742
-							$attr2 .= ' '.$arreach['whole'];
743
-						}
744
-						else
745
-						{
746
-							# there are some checks
747
-							$ok = true;
748
-							if(is_array($current) && count($current) > 0)
749
-							{
750
-								foreach ($current as $currkey => $currval)
751
-								{
752
-									if (!$this->_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval))
753
-									{
754
-										$ok = false;
755
-										break;
756
-									}
757
-								}
758
-
759
-								if ($ok)
760
-								{
761
-									# it passed them
762
-									$attr2 .= ' '.$arreach['whole'];
763
-								}
764
-							}
765
-						}
766
-					}
767
-				}
768
-
769
-				# Remove any "<" or ">" characters
770
-				$attr2 = preg_replace('/[<>]/', '', $attr2);
771
-				return "<$element$attr2$xhtml_slash>";
772
-			}
773
-
774
-			/**
775
-			 *	This method combs through an attribute list string and returns an associative array of attributes and values.
776
-			 *
777
-			 *	This method does a lot of work. It parses an attribute list into an array
778
-			 *	with attribute data, and tries to do the right thing even if it gets weird
779
-			 *	input. It will add quotes around attribute values that don't have any quotes
780
-			 *	or apostrophes around them, to make it easier to produce HTML code that will
781
-			 *	conform to W3C's HTML specification. It will also remove bad URL protocols
782
-			 *	from attribute values.
783
-			 *
784
-			 *	@access private
785
-			 *	@param string $attr Text containing tag attributes for parsing
786
-			 *	@return array Associative array containing data on attribute and value
787
-			 *	@since PHP4 OOP 0.0.1
788
-			 */
789
-			function _hair($attr)
790
-			{
791
-				$attrarr  = array();
792
-				$mode     = 0;
793
-				$attrname = '';
794
-
795
-				# Loop through the whole attribute list
796
-
797
-				while (strlen($attr) != 0)
798
-				{
799
-					# Was the last operation successful?
800
-					$working = 0;
801
-
802
-					switch ($mode)
803
-					{
804
-						case 0:	# attribute name, href for instance
805
-							if (preg_match('/^([-a-zA-Z]+)/', $attr, $match))
806
-							{
807
-								$attrname = $match[1];
808
-								$working = $mode = 1;
809
-								$attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
810
-							}
811
-							break;
812
-						case 1:	# equals sign or valueless ("selected")
813
-							if (preg_match('/^\s*=\s*/', $attr)) # equals sign
814
-							{
815
-								$working = 1;
816
-								$mode    = 2;
817
-								$attr    = preg_replace('/^\s*=\s*/', '', $attr);
818
-								break;
819
-							}
820
-							if (preg_match('/^\s+/', $attr)) # valueless
821
-							{
822
-								$working   = 1;
823
-								$mode      = 0;
824
-								$attrarr[] = array(
825
-									'name'  => $attrname,
826
-									'value' => '',
827
-									'whole' => $attrname,
828
-									'vless' => 'y'
829
-								);
830
-								$attr      = preg_replace('/^\s+/', '', $attr);
831
-							}
832
-							break;
833
-						case 2: # attribute value, a URL after href= for instance
834
-							if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value"
835
-							{
836
-								$thisval   = $this->_bad_protocol($match[1]);
837
-								$attrarr[] = array(
838
-									'name'  => $attrname,
839
-									'value' => $thisval,
840
-									'whole' => "$attrname=\"$thisval\"",
841
-									'vless' => 'n'
842
-								);
843
-								$working   = 1;
844
-								$mode      = 0;
845
-								$attr      = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
846
-								break;
847
-							}
848
-							if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value'
849
-							{
850
-								$thisval   = $this->_bad_protocol($match[1]);
851
-								$attrarr[] = array(
852
-									'name'  => $attrname,
853
-									'value' => $thisval,
854
-									'whole' => "$attrname='$thisval'",
855
-									'vless' => 'n'
856
-								);
857
-								$working   = 1;
858
-								$mode      = 0;
859
-								$attr      = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
860
-								break;
861
-							}
862
-							if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value
863
-							{
864
-								$thisval   = $this->_bad_protocol($match[1]);
865
-								$attrarr[] = array(
866
-									'name'  => $attrname,
867
-									'value' => $thisval,
868
-									'whole' => "$attrname=\"$thisval\"",
869
-									'vless' => 'n'
870
-								);
871
-								# We add quotes to conform to W3C's HTML spec.
872
-								$working   = 1;
873
-								$mode      = 0;
874
-								$attr      = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
875
-							}
876
-							break;
877
-					}
878
-
879
-					if ($working == 0) # not well formed, remove and try again
880
-					{
881
-						$attr = $this->_html_error($attr);
882
-						$mode = 0;
883
-					}
884
-				}
885
-
886
-				# special case, for when the attribute list ends with a valueless
887
-				# attribute like "selected"
888
-				if ($mode == 1)
889
-				{
890
-					$attrarr[] = array(
891
-						'name'  => $attrname,
892
-						'value' => '',
893
-						'whole' => $attrname,
894
-						'vless' => 'y'
895
-					);
896
-				}
897
-
898
-				return $attrarr;
899
-			}
900
-
901
-			/**
902
-			 *	This method removes disallowed protocols.
903
-			 *
904
-			 *	This method removes all non-allowed protocols from the beginning of
905
-			 *	$string. It ignores whitespace and the case of the letters, and it does
906
-			 *	understand HTML entities. It does its work in a while loop, so it won't be
907
-			 *	fooled by a string like "javascript:javascript:alert(57)".
908
-			 *
909
-			 *	@access private
910
-			 *	@param string $string String to check for protocols
911
-			 *	@return string String with removed protocols
912
-			 *	@since PHP4 OOP 0.0.1
913
-			 */
914
-			function _bad_protocol($string)
915
-			{
916
-				$string  = $this->_no_null($string);
917
-				$string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
918
-				$string2 = $string.'a';
919
-
920
-				while ($string != $string2)
921
-				{
922
-					$string2 = $string;
923
-					$string  = $this->_bad_protocol_once($string);
924
-				} # while
925
-
926
-				return $string;
927
-			}
928
-
929
-			/**
930
-			 *	Helper method used by _bad_protocol()
931
-			 *
932
-			 *	This function searches for URL protocols at the beginning of $string, while
933
-			 *	handling whitespace and HTML entities.
934
-			 *  Function updated to fix security vulnerability (see http://projects.dokeos.com/index.php?do=details&task_id=2312)
935
-			 *
936
-			 *	@access private
937
-			 *	@param string $string String to check for protocols
938
-			 *	@return string String with removed protocols
939
-			 *	@see _bad_protocol()
940
-			 *	@since PHP4 OOP 0.0.1
941
-			 */
942
-			function _bad_protocol_once($string)
943
-			{
944
-				$string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
945
-				if(isset($string2[1]) && !preg_match('%/\?%',$string2[0]))
946
-				{
947
-					$string = $this->_bad_protocol_once2($string2[0]).trim($string2[1]);
948
-				}
949
-				return $string;
950
-			}
951
-			/**
952
-			 *	Helper method used by _bad_protocol_once() regex
953
-			 *
954
-			 *	This function processes URL protocols, checks to see if they're in the white-
955
-			 *	list or not, and returns different data depending on the answer.
956
-			 *
957
-			 *	@access private
958
-			 *	@param string $string String to check for protocols
959
-			 *	@return string String with removed protocols
960
-			 *	@see _bad_protocol()
961
-			 *	@see _bad_protocol_once()
962
-			 *	@since PHP4 OOP 0.0.1
963
-			 */
964
-			function _bad_protocol_once2($string)
965
-			{
966
-				$string = $this->_decode_entities($string);
967
-				$string = preg_replace('/\s/', '', $string);
968
-				$string = $this->_no_null($string);
969
-				$string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
970
-				$string = strtolower($string);
971
-
972
-				$allowed = false;
973
-				if(is_array($this->allowed_protocols) && count($this->allowed_protocols) > 0)
974
-				{
975
-					foreach ($this->allowed_protocols as $one_protocol)
976
-					{
977
-						if (strtolower($one_protocol) == $string)
978
-						{
979
-							$allowed = true;
980
-							break;
981
-						}
982
-					}
983
-				}
984
-
985
-				if ($allowed)
986
-				{
987
-					return "$string:";
988
-				}
989
-				else
990
-				{
991
-					return '';
992
-				}
993
-			}
994
-
995
-			/**
996
-			 *	This function performs different checks for attribute values.
997
-			 *
998
-			 *	The currently implemented checks are "maxlen", "minlen", "maxval",
999
-			 *	"minval" and "valueless" with even more checks to come soon.
1000
-			 *
1001
-			 *	@access private
1002
-			 *	@param string $value The value of the attribute to be checked.
1003
-			 *	@param string $vless Indicates whether the the value is supposed to be valueless
1004
-			 *	@param string $checkname The check to be performed
1005
-			 *	@param string $checkvalue The value that is to be checked against
1006
-			 *	@return bool Indicates whether the check passed or not
1007
-			 *	@since PHP4 OOP 0.0.1
1008
-			 */
1009
-			function _check_attr_val($value, $vless, $checkname, $checkvalue)
1010
-			{
1011
-				$ok = true;
1012
-
1013
-				switch (strtolower($checkname))
1014
-				{
1015
-					/**
1016
-					*	The maxlen check makes sure that the attribute value has a length not
1017
-					*	greater than the given value. This can be used to avoid Buffer Overflows
1018
-					*	in WWW clients and various Internet servers.
1019
-					*/
1020
-					case 'maxlen':
1021
-						if (strlen($value) > $checkvalue)
1022
-						{
1023
-							$ok = false;
1024
-						}
1025
-						break;
1026
-
1027
-					/**
1028
-					*	The minlen check makes sure that the attribute value has a length not
1029
-					*	smaller than the given value.
1030
-					*/
1031
-					case 'minlen':
1032
-						if (strlen($value) < $checkvalue)
1033
-						{
1034
-							$ok = false;
1035
-						}
1036
-						break;
1037
-
1038
-					/**
1039
-					*	The maxval check does two things: it checks that the attribute value is
1040
-					*	an integer from 0 and up, without an excessive amount of zeroes or
1041
-					*	whitespace (to avoid Buffer Overflows). It also checks that the attribute
1042
-					*	value is not greater than the given value.
1043
-					*	This check can be used to avoid Denial of Service attacks.
1044
-					*/
1045
-					case 'maxval':
1046
-						if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1047
-						{
1048
-							$ok = false;
1049
-						}
1050
-						if ($value > $checkvalue)
1051
-						{
1052
-							$ok = false;
1053
-						}
1054
-						break;
1055
-
1056
-					/**
1057
-					*	The minval check checks that the attribute value is a positive integer,
1058
-					*	and that it is not smaller than the given value.
1059
-					*/
1060
-					case 'minval':
1061
-						if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1062
-						{
1063
-							$ok = false;
1064
-						}
1065
-						if ($value < $checkvalue)
1066
-						{
1067
-							$ok = false;
1068
-						}
1069
-						break;
1070
-
1071
-					/**
1072
-					*	The valueless check checks if the attribute has a value
1073
-					*	(like <a href="blah">) or not (<option selected>). If the given value
1074
-					*	is a "y" or a "Y", the attribute must not have a value.
1075
-					*	If the given value is an "n" or an "N", the attribute must have one.
1076
-					*/
1077
-					case 'valueless':
1078
-					if (strtolower($checkvalue) != $vless)
1079
-					{
1080
-						$ok = false;
1081
-					}
1082
-					break;
1083
-
1084
-				}
1085
-
1086
-				return $ok;
1087
-			}
1088
-
1089
-			/**
1090
-			 *	Changes \" to "
1091
-			 *
1092
-			 *	This function changes the character sequence  \"  to just  "
1093
-			 *	It leaves all other slashes alone. It's really weird, but the quoting from
1094
-			 *	preg_replace(//e) seems to require this.
1095
-			 *
1096
-			 *	@access private
1097
-			 *	@param string $string The string to be stripped.
1098
-			 *	@return string string stripped of \"
1099
-			 *	@since PHP4 OOP 0.0.1
1100
-			 */
1101
-			function _stripslashes($string)
1102
-			{
1103
-				return preg_replace('%\\\\"%', '"', $string);
1104
-			}
1105
-
1106
-			/**
1107
-			 *	helper method for _hair()
1108
-			 *
1109
-			 *	This function deals with parsing errors in _hair(). The general plan is
1110
-			 *	to remove everything to and including some whitespace, but it deals with
1111
-			 *	quotes and apostrophes as well.
1112
-			 *
1113
-			 *	@access private
1114
-			 *	@param string $string The string to be stripped.
1115
-			 *	@return string string stripped of whitespace
1116
-			 *	@see _hair()
1117
-			 *	@since PHP4 OOP 0.0.1
1118
-			 */
1119
-			function _html_error($string)
1120
-			{
1121
-				return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
1122
-			}
1123
-
1124
-			/**
1125
-			 *	Decodes numeric HTML entities
1126
-			 *
1127
-			 *	This method decodes numeric HTML entities (&#65; and &#x41;). It doesn't
1128
-			 *	do anything with other entities like &auml;, but we don't need them in the
1129
-			 *	URL protocol white listing system anyway.
1130
-			 *
1131
-			 *	@access private
1132
-			 *	@param string $value The entitiy to be decoded.
1133
-			 *	@return string Decoded entity
1134
-			 *	@since PHP4 OOP 0.0.1
1135
-			 */
1136
-			function _decode_entities($string)
1137
-			{
1138
-				$string = preg_replace('/&#([0-9]+);/e', 'chr("\\1")', $string);
1139
-				$string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', 'chr(hexdec("\\1"))', $string);
1140
-				return $string;
1141
-			}
1142
-
1143
-			/**
1144
-			 *	Returns PHP4 OOP version # of kses.
1145
-			 *
1146
-			 *	Since this class has been refactored and documented and proven to work,
1147
-			 *	I'm syncing the version number to procedural kses.
1148
-			 *
1149
-			 *	@access public
1150
-			 *	@return string Version number
1151
-			 *	@since PHP4 OOP 0.0.1
1152
-			 */
1153
-			function _version()
1154
-			{
1155
-				return 'PHP4 0.2.2 (OOP fork of procedural kses 0.2.2)';
1156
-			}
1157
-		}
1158
-
1159
-
1160
-
1161
-	}
88
+            var $allowed_protocols = array();
89
+            var $allowed_html      = array();
90
+            /**#@-*/
91
+
92
+            /**
93
+             *	Constructor for kses.
94
+             *
95
+             *	This sets a default collection of protocols allowed in links, and creates an
96
+             *	empty set of allowed HTML tags.
97
+             *	@since PHP4 OOP 0.0.1
98
+             */
99
+            function kses4()
100
+            {
101
+                /**
102
+                 *	You could add protocols such as ftp, new, gopher, mailto, irc, etc.
103
+                 *
104
+                 *	The base values the original kses provided were:
105
+                 *		'http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto'
106
+                 */
107
+                $this->allowed_protocols = array('http', 'ftp', 'mailto');
108
+                $this->allowed_html      = array();
109
+            }
110
+
111
+            /**
112
+             *	Basic task of kses - parses $string and strips it as required.
113
+             *
114
+             *	This method strips all the disallowed (X)HTML tags, attributes
115
+             *	and protocols from the input $string.
116
+             *
117
+             *	@access public
118
+             *	@param string $string String to be stripped of 'evil scripts'
119
+             *	@return string The stripped string
120
+             *	@since PHP4 OOP 0.2.1
121
+             */
122
+            function Parse($string = "")
123
+            {
124
+                if (get_magic_quotes_gpc())
125
+                {
126
+                    $string = stripslashes($string);
127
+                }
128
+                $string = $this->_no_null($string);
129
+                $string = $this->_js_entities($string);
130
+                $string = $this->_normalize_entities($string);
131
+                $string = $this->filterKsesTextHook($string);
132
+                return    $this->_split($string);
133
+            }
134
+
135
+            /**
136
+             *	Allows for single/batch addition of protocols
137
+             *
138
+             *	This method accepts one argument that can be either a string
139
+             *	or an array of strings.  Invalid data will be ignored.
140
+             *
141
+             *	The argument will be processed, and each string will be added
142
+             *	via AddProtocol().
143
+             *
144
+             *	@access public
145
+             *	@param mixed , A string or array of protocols that will be added to the internal list of allowed protocols.
146
+             *	@return bool Status of adding valid protocols.
147
+             *	@see AddProtocol()
148
+             *	@since PHP4 OOP 0.2.1
149
+             */
150
+            function AddProtocols()
151
+            {
152
+                $c_args = func_num_args();
153
+                if($c_args != 1)
154
+                {
155
+                    trigger_error("kses4::AddProtocols() did not receive an argument.", E_USER_WARNING);
156
+                    return false;
157
+                }
158
+
159
+                $protocol_data = func_get_arg(0);
160
+
161
+                if(is_array($protocol_data) && count($protocol_data) > 0)
162
+                {
163
+                    foreach($protocol_data as $protocol)
164
+                    {
165
+                        $this->AddProtocol($protocol);
166
+                    }
167
+                    return true;
168
+                }
169
+                elseif(is_string($protocol_data))
170
+                {
171
+                    $this->AddProtocol($protocol_data);
172
+                    return true;
173
+                }
174
+                else
175
+                {
176
+                    trigger_error("kses4::AddProtocols() did not receive a string or an array.", E_USER_WARNING);
177
+                    return false;
178
+                }
179
+            }
180
+
181
+            /**
182
+             *	Allows for single/batch addition of protocols
183
+             *
184
+             *	@deprecated Use AddProtocols()
185
+             *	@see AddProtocols()
186
+             *	@return bool
187
+             *	@since PHP4 OOP 0.0.1
188
+             */
189
+            function Protocols()
190
+            {
191
+                $c_args = func_num_args();
192
+                if($c_args != 1)
193
+                {
194
+                    trigger_error("kses4::Protocols() did not receive an argument.", E_USER_WARNING);
195
+                    return false;
196
+                }
197
+
198
+                return $this->AddProtocols(func_get_arg(0));
199
+            }
200
+
201
+            /**
202
+             *	Adds a single protocol to $this->allowed_protocols.
203
+             *
204
+             *	This method accepts a string argument and adds it to
205
+             *	the list of allowed protocols to keep when performing
206
+             *	Parse().
207
+             *
208
+             *	@access public
209
+             *	@param string $protocol The name of the protocol to be added.
210
+             *	@return bool Status of adding valid protocol.
211
+             *	@since PHP4 OOP 0.0.1
212
+             */
213
+            function AddProtocol($protocol = "")
214
+            {
215
+                if(!is_string($protocol))
216
+                {
217
+                    trigger_error("kses4::AddProtocol() requires a string.", E_USER_WARNING);
218
+                    return false;
219
+                }
220
+
221
+                $protocol = strtolower(trim($protocol));
222
+                if($protocol == "")
223
+                {
224
+                    trigger_error("kses4::AddProtocol() tried to add an empty/NULL protocol.", E_USER_WARNING);
225
+                    return false;
226
+                }
227
+
228
+                // Remove any inadvertent ':' at the end of the protocol.
229
+                if(substr($protocol, strlen($protocol) - 1, 1) == ":")
230
+                {
231
+                    $protocol = substr($protocol, 0, strlen($protocol) - 1);
232
+                }
233
+
234
+                if(!in_array($protocol, $this->allowed_protocols))
235
+                {
236
+                    array_push($this->allowed_protocols, $protocol);
237
+                    sort($this->allowed_protocols);
238
+                }
239
+                return true;
240
+            }
241
+
242
+            /**
243
+             *	Allows for single/batch replacement of protocols
244
+             *
245
+             *	This method accepts one argument that can be either a string
246
+             *	or an array of strings.  Invalid data will be ignored.
247
+             *
248
+             *	Existing protocols will be removed, then the argument will be
249
+             *	processed, and each string will be added via AddProtocol().
250
+             *
251
+             *	@access public
252
+             *	@param mixed , A string or array of protocols that will be the new internal list of allowed protocols.
253
+             *	@return bool Status of replacing valid protocols.
254
+             *	@since PHP4 OOP 0.2.2
255
+             *	@see AddProtocol()
256
+             */
257
+            function SetProtocols()
258
+            {
259
+                $c_args = func_num_args();
260
+                if($c_args != 1)
261
+                {
262
+                    trigger_error("kses4::SetProtocols() did not receive an argument.", E_USER_WARNING);
263
+                    return false;
264
+                }
265
+
266
+                $protocol_data = func_get_arg(0);
267
+
268
+                if(is_array($protocol_data) && count($protocol_data) > 0)
269
+                {
270
+                    $this->allowed_protocols = array();
271
+                    foreach($protocol_data as $protocol)
272
+                    {
273
+                        $this->AddProtocol($protocol);
274
+                    }
275
+                    return true;
276
+                }
277
+                elseif(is_string($protocol_data))
278
+                {
279
+                    $this->allowed_protocols = array();
280
+                    $this->AddProtocol($protocol_data);
281
+                    return true;
282
+                }
283
+                else
284
+                {
285
+                    trigger_error("kses4::SetProtocols() did not receive a string or an array.", E_USER_WARNING);
286
+                    return false;
287
+                }
288
+            }
289
+
290
+            /**
291
+             *	Raw dump of allowed protocols
292
+             *
293
+             *	This returns an indexed array of allowed protocols for a particular KSES
294
+             *	instantiation.
295
+             *
296
+             *	@access public
297
+             *	@return array The list of allowed protocols.
298
+             *	@since PHP4 OOP 0.2.2
299
+             */
300
+            function DumpProtocols()
301
+            {
302
+                return $this->allowed_protocols;
303
+            }
304
+
305
+            /**
306
+             *	Raw dump of allowed (X)HTML elements
307
+             *
308
+             *	This returns an indexed array of allowed (X)HTML elements and attributes
309
+             *	for a particular KSES instantiation.
310
+             *
311
+             *	@access public
312
+             *	@return array The list of allowed elements.
313
+             *	@since PHP4 OOP 0.2.2
314
+             */
315
+            function DumpElements()
316
+            {
317
+                return $this->allowed_html;
318
+            }
319
+
320
+            /**
321
+             *	Adds valid (X)HTML with corresponding attributes that will be kept when stripping 'evil scripts'.
322
+             *
323
+             *	This method accepts one argument that can be either a string
324
+             *	or an array of strings.  Invalid data will be ignored.
325
+             *
326
+             *	@access public
327
+             *	@param string $tag (X)HTML tag that will be allowed after stripping text.
328
+             *	@param array $attribs Associative array of allowed attributes - key => attribute name - value => attribute parameter
329
+             *	@return bool Status of Adding (X)HTML and attributes.
330
+             *	@since PHP4 OOP 0.0.1
331
+             */
332
+            function AddHTML($tag = "", $attribs = array())
333
+            {
334
+                if(!is_string($tag))
335
+                {
336
+                    trigger_error("kses4::AddHTML() requires the tag to be a string", E_USER_WARNING);
337
+                    return false;
338
+                }
339
+
340
+                $tag = strtolower(trim($tag));
341
+                if($tag == "")
342
+                {
343
+                    trigger_error("kses4::AddHTML() tried to add an empty/NULL tag", E_USER_WARNING);
344
+                    return false;
345
+                }
346
+
347
+                if(!is_array($attribs))
348
+                {
349
+                    trigger_error("kses4::AddHTML() requires an array (even an empty one) of attributes for '$tag'", E_USER_WARNING);
350
+                    return false;
351
+                }
352
+
353
+                $new_attribs = array();
354
+                if(is_array($attribs) && count($attribs) > 0)
355
+                {
356
+                    foreach($attribs as $idx1 => $val1)
357
+                    {
358
+                        $new_idx1 = strtolower($idx1);
359
+                        $new_val1 = $attribs[$idx1];
360
+
361
+                        if(is_array($new_val1) && count($new_val1) > 0)
362
+                        {
363
+                            $tmp_val = array();
364
+                            foreach($new_val1 as $idx2 => $val2)
365
+                            {
366
+                                $new_idx2 = strtolower($idx2);
367
+                                $tmp_val[$new_idx2] = $val2;
368
+                            }
369
+                            $new_val1 = $tmp_val;
370
+                        }
371
+
372
+                        $new_attribs[$new_idx1] = $new_val1;
373
+                    }
374
+                }
375
+
376
+                $this->allowed_html[$tag] = $new_attribs;
377
+                return true;
378
+            }
379
+
380
+            /**
381
+             *	Removes a single protocol from $this->allowed_protocols.
382
+             *
383
+             *	This method accepts a string argument and removes it from
384
+             *	the list of allowed protocols to keep when performing
385
+             *	Parse().
386
+             *
387
+             *	@access public
388
+             *	@param string $protocol The name of the protocol to be removed.
389
+             *	@return bool Status of removing valid protocol.
390
+             *	@since PHP4 OOP 0.2.1
391
+             */
392
+            function RemoveProtocol($protocol = "")
393
+            {
394
+                if(!is_string($protocol))
395
+                {
396
+                    trigger_error("kses4::RemoveProtocol() requires a string.", E_USER_WARNING);
397
+                    return false;
398
+                }
399
+
400
+                // Remove any inadvertent ':' at the end of the protocol.
401
+                if(substr($protocol, strlen($protocol) - 1, 1) == ":")
402
+                {
403
+                    $protocol = substr($protocol, 0, strlen($protocol) - 1);
404
+                }
405
+
406
+                $protocol = strtolower(trim($protocol));
407
+                if($protocol == "")
408
+                {
409
+                    trigger_error("kses4::RemoveProtocol() tried to remove an empty/NULL protocol.", E_USER_WARNING);
410
+                    return false;
411
+                }
412
+
413
+                //	Ensures that the protocol exists before removing it.
414
+                if(in_array($protocol, $this->allowed_protocols))
415
+                {
416
+                    $this->allowed_protocols = array_diff($this->allowed_protocols, array($protocol));
417
+                    sort($this->allowed_protocols);
418
+                }
419
+
420
+                return true;
421
+            }
422
+
423
+            /**
424
+             *	Allows for single/batch removal of protocols
425
+             *
426
+             *	This method accepts one argument that can be either a string
427
+             *	or an array of strings.  Invalid data will be ignored.
428
+             *
429
+             *	The argument will be processed, and each string will be removed
430
+             *	via RemoveProtocol().
431
+             *
432
+             *	@access public
433
+             *	@param mixed , A string or array of protocols that will be removed from the internal list of allowed protocols.
434
+             *	@return bool Status of removing valid protocols.
435
+             *	@see RemoveProtocol()
436
+             *	@since PHP5 OOP 0.2.1
437
+             */
438
+            function RemoveProtocols()
439
+            {
440
+                $c_args = func_num_args();
441
+                if($c_args != 1)
442
+                {
443
+                    return false;
444
+                }
445
+
446
+                $protocol_data = func_get_arg(0);
447
+
448
+                if(is_array($protocol_data) && count($protocol_data) > 0)
449
+                {
450
+                    foreach($protocol_data as $protocol)
451
+                    {
452
+                        $this->RemoveProtocol($protocol);
453
+                    }
454
+                }
455
+                elseif(is_string($protocol_data))
456
+                {
457
+                    $this->RemoveProtocol($protocol_data);
458
+                    return true;
459
+                }
460
+                else
461
+                {
462
+                    trigger_error("kses4::RemoveProtocols() did not receive a string or an array.", E_USER_WARNING);
463
+                    return false;
464
+                }
465
+            }
466
+
467
+            /**
468
+             *	This method removes any NULL or characters in $string.
469
+             *
470
+             *	@access private
471
+             *	@param string $string
472
+             *	@return string String without any NULL/chr(173)
473
+             *	@since PHP4 OOP 0.0.1
474
+             */
475
+            function _no_null($string)
476
+            {
477
+                $string = preg_replace('/\0+/', '', $string);
478
+                $string = preg_replace('/(\\\\0)+/', '', $string);
479
+                return $string;
480
+            }
481
+
482
+            /**
483
+             *	This function removes the HTML JavaScript entities found in early versions of
484
+             *	Netscape 4.
485
+             *
486
+             *	@access private
487
+             *	@param string $string
488
+             *	@return string String without any NULL/chr(173)
489
+             *	@since PHP4 OOP 0.0.1
490
+             */
491
+            function _js_entities($string)
492
+            {
493
+                return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
494
+            }
495
+
496
+            /**
497
+             *	Normalizes HTML entities
498
+             *
499
+             *	This function normalizes HTML entities. It will convert "AT&T" to the correct
500
+             *	"AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
501
+             *
502
+             *	@access private
503
+             *	@param string $string
504
+             *	@return string String with normalized entities
505
+             *	@since PHP4 OOP 0.0.1
506
+             */
507
+            function _normalize_entities($string)
508
+            {
509
+                # Disarm all entities by converting & to &amp;
510
+                $string = str_replace('&', '&amp;', $string);
511
+
512
+                # Change back the allowed entities in our entity white list
513
+
514
+                $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string);
515
+                $string = preg_replace('/&amp;#0*([0-9]{1,5});/e', '\$this->_normalize_entities2("\\1")', $string);
516
+                $string = preg_replace('/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', '&#\\1\\2;', $string);
517
+
518
+                return $string;
519
+            }
520
+
521
+            /**
522
+             *	Helper method used by normalizeEntites()
523
+             *
524
+             *	This method helps normalizeEntities() to only accept 16 bit values
525
+             *	and nothing more for &#number; entities.
526
+             *
527
+             *	This method helps normalize_entities() during a preg_replace()
528
+             *	where a &#(0)*XXXXX; occurs.  The '(0)*XXXXXX' value is converted to
529
+             *	a number and the result is returned as a numeric entity if the number
530
+             *	is less than 65536.  Otherwise, the value is returned 'as is'.
531
+             *
532
+             *	@access private
533
+             *	@param string $i
534
+             *	@return string Normalized numeric entity
535
+             *	@see _normalize_entities()
536
+             *	@since PHP4 OOP 0.0.1
537
+             */
538
+            function _normalize_entities2($i)
539
+            {
540
+                return (($i > 65535) ? "&amp;#$i;" : "&#$i;");
541
+            }
542
+
543
+            /**
544
+             *	Allows for additional user defined modifications to text.
545
+             *
546
+             *	@deprecated use filterKsesTextHook()
547
+             *	@param string $string
548
+             *	@see filterKsesTextHook()
549
+             *	@return string
550
+             *	@since PHP4 OOP 0.0.1
551
+             */
552
+            function _hook($string)
553
+            {
554
+                return $this->filterKsesTextHook($string);
555
+            }
556
+
557
+            /**
558
+             *	Allows for additional user defined modifications to text.
559
+             *
560
+             *	This method allows for additional modifications to be performed on
561
+             *	a string that's being run through Parse().  Currently, it returns the
562
+             *	input string 'as is'.
563
+             *
564
+             *	This method is provided for users to extend the kses class for their own
565
+             *	requirements.
566
+             *
567
+             *	@access public
568
+             *	@param string $string String to perfrom additional modifications on.
569
+             *	@return string User modified string.
570
+             *	@see Parse()
571
+             *	@since PHP5 OOP 1.0.0
572
+             */
573
+            function filterKsesTextHook($string)
574
+            {
575
+                return $string;
576
+            }
577
+
578
+            /**
579
+             *	This method goes through an array, and changes the keys to all lower case.
580
+             *
581
+             *	@access private
582
+             *	@param array $in_array Associative array
583
+             *	@return array Modified array
584
+             *	@since PHP4 OOP 0.0.1
585
+             */
586
+            function _array_lc($inarray)
587
+            {
588
+                $outarray = array();
589
+
590
+                if(is_array($inarray) && count($inarray) > 0)
591
+                {
592
+                    foreach ($inarray as $inkey => $inval)
593
+                    {
594
+                        $outkey = strtolower($inkey);
595
+                        $outarray[$outkey] = array();
596
+
597
+                        if(is_array($inval) && count($inval) > 0)
598
+                        {
599
+                            foreach ($inval as $inkey2 => $inval2)
600
+                            {
601
+                                $outkey2 = strtolower($inkey2);
602
+                                $outarray[$outkey][$outkey2] = $inval2;
603
+                            }
604
+                        }
605
+                    }
606
+                }
607
+
608
+                return $outarray;
609
+            }
610
+
611
+            /**
612
+             *	This method searched for HTML tags, no matter how malformed.  It also
613
+             *	matches stray ">" characters.
614
+             *
615
+             *	@access private
616
+             *	@param string $string
617
+             *	@return string HTML tags
618
+             *	@since PHP4 OOP 0.0.1
619
+             */
620
+            function _split($string)
621
+            {
622
+                return preg_replace(
623
+                    '%(<'.   # EITHER: <
624
+                    '[^>]*'. # things that aren't >
625
+                    '(>|$)'. # > or end of string
626
+                    '|>)%e', # OR: just a >
627
+                    "\$this->_split2('\\1')",
628
+                    $string);
629
+            }
630
+
631
+            /**
632
+             *	This method strips out disallowed and/or mangled (X)HTML tags along with assigned attributes.
633
+             *
634
+             *	This method does a lot of work. It rejects some very malformed things
635
+             *	like <:::>. It returns an empty string if the element isn't allowed (look
636
+             *	ma, no strip_tags()!). Otherwise it splits the tag into an element and an
637
+             *	allowed attribute list.
638
+             *
639
+             *	@access private
640
+             *	@param string $string
641
+             *	@return string Modified string minus disallowed/mangled (X)HTML and attributes
642
+             *	@since PHP4 OOP 0.0.1
643
+             */
644
+            function _split2($string)
645
+            {
646
+                $string = $this->_stripslashes($string);
647
+
648
+                if (substr($string, 0, 1) != '<')
649
+                {
650
+                    # It matched a ">" character
651
+                    return '&gt;';
652
+                }
653
+
654
+                if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
655
+                {
656
+                    # It's seriously malformed
657
+                    return '';
658
+                }
659
+
660
+                $slash    = trim($matches[1]);
661
+                $elem     = $matches[2];
662
+                $attrlist = $matches[3];
663
+
664
+                if (
665
+                    !isset($this->allowed_html[strtolower($elem)]) ||
666
+                    !is_array($this->allowed_html[strtolower($elem)])
667
+                )
668
+                {
669
+                    # They are using a not allowed HTML element
670
+                    return '';
671
+                }
672
+
673
+                if ($slash != '')
674
+                {
675
+                    return "<$slash$elem>";
676
+                }
677
+                # No attributes are allowed for closing elements
678
+
679
+                return $this->_attr("$slash$elem", $attrlist);
680
+            }
681
+
682
+            /**
683
+             *	This method strips out disallowed attributes for (X)HTML tags.
684
+             *
685
+             *	This method removes all attributes if none are allowed for this element.
686
+             *	If some are allowed it calls $this->_hair() to split them further, and then it
687
+             *	builds up new HTML code from the data that $this->_hair() returns. It also
688
+             *	removes "<" and ">" characters, if there are any left. One more thing it
689
+             *	does is to check if the tag has a closing XHTML slash, and if it does,
690
+             *	it puts one in the returned code as well.
691
+             *
692
+             *	@access private
693
+             *	@param string $element (X)HTML tag to check
694
+             *	@param string $attr Text containing attributes to check for validity.
695
+             *	@return string Resulting valid (X)HTML or ''
696
+             *	@see _hair()
697
+             *	@since PHP4 OOP 0.0.1
698
+             */
699
+            function _attr($element, $attr)
700
+            {
701
+                # Is there a closing XHTML slash at the end of the attributes?
702
+                $xhtml_slash = '';
703
+                if (preg_match('%\s/\s*$%', $attr))
704
+                {
705
+                    $xhtml_slash = ' /';
706
+                }
707
+
708
+                # Are any attributes allowed at all for this element?
709
+                if (
710
+                    !isset($this->allowed_html[strtolower($element)]) ||
711
+                    count($this->allowed_html[strtolower($element)]) == 0
712
+                )
713
+                {
714
+                    return "<$element$xhtml_slash>";
715
+                }
716
+
717
+                # Split it
718
+                $attrarr = $this->_hair($attr);
719
+
720
+                # Go through $attrarr, and save the allowed attributes for this element
721
+                # in $attr2
722
+                $attr2 = '';
723
+                if(is_array($attrarr) && count($attrarr) > 0)
724
+                {
725
+                    foreach ($attrarr as $arreach)
726
+                    {
727
+                        if(!isset($this->allowed_html[strtolower($element)][strtolower($arreach['name'])]))
728
+                        {
729
+                            continue;
730
+                        }
731
+
732
+                        $current = $this->allowed_html[strtolower($element)][strtolower($arreach['name'])];
733
+                        if ($current == '')
734
+                        {
735
+                            # the attribute is not allowed
736
+                            continue;
737
+                        }
738
+
739
+                        if (!is_array($current))
740
+                        {
741
+                            # there are no checks
742
+                            $attr2 .= ' '.$arreach['whole'];
743
+                        }
744
+                        else
745
+                        {
746
+                            # there are some checks
747
+                            $ok = true;
748
+                            if(is_array($current) && count($current) > 0)
749
+                            {
750
+                                foreach ($current as $currkey => $currval)
751
+                                {
752
+                                    if (!$this->_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval))
753
+                                    {
754
+                                        $ok = false;
755
+                                        break;
756
+                                    }
757
+                                }
758
+
759
+                                if ($ok)
760
+                                {
761
+                                    # it passed them
762
+                                    $attr2 .= ' '.$arreach['whole'];
763
+                                }
764
+                            }
765
+                        }
766
+                    }
767
+                }
768
+
769
+                # Remove any "<" or ">" characters
770
+                $attr2 = preg_replace('/[<>]/', '', $attr2);
771
+                return "<$element$attr2$xhtml_slash>";
772
+            }
773
+
774
+            /**
775
+             *	This method combs through an attribute list string and returns an associative array of attributes and values.
776
+             *
777
+             *	This method does a lot of work. It parses an attribute list into an array
778
+             *	with attribute data, and tries to do the right thing even if it gets weird
779
+             *	input. It will add quotes around attribute values that don't have any quotes
780
+             *	or apostrophes around them, to make it easier to produce HTML code that will
781
+             *	conform to W3C's HTML specification. It will also remove bad URL protocols
782
+             *	from attribute values.
783
+             *
784
+             *	@access private
785
+             *	@param string $attr Text containing tag attributes for parsing
786
+             *	@return array Associative array containing data on attribute and value
787
+             *	@since PHP4 OOP 0.0.1
788
+             */
789
+            function _hair($attr)
790
+            {
791
+                $attrarr  = array();
792
+                $mode     = 0;
793
+                $attrname = '';
794
+
795
+                # Loop through the whole attribute list
796
+
797
+                while (strlen($attr) != 0)
798
+                {
799
+                    # Was the last operation successful?
800
+                    $working = 0;
801
+
802
+                    switch ($mode)
803
+                    {
804
+                        case 0:	# attribute name, href for instance
805
+                            if (preg_match('/^([-a-zA-Z]+)/', $attr, $match))
806
+                            {
807
+                                $attrname = $match[1];
808
+                                $working = $mode = 1;
809
+                                $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
810
+                            }
811
+                            break;
812
+                        case 1:	# equals sign or valueless ("selected")
813
+                            if (preg_match('/^\s*=\s*/', $attr)) # equals sign
814
+                            {
815
+                                $working = 1;
816
+                                $mode    = 2;
817
+                                $attr    = preg_replace('/^\s*=\s*/', '', $attr);
818
+                                break;
819
+                            }
820
+                            if (preg_match('/^\s+/', $attr)) # valueless
821
+                            {
822
+                                $working   = 1;
823
+                                $mode      = 0;
824
+                                $attrarr[] = array(
825
+                                    'name'  => $attrname,
826
+                                    'value' => '',
827
+                                    'whole' => $attrname,
828
+                                    'vless' => 'y'
829
+                                );
830
+                                $attr      = preg_replace('/^\s+/', '', $attr);
831
+                            }
832
+                            break;
833
+                        case 2: # attribute value, a URL after href= for instance
834
+                            if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value"
835
+                            {
836
+                                $thisval   = $this->_bad_protocol($match[1]);
837
+                                $attrarr[] = array(
838
+                                    'name'  => $attrname,
839
+                                    'value' => $thisval,
840
+                                    'whole' => "$attrname=\"$thisval\"",
841
+                                    'vless' => 'n'
842
+                                );
843
+                                $working   = 1;
844
+                                $mode      = 0;
845
+                                $attr      = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
846
+                                break;
847
+                            }
848
+                            if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value'
849
+                            {
850
+                                $thisval   = $this->_bad_protocol($match[1]);
851
+                                $attrarr[] = array(
852
+                                    'name'  => $attrname,
853
+                                    'value' => $thisval,
854
+                                    'whole' => "$attrname='$thisval'",
855
+                                    'vless' => 'n'
856
+                                );
857
+                                $working   = 1;
858
+                                $mode      = 0;
859
+                                $attr      = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
860
+                                break;
861
+                            }
862
+                            if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value
863
+                            {
864
+                                $thisval   = $this->_bad_protocol($match[1]);
865
+                                $attrarr[] = array(
866
+                                    'name'  => $attrname,
867
+                                    'value' => $thisval,
868
+                                    'whole' => "$attrname=\"$thisval\"",
869
+                                    'vless' => 'n'
870
+                                );
871
+                                # We add quotes to conform to W3C's HTML spec.
872
+                                $working   = 1;
873
+                                $mode      = 0;
874
+                                $attr      = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
875
+                            }
876
+                            break;
877
+                    }
878
+
879
+                    if ($working == 0) # not well formed, remove and try again
880
+                    {
881
+                        $attr = $this->_html_error($attr);
882
+                        $mode = 0;
883
+                    }
884
+                }
885
+
886
+                # special case, for when the attribute list ends with a valueless
887
+                # attribute like "selected"
888
+                if ($mode == 1)
889
+                {
890
+                    $attrarr[] = array(
891
+                        'name'  => $attrname,
892
+                        'value' => '',
893
+                        'whole' => $attrname,
894
+                        'vless' => 'y'
895
+                    );
896
+                }
897
+
898
+                return $attrarr;
899
+            }
900
+
901
+            /**
902
+             *	This method removes disallowed protocols.
903
+             *
904
+             *	This method removes all non-allowed protocols from the beginning of
905
+             *	$string. It ignores whitespace and the case of the letters, and it does
906
+             *	understand HTML entities. It does its work in a while loop, so it won't be
907
+             *	fooled by a string like "javascript:javascript:alert(57)".
908
+             *
909
+             *	@access private
910
+             *	@param string $string String to check for protocols
911
+             *	@return string String with removed protocols
912
+             *	@since PHP4 OOP 0.0.1
913
+             */
914
+            function _bad_protocol($string)
915
+            {
916
+                $string  = $this->_no_null($string);
917
+                $string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
918
+                $string2 = $string.'a';
919
+
920
+                while ($string != $string2)
921
+                {
922
+                    $string2 = $string;
923
+                    $string  = $this->_bad_protocol_once($string);
924
+                } # while
925
+
926
+                return $string;
927
+            }
928
+
929
+            /**
930
+             *	Helper method used by _bad_protocol()
931
+             *
932
+             *	This function searches for URL protocols at the beginning of $string, while
933
+             *	handling whitespace and HTML entities.
934
+             *  Function updated to fix security vulnerability (see http://projects.dokeos.com/index.php?do=details&task_id=2312)
935
+             *
936
+             *	@access private
937
+             *	@param string $string String to check for protocols
938
+             *	@return string String with removed protocols
939
+             *	@see _bad_protocol()
940
+             *	@since PHP4 OOP 0.0.1
941
+             */
942
+            function _bad_protocol_once($string)
943
+            {
944
+                $string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2);
945
+                if(isset($string2[1]) && !preg_match('%/\?%',$string2[0]))
946
+                {
947
+                    $string = $this->_bad_protocol_once2($string2[0]).trim($string2[1]);
948
+                }
949
+                return $string;
950
+            }
951
+            /**
952
+             *	Helper method used by _bad_protocol_once() regex
953
+             *
954
+             *	This function processes URL protocols, checks to see if they're in the white-
955
+             *	list or not, and returns different data depending on the answer.
956
+             *
957
+             *	@access private
958
+             *	@param string $string String to check for protocols
959
+             *	@return string String with removed protocols
960
+             *	@see _bad_protocol()
961
+             *	@see _bad_protocol_once()
962
+             *	@since PHP4 OOP 0.0.1
963
+             */
964
+            function _bad_protocol_once2($string)
965
+            {
966
+                $string = $this->_decode_entities($string);
967
+                $string = preg_replace('/\s/', '', $string);
968
+                $string = $this->_no_null($string);
969
+                $string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
970
+                $string = strtolower($string);
971
+
972
+                $allowed = false;
973
+                if(is_array($this->allowed_protocols) && count($this->allowed_protocols) > 0)
974
+                {
975
+                    foreach ($this->allowed_protocols as $one_protocol)
976
+                    {
977
+                        if (strtolower($one_protocol) == $string)
978
+                        {
979
+                            $allowed = true;
980
+                            break;
981
+                        }
982
+                    }
983
+                }
984
+
985
+                if ($allowed)
986
+                {
987
+                    return "$string:";
988
+                }
989
+                else
990
+                {
991
+                    return '';
992
+                }
993
+            }
994
+
995
+            /**
996
+             *	This function performs different checks for attribute values.
997
+             *
998
+             *	The currently implemented checks are "maxlen", "minlen", "maxval",
999
+             *	"minval" and "valueless" with even more checks to come soon.
1000
+             *
1001
+             *	@access private
1002
+             *	@param string $value The value of the attribute to be checked.
1003
+             *	@param string $vless Indicates whether the the value is supposed to be valueless
1004
+             *	@param string $checkname The check to be performed
1005
+             *	@param string $checkvalue The value that is to be checked against
1006
+             *	@return bool Indicates whether the check passed or not
1007
+             *	@since PHP4 OOP 0.0.1
1008
+             */
1009
+            function _check_attr_val($value, $vless, $checkname, $checkvalue)
1010
+            {
1011
+                $ok = true;
1012
+
1013
+                switch (strtolower($checkname))
1014
+                {
1015
+                    /**
1016
+                     *	The maxlen check makes sure that the attribute value has a length not
1017
+                     *	greater than the given value. This can be used to avoid Buffer Overflows
1018
+                     *	in WWW clients and various Internet servers.
1019
+                     */
1020
+                    case 'maxlen':
1021
+                        if (strlen($value) > $checkvalue)
1022
+                        {
1023
+                            $ok = false;
1024
+                        }
1025
+                        break;
1026
+
1027
+                    /**
1028
+                     *	The minlen check makes sure that the attribute value has a length not
1029
+                     *	smaller than the given value.
1030
+                     */
1031
+                    case 'minlen':
1032
+                        if (strlen($value) < $checkvalue)
1033
+                        {
1034
+                            $ok = false;
1035
+                        }
1036
+                        break;
1037
+
1038
+                    /**
1039
+                     *	The maxval check does two things: it checks that the attribute value is
1040
+                     *	an integer from 0 and up, without an excessive amount of zeroes or
1041
+                     *	whitespace (to avoid Buffer Overflows). It also checks that the attribute
1042
+                     *	value is not greater than the given value.
1043
+                     *	This check can be used to avoid Denial of Service attacks.
1044
+                     */
1045
+                    case 'maxval':
1046
+                        if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1047
+                        {
1048
+                            $ok = false;
1049
+                        }
1050
+                        if ($value > $checkvalue)
1051
+                        {
1052
+                            $ok = false;
1053
+                        }
1054
+                        break;
1055
+
1056
+                    /**
1057
+                     *	The minval check checks that the attribute value is a positive integer,
1058
+                     *	and that it is not smaller than the given value.
1059
+                     */
1060
+                    case 'minval':
1061
+                        if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
1062
+                        {
1063
+                            $ok = false;
1064
+                        }
1065
+                        if ($value < $checkvalue)
1066
+                        {
1067
+                            $ok = false;
1068
+                        }
1069
+                        break;
1070
+
1071
+                    /**
1072
+                     *	The valueless check checks if the attribute has a value
1073
+                     *	(like <a href="blah">) or not (<option selected>). If the given value
1074
+                     *	is a "y" or a "Y", the attribute must not have a value.
1075
+                     *	If the given value is an "n" or an "N", the attribute must have one.
1076
+                     */
1077
+                    case 'valueless':
1078
+                    if (strtolower($checkvalue) != $vless)
1079
+                    {
1080
+                        $ok = false;
1081
+                    }
1082
+                    break;
1083
+
1084
+                }
1085
+
1086
+                return $ok;
1087
+            }
1088
+
1089
+            /**
1090
+             *	Changes \" to "
1091
+             *
1092
+             *	This function changes the character sequence  \"  to just  "
1093
+             *	It leaves all other slashes alone. It's really weird, but the quoting from
1094
+             *	preg_replace(//e) seems to require this.
1095
+             *
1096
+             *	@access private
1097
+             *	@param string $string The string to be stripped.
1098
+             *	@return string string stripped of \"
1099
+             *	@since PHP4 OOP 0.0.1
1100
+             */
1101
+            function _stripslashes($string)
1102
+            {
1103
+                return preg_replace('%\\\\"%', '"', $string);
1104
+            }
1105
+
1106
+            /**
1107
+             *	helper method for _hair()
1108
+             *
1109
+             *	This function deals with parsing errors in _hair(). The general plan is
1110
+             *	to remove everything to and including some whitespace, but it deals with
1111
+             *	quotes and apostrophes as well.
1112
+             *
1113
+             *	@access private
1114
+             *	@param string $string The string to be stripped.
1115
+             *	@return string string stripped of whitespace
1116
+             *	@see _hair()
1117
+             *	@since PHP4 OOP 0.0.1
1118
+             */
1119
+            function _html_error($string)
1120
+            {
1121
+                return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
1122
+            }
1123
+
1124
+            /**
1125
+             *	Decodes numeric HTML entities
1126
+             *
1127
+             *	This method decodes numeric HTML entities (&#65; and &#x41;). It doesn't
1128
+             *	do anything with other entities like &auml;, but we don't need them in the
1129
+             *	URL protocol white listing system anyway.
1130
+             *
1131
+             *	@access private
1132
+             *	@param string $value The entitiy to be decoded.
1133
+             *	@return string Decoded entity
1134
+             *	@since PHP4 OOP 0.0.1
1135
+             */
1136
+            function _decode_entities($string)
1137
+            {
1138
+                $string = preg_replace('/&#([0-9]+);/e', 'chr("\\1")', $string);
1139
+                $string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', 'chr(hexdec("\\1"))', $string);
1140
+                return $string;
1141
+            }
1142
+
1143
+            /**
1144
+             *	Returns PHP4 OOP version # of kses.
1145
+             *
1146
+             *	Since this class has been refactored and documented and proven to work,
1147
+             *	I'm syncing the version number to procedural kses.
1148
+             *
1149
+             *	@access public
1150
+             *	@return string Version number
1151
+             *	@since PHP4 OOP 0.0.1
1152
+             */
1153
+            function _version()
1154
+            {
1155
+                return 'PHP4 0.2.2 (OOP fork of procedural kses 0.2.2)';
1156
+            }
1157
+        }
1158
+
1159
+
1160
+
1161
+    }
1162 1162
 ?>
1163 1163
\ No newline at end of file
Please login to merge, or discard this patch.
main/inc/lib/xajax/xajax.inc.php 1 patch
Indentation   +1165 added lines, -1165 removed lines patch added patch discarded remove patch
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
  */
48 48
 if (!defined ('XAJAX_DEFAULT_CHAR_ENCODING'))
49 49
 {
50
-	define ('XAJAX_DEFAULT_CHAR_ENCODING', 'utf-8' );
50
+    define ('XAJAX_DEFAULT_CHAR_ENCODING', 'utf-8' );
51 51
 }
52 52
 
53 53
 /**
@@ -55,11 +55,11 @@  discard block
 block discarded – undo
55 55
  */
56 56
 if (!defined ('XAJAX_GET'))
57 57
 {
58
-	define ('XAJAX_GET', 0);
58
+    define ('XAJAX_GET', 0);
59 59
 }
60 60
 if (!defined ('XAJAX_POST'))
61 61
 {
62
-	define ('XAJAX_POST', 1);
62
+    define ('XAJAX_POST', 1);
63 63
 }
64 64
 
65 65
 /**
@@ -72,1145 +72,1145 @@  discard block
 block discarded – undo
72 72
  */
73 73
 class xajax
74 74
 {
75
-	/**#@+
75
+    /**#@+
76 76
 	 * @access protected
77 77
 	 */
78
-	/**
79
-	 * @var array Array of PHP functions that will be callable through javascript wrappers
80
-	 */
81
-	var $aFunctions;
82
-	/**
83
-	 * @var array Array of object callbacks that will allow Javascript to call PHP methods (key=function name)
84
-	 */
85
-	var $aObjects;
86
-	/**
87
-	 * @var array Array of RequestTypes to be used with each function (key=function name)
88
-	 */
89
-	var $aFunctionRequestTypes;
90
-	/**
91
-	 * @var array Array of Include Files for any external functions (key=function name)
92
-	 */
93
-	var $aFunctionIncludeFiles;
94
-	/**
95
-	 * @var string Name of the PHP function to call if no callable function was found
96
-	 */
97
-	var $sCatchAllFunction;
98
-	/**
99
-	 * @var string Name of the PHP function to call before any other function
100
-	 */
101
-	var $sPreFunction;
102
-	/**
103
-	 * @var string The URI for making requests to the xajax object
104
-	 */
105
-	var $sRequestURI;
106
-	/**
107
-	 * @var string The prefix to prepend to the javascript wraper function name
108
-	 */
109
-	var $sWrapperPrefix;
110
-	/**
111
-	 * @var boolean Show debug messages (default false)
112
-	 */
113
-	var $bDebug;
114
-	/**
115
-	 * @var boolean Show messages in the client browser's status bar (default false)
116
-	 */
117
-	var $bStatusMessages;
118
-	/**
119
-	 * @var boolean Allow xajax to exit after processing a request (default true)
120
-	 */
121
-	var $bExitAllowed;
122
-	/**
123
-	 * @var boolean Use wait cursor in browser (default true)
124
-	 */
125
-	var $bWaitCursor;
126
-	/**
127
-	 * @var boolean Use an special xajax error handler so the errors are sent to the browser properly (default false)
128
-	 */
129
-	var $bErrorHandler;
130
-	/**
131
-	 * @var string Specify what, if any, file xajax should log errors to (and more information in a future release)
132
-	 */
133
-	var $sLogFile;
134
-	/**
135
-	 * @var boolean Clean all output buffers before outputting response (default false)
136
-	 */
137
-	var $bCleanBuffer;
138
-	/**
139
-	 * @var string String containing the character encoding used
140
-	 */
141
-	var $sEncoding;
142
-	/**
143
-	 * @var boolean Decode input request args from UTF-8 (default false)
144
-	 */
145
-	var $bDecodeUTF8Input;
146
-	/**
147
-	 * @var boolean Convert special characters to HTML entities (default false)
148
-	 */
149
-	var $bOutputEntities;
150
-	/**
151
-	 * @var array Array for parsing complex objects
152
-	 */
153
-	var $aObjArray;
154
-	/**
155
-	 * @var integer Position in $aObjArray
156
-	 */
157
-	var $iPos;
158
-
159
-	/**#@-*/
160
-
161
-	/**
162
-	 * Constructor. You can set some extra xajax options right away or use
163
-	 * individual methods later to set options.
164
-	 *
165
-	 * @param string  defaults to the current browser URI
166
-	 * @param string  defaults to "xajax_";
167
-	 * @param string  defaults to XAJAX_DEFAULT_CHAR_ENCODING defined above
168
-	 * @param boolean defaults to false
169
-	 */
170
-	function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$sEncoding=XAJAX_DEFAULT_CHAR_ENCODING,$bDebug=false)
171
-	{
172
-		$this->aFunctions = array();
173
-		$this->aObjects = array();
174
-		$this->aFunctionIncludeFiles = array();
175
-		$this->sRequestURI = $sRequestURI;
176
-		if ($this->sRequestURI == "")
177
-			$this->sRequestURI = $this->_detectURI();
178
-		$this->sWrapperPrefix = $sWrapperPrefix;
179
-		$this->bDebug = $bDebug;
180
-		$this->bStatusMessages = false;
181
-		$this->bWaitCursor = true;
182
-		$this->bExitAllowed = true;
183
-		$this->bErrorHandler = false;
184
-		$this->sLogFile = "";
185
-		$this->bCleanBuffer = false;
186
-		$this->setCharEncoding($sEncoding);
187
-		$this->bDecodeUTF8Input = false;
188
-		$this->bOutputEntities = false;
189
-	}
190
-
191
-	/**
192
-	 * Sets the URI to which requests will be made.
193
-	 * <i>Usage:</i> <kbd>$xajax->setRequestURI("http://www.xajaxproject.org");</kbd>
194
-	 *
195
-	 * @param string the URI (can be absolute or relative) of the PHP script
196
-	 *               that will be accessed when an xajax request occurs
197
-	 */
198
-	function setRequestURI($sRequestURI)
199
-	{
200
-		$this->sRequestURI = $sRequestURI;
201
-	}
202
-
203
-	/**
204
-	 * Sets the prefix that will be appended to the Javascript wrapper
205
-	 * functions (default is "xajax_").
206
-	 *
207
-	 * @param string
208
-	 */
209
-	//
210
-	function setWrapperPrefix($sPrefix)
211
-	{
212
-		$this->sWrapperPrefix = $sPrefix;
213
-	}
214
-
215
-	/**
216
-	 * Enables debug messages for xajax.
217
-	 * */
218
-	function debugOn()
219
-	{
220
-		$this->bDebug = true;
221
-	}
222
-
223
-	/**
224
-	 * Disables debug messages for xajax (default behavior).
225
-	 */
226
-	function debugOff()
227
-	{
228
-		$this->bDebug = false;
229
-	}
230
-
231
-	/**
232
-	 * Enables messages in the browser's status bar for xajax.
233
-	 */
234
-	function statusMessagesOn()
235
-	{
236
-		$this->bStatusMessages = true;
237
-	}
238
-
239
-	/**
240
-	 * Disables messages in the browser's status bar for xajax (default behavior).
241
-	 */
242
-	function statusMessagesOff()
243
-	{
244
-		$this->bStatusMessages = false;
245
-	}
246
-
247
-	/**
248
-	 * Enables the wait cursor to be displayed in the browser (default behavior).
249
-	 */
250
-	function waitCursorOn()
251
-	{
252
-		$this->bWaitCursor = true;
253
-	}
254
-
255
-	/**
256
-	 * Disables the wait cursor to be displayed in the browser.
257
-	 */
258
-	function waitCursorOff()
259
-	{
260
-		$this->bWaitCursor = false;
261
-	}
262
-
263
-	/**
264
-	 * Enables xajax to exit immediately after processing a request and
265
-	 * sending the response back to the browser (default behavior).
266
-	 */
267
-	function exitAllowedOn()
268
-	{
269
-		$this->bExitAllowed = true;
270
-	}
271
-
272
-	/**
273
-	 * Disables xajax's default behavior of exiting immediately after
274
-	 * processing a request and sending the response back to the browser.
275
-	 */
276
-	function exitAllowedOff()
277
-	{
278
-		$this->bExitAllowed = false;
279
-	}
280
-
281
-	/**
282
-	 * Turns on xajax's error handling system so that PHP errors that occur
283
-	 * during a request are trapped and pushed to the browser in the form of
284
-	 * a Javascript alert.
285
-	 */
286
-	function errorHandlerOn()
287
-	{
288
-		$this->bErrorHandler = true;
289
-	}
290
-
291
-	/**
292
-	 * Turns off xajax's error handling system (default behavior).
293
-	 */
294
-	function errorHandlerOff()
295
-	{
296
-		$this->bErrorHandler = false;
297
-	}
298
-
299
-	/**
300
-	 * Specifies a log file that will be written to by xajax during a request
301
-	 * (used only by the error handling system at present). If you don't invoke
302
-	 * this method, or you pass in "", then no log file will be written to.
303
-	 * <i>Usage:</i> <kbd>$xajax->setLogFile("/xajax_logs/errors.log");</kbd>
304
-	 */
305
-	function setLogFile($sFilename)
306
-	{
307
-		$this->sLogFile = $sFilename;
308
-	}
309
-
310
-	/**
311
-	 * Causes xajax to clean out all output buffers before outputting a
312
-	 * response (default behavior).
313
-	 */
314
-	function cleanBufferOn()
315
-	{
316
-		$this->bCleanBuffer = true;
317
-	}
318
-	/**
319
-	 * Turns off xajax's output buffer cleaning.
320
-	 */
321
-	function cleanBufferOff()
322
-	{
323
-		$this->bCleanBuffer = false;
324
-	}
325
-
326
-	/**
327
-	 * Sets the character encoding for the HTTP output based on
328
-	 * <kbd>$sEncoding</kbd>, which is a string containing the character
329
-	 * encoding to use. You don't need to use this method normally, since the
330
-	 * character encoding for the response gets set automatically based on the
331
-	 * <kbd>XAJAX_DEFAULT_CHAR_ENCODING</kbd> constant.
332
-	 * <i>Usage:</i> <kbd>$xajax->setCharEncoding("utf-8");</kbd>
333
-	 *
334
-	 * @param string the encoding type to use (utf-8, iso-8859-1, etc.)
335
-	 */
336
-	function setCharEncoding($sEncoding)
337
-	{
338
-		$this->sEncoding = $sEncoding;
339
-	}
340
-
341
-	/**
342
-	 * Causes xajax to decode the input request args from UTF-8 to the current
343
-	 * encoding if possible. Either the iconv or mb_string extension must be
344
-	 * present for optimal functionality.
345
-	 */
346
-	function decodeUTF8InputOn()
347
-	{
348
-		$this->bDecodeUTF8Input = true;
349
-	}
350
-
351
-	/**
352
-	 * Turns off decoding the input request args from UTF-8 (default behavior).
353
-	 */
354
-	function decodeUTF8InputOff()
355
-	{
356
-		$this->bDecodeUTF8Input = false;
357
-	}
358
-
359
-	/**
360
-	 * Tells the response object to convert special characters to HTML entities
361
-	 * automatically (only works if the mb_string extension is available).
362
-	 */
363
-	function outputEntitiesOn()
364
-	{
365
-		$this->bOutputEntities = true;
366
-	}
367
-
368
-	/**
369
-	 * Tells the response object to output special characters intact. (default
370
-	 * behavior).
371
-	 */
372
-	function outputEntitiesOff()
373
-	{
374
-		$this->bOutputEntities = false;
375
-	}
376
-
377
-	/**
378
-	 * Registers a PHP function or method to be callable through xajax in your
379
-	 * Javascript. If you want to register a function, pass in the name of that
380
-	 * function. If you want to register a static class method, pass in an
381
-	 * array like so:
382
-	 * <kbd>array("myFunctionName", "myClass", "myMethod")</kbd>
383
-	 * For an object instance method, use an object variable for the second
384
-	 * array element (and in PHP 4 make sure you put an & before the variable
385
-	 * to pass the object by reference). Note: the function name is what you
386
-	 * call via Javascript, so it can be anything as long as it doesn't
387
-	 * conflict with any other registered function name.
388
-	 *
389
-	 * <i>Usage:</i> <kbd>$xajax->registerFunction("myFunction");</kbd>
390
-	 * or: <kbd>$xajax->registerFunction(array("myFunctionName", &$myObject, "myMethod"));</kbd>
391
-	 *
392
-	 * @param mixed  contains the function name or an object callback array
393
-	 * @param mixed  request type (XAJAX_GET/XAJAX_POST) that should be used
394
-	 *               for this function.  Defaults to XAJAX_POST.
395
-	 */
396
-	function registerFunction($mFunction,$sRequestType=XAJAX_POST)
397
-	{
398
-		if (is_array($mFunction)) {
399
-			$this->aFunctions[$mFunction[0]] = 1;
400
-			$this->aFunctionRequestTypes[$mFunction[0]] = $sRequestType;
401
-			$this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
402
-		}
403
-		else {
404
-			$this->aFunctions[$mFunction] = 1;
405
-			$this->aFunctionRequestTypes[$mFunction] = $sRequestType;
406
-		}
407
-	}
408
-
409
-	/**
410
-	 * Registers a PHP function to be callable through xajax which is located
411
-	 * in some other file.  If the function is requested the external file will
412
-	 * be included to define the function before the function is called.
413
-	 *
414
-	 * <i>Usage:</i> <kbd>$xajax->registerExternalFunction("myFunction","myFunction.inc.php",XAJAX_POST);</kbd>
415
-	 *
416
-	 * @param string contains the function name or an object callback array
417
-	 *               ({@link xajax::registerFunction() see registerFunction} for
418
-	 *               more info on object callback arrays)
419
-	 * @param string contains the path and filename of the include file
420
-	 * @param mixed  the RequestType (XAJAX_GET/XAJAX_POST) that should be used
421
-	 *		          for this function. Defaults to XAJAX_POST.
422
-	 */
423
-	function registerExternalFunction($mFunction,$sIncludeFile,$sRequestType=XAJAX_POST)
424
-	{
425
-		$this->registerFunction($mFunction, $sRequestType);
426
-
427
-		if (is_array($mFunction)) {
428
-			$this->aFunctionIncludeFiles[$mFunction[0]] = $sIncludeFile;
429
-		}
430
-		else {
431
-			$this->aFunctionIncludeFiles[$mFunction] = $sIncludeFile;
432
-		}
433
-	}
434
-
435
-	/**
436
-	 * Registers a PHP function to be called when xajax cannot find the
437
-	 * function being called via Javascript. Because this is technically
438
-	 * impossible when using "wrapped" functions, the catch-all feature is
439
-	 * only useful when you're directly using the xajax.call() Javascript
440
-	 * method. Use the catch-all feature when you want more dynamic ability to
441
-	 * intercept unknown calls and handle them in a custom way.
442
-	 *
443
-	 * <i>Usage:</i> <kbd>$xajax->registerCatchAllFunction("myCatchAllFunction");</kbd>
444
-	 *
445
-	 * @param string contains the function name or an object callback array
446
-	 *               ({@link xajax::registerFunction() see registerFunction} for
447
-	 *               more info on object callback arrays)
448
-	 */
449
-	function registerCatchAllFunction($mFunction)
450
-	{
451
-		if (is_array($mFunction)) {
452
-			$this->sCatchAllFunction = $mFunction[0];
453
-			$this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
454
-		}
455
-		else {
456
-			$this->sCatchAllFunction = $mFunction;
457
-		}
458
-	}
459
-
460
-	/**
461
-	 * Registers a PHP function to be called before xajax calls the requested
462
-	 * function. xajax will automatically add the request function's response
463
-	 * to the pre-function's response to create a single response. Another
464
-	 * feature is the ability to return not just a response, but an array with
465
-	 * the first element being false (a boolean) and the second being the
466
-	 * response. In this case, the pre-function's response will be returned to
467
-	 * the browser without xajax calling the requested function.
468
-	 *
469
-	 * <i>Usage:</i> <kbd>$xajax->registerPreFunction("myPreFunction");</kbd>
470
-	 *
471
-	 * @param string contains the function name or an object callback array
472
-	 *               ({@link xajax::registerFunction() see registerFunction} for
473
-	 *               more info on object callback arrays)
474
-	 */
475
-	function registerPreFunction($mFunction)
476
-	{
477
-		if (is_array($mFunction)) {
478
-			$this->sPreFunction = $mFunction[0];
479
-			$this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
480
-		}
481
-		else {
482
-			$this->sPreFunction = $mFunction;
483
-		}
484
-	}
485
-
486
-	/**
487
-	 * Returns true if xajax can process the request, false if otherwise.
488
-	 * You can use this to determine if xajax needs to process the request or
489
-	 * not.
490
-	 *
491
-	 * @return boolean
492
-	 */
493
-	function canProcessRequests()
494
-	{
495
-		if ($this->getRequestMode() != -1) return true;
496
-		return false;
497
-	}
498
-
499
-	/**
500
-	 * Returns the current request mode (XAJAX_GET or XAJAX_POST), or -1 if
501
-	 * there is none.
502
-	 *
503
-	 * @return mixed
504
-	 */
505
-	function getRequestMode()
506
-	{
507
-		if (!empty($_GET["xajax"]))
508
-			return XAJAX_GET;
509
-
510
-		if (!empty($_POST["xajax"]))
511
-			return XAJAX_POST;
512
-
513
-		return -1;
514
-	}
515
-
516
-	/**
517
-	 * This is the main communications engine of xajax. The engine handles all
518
-	 * incoming xajax requests, calls the apporiate PHP functions (or
519
-	 * class/object methods) and passes the XML responses back to the
520
-	 * Javascript response handler. If your RequestURI is the same as your Web
521
-	 * page then this function should be called before any headers or HTML has
522
-	 * been sent.
523
-	 */
524
-	function processRequests()
525
-	{
526
-
527
-		$requestMode = -1;
528
-		$sFunctionName = "";
529
-		$bFoundFunction = true;
530
-		$bFunctionIsCatchAll = false;
531
-		$sFunctionNameForSpecial = "";
532
-		$aArgs = array();
533
-		$sPreResponse = "";
534
-		$bEndRequest = false;
535
-		$sResponse = "";
536
-
537
-		$requestMode = $this->getRequestMode();
538
-		if ($requestMode == -1) return;
539
-
540
-		if ($requestMode == XAJAX_POST)
541
-		{
542
-			$sFunctionName = $_POST["xajax"];
543
-
544
-			if (!empty($_POST["xajaxargs"]))
545
-				$aArgs = $_POST["xajaxargs"];
546
-		}
547
-		else
548
-		{
549
-			header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
550
-			header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
551
-			header ("Cache-Control: no-cache, must-revalidate");
552
-			header ("Pragma: no-cache");
553
-
554
-			$sFunctionName = $_GET["xajax"];
555
-
556
-			if (!empty($_GET["xajaxargs"]))
557
-				$aArgs = $_GET["xajaxargs"];
558
-		}
559
-
560
-		// Use xajax error handler if necessary
561
-		if ($this->bErrorHandler) {
562
-			$GLOBALS['xajaxErrorHandlerText'] = "";
563
-			set_error_handler("xajaxErrorHandler");
564
-		}
565
-
566
-		if ($this->sPreFunction) {
567
-			if (!$this->_isFunctionCallable($this->sPreFunction)) {
568
-				$bFoundFunction = false;
569
-				$objResponse = new xajaxResponse();
570
-				$objResponse->addAlert("Unknown Pre-Function ". $this->sPreFunction);
571
-				$sResponse = $objResponse->getXML();
572
-			}
573
-		}
574
-		//include any external dependencies associated with this function name
575
-		if (array_key_exists($sFunctionName,$this->aFunctionIncludeFiles))
576
-		{
577
-			ob_start();
578
-			include_once($this->aFunctionIncludeFiles[$sFunctionName]);
579
-			ob_end_clean();
580
-		}
581
-
582
-		if ($bFoundFunction) {
583
-			$sFunctionNameForSpecial = $sFunctionName;
584
-			if (!array_key_exists($sFunctionName, $this->aFunctions))
585
-			{
586
-				if ($this->sCatchAllFunction) {
587
-					$sFunctionName = $this->sCatchAllFunction;
588
-					$bFunctionIsCatchAll = true;
589
-				}
590
-				else {
591
-					$bFoundFunction = false;
592
-					$objResponse = new xajaxResponse();
593
-					$objResponse->addAlert("Unknown Function $sFunctionName.");
594
-					$sResponse = $objResponse->getXML();
595
-				}
596
-			}
597
-			else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode)
598
-			{
599
-				$bFoundFunction = false;
600
-				$objResponse = new xajaxResponse();
601
-				$objResponse->addAlert("Incorrect Request Type.");
602
-				$sResponse = $objResponse->getXML();
603
-			}
604
-		}
605
-
606
-		if ($bFoundFunction)
607
-		{
608
-			for ($i = 0; $i < sizeof($aArgs); $i++)
609
-			{
610
-				// If magic quotes is on, then we need to strip the slashes from the args
611
-				if (get_magic_quotes_gpc() == 1 && is_string($aArgs[$i])) {
612
-
613
-					$aArgs[$i] = stripslashes($aArgs[$i]);
614
-				}
615
-				if (stristr($aArgs[$i],"<xjxobj>") != false)
616
-				{
617
-					$aArgs[$i] = $this->_xmlToArray("xjxobj",$aArgs[$i]);
618
-				}
619
-				else if (stristr($aArgs[$i],"<xjxquery>") != false)
620
-				{
621
-					$aArgs[$i] = $this->_xmlToArray("xjxquery",$aArgs[$i]);
622
-				}
623
-				else if ($this->bDecodeUTF8Input)
624
-				{
625
-					$aArgs[$i] = $this->_decodeUTF8Data($aArgs[$i]);
626
-				}
627
-			}
628
-
629
-			if ($this->sPreFunction) {
630
-				$mPreResponse = $this->_callFunction($this->sPreFunction, array($sFunctionNameForSpecial, $aArgs));
631
-				if (is_array($mPreResponse) && $mPreResponse[0] === false) {
632
-					$bEndRequest = true;
633
-					$sPreResponse = $mPreResponse[1];
634
-				}
635
-				else {
636
-					$sPreResponse = $mPreResponse;
637
-				}
638
-				if (is_a($sPreResponse, "xajaxResponse")) {
639
-					$sPreResponse = $sPreResponse->getXML();
640
-				}
641
-				if ($bEndRequest) $sResponse = $sPreResponse;
642
-			}
643
-
644
-			if (!$bEndRequest) {
645
-				if (!$this->_isFunctionCallable($sFunctionName)) {
646
-					$objResponse = new xajaxResponse();
647
-					$objResponse->addAlert("The Registered Function $sFunctionName Could Not Be Found.");
648
-					$sResponse = $objResponse->getXML();
649
-				}
650
-				else {
651
-					if ($bFunctionIsCatchAll) {
652
-						$aArgs = array($sFunctionNameForSpecial, $aArgs);
653
-					}
654
-					$sResponse = $this->_callFunction($sFunctionName, $aArgs);
655
-				}
656
-				if (is_a($sResponse, "xajaxResponse")) {
657
-					$sResponse = $sResponse->getXML();
658
-				}
659
-				if (!is_string($sResponse) || strpos($sResponse, "<xjx>") === FALSE) {
660
-					$objResponse = new xajaxResponse();
661
-					$objResponse->addAlert("No XML Response Was Returned By Function $sFunctionName.");
662
-					$sResponse = $objResponse->getXML();
663
-				}
664
-				else if ($sPreResponse != "") {
665
-					$sNewResponse = new xajaxResponse($this->sEncoding, $this->bOutputEntities);
666
-					$sNewResponse->loadXML($sPreResponse);
667
-					$sNewResponse->loadXML($sResponse);
668
-					$sResponse = $sNewResponse->getXML();
669
-				}
670
-			}
671
-		}
672
-
673
-		$sContentHeader = "Content-type: text/xml;";
674
-		if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0)
675
-			$sContentHeader .= " charset=".$this->sEncoding;
676
-		header($sContentHeader);
677
-		if ($this->bErrorHandler && !empty( $GLOBALS['xajaxErrorHandlerText'] )) {
678
-			$sErrorResponse = new xajaxResponse();
679
-			$sErrorResponse->addAlert("** PHP Error Messages: **" . $GLOBALS['xajaxErrorHandlerText']);
680
-			if ($this->sLogFile) {
681
-				$fH = @fopen($this->sLogFile, "a");
682
-				if (!$fH) {
683
-					$sErrorResponse->addAlert("** Logging Error **\n\nxajax was unable to write to the error log file:\n" . $this->sLogFile);
684
-				}
685
-				else {
686
-					fwrite($fH, "** xajax Error Log - " . strftime("%b %e %Y %I:%M:%S %p") . " **" . $GLOBALS['xajaxErrorHandlerText'] . "\n\n\n");
687
-					fclose($fH);
688
-				}
689
-			}
690
-
691
-			$sErrorResponse->loadXML($sResponse);
692
-			$sResponse = $sErrorResponse->getXML();
693
-
694
-		}
695
-		if ($this->bCleanBuffer) while (@ob_end_clean());
696
-		print $sResponse;
697
-		if ($this->bErrorHandler) restore_error_handler();
698
-
699
-		if ($this->bExitAllowed)
700
-			exit();
701
-	}
702
-
703
-	/**
704
-	 * Prints the xajax Javascript header and wrapper code into your page by
705
-	 * printing the output of the getJavascript() method. It should only be
706
-	 * called between the <pre><head> </head></pre> tags in your HTML page.
707
-	 * Remember, if you only want to obtain the result of this function, use
708
-	 * {@link xajax::getJavascript()} instead.
709
-	 *
710
-	 * <i>Usage:</i>
711
-	 * <code>
712
-	 *  <head>
713
-	 *		...
714
-	 *		< ?php $xajax->printJavascript(); ? >
715
-	 * </code>
716
-	 *
717
-	 * @param string the relative address of the folder where xajax has been
718
-	 *               installed. For instance, if your PHP file is
719
-	 *               "http://www.myserver.com/myfolder/mypage.php"
720
-	 *               and xajax was installed in
721
-	 *               "http://www.myserver.com/anotherfolder", then $sJsURI
722
-	 *               should be set to "../anotherfolder". Defaults to assuming
723
-	 *               xajax is in the same folder as your PHP file.
724
-	 * @param string the relative folder/file pair of the xajax Javascript
725
-	 *               engine located within the xajax installation folder.
726
-	 *               Defaults to xajax_js/xajax.js.
727
-	 */
728
-	function printJavascript($sJsURI="", $sJsFile=NULL)
729
-	{
730
-		print $this->getJavascript($sJsURI, $sJsFile);
731
-	}
732
-
733
-	/**
734
-	 * Returns the xajax Javascript code that should be added to your HTML page
735
-	 * between the <kbd><head> </head></kbd> tags.
736
-	 *
737
-	 * <i>Usage:</i>
738
-	 * <code>
739
-	 *  < ?php $xajaxJSHead = $xajax->getJavascript(); ? >
740
-	 *	<head>
741
-	 *		...
742
-	 *		< ?php echo $xajaxJSHead; ? >
743
-	 * </code>
744
-	 *
745
-	 * @param string the relative address of the folder where xajax has been
746
-	 *               installed. For instance, if your PHP file is
747
-	 *               "http://www.myserver.com/myfolder/mypage.php"
748
-	 *               and xajax was installed in
749
-	 *               "http://www.myserver.com/anotherfolder", then $sJsURI
750
-	 *               should be set to "../anotherfolder". Defaults to assuming
751
-	 *               xajax is in the same folder as your PHP file.
752
-	 * @param string the relative folder/file pair of the xajax Javascript
753
-	 *               engine located within the xajax installation folder.
754
-	 *               Defaults to xajax_js/xajax.js.
755
-	 * @return string
756
-	 */
757
-	function getJavascript($sJsURI="", $sJsFile=NULL)
758
-	{
759
-		$html = $this->getJavascriptConfig();
760
-		$html .= $this->getJavascriptInclude($sJsURI, $sJsFile);
761
-
762
-		return $html;
763
-	}
764
-
765
-	/**
766
-	 * Returns a string containing inline Javascript that sets up the xajax
767
-	 * runtime (typically called internally by xajax from get/printJavascript).
768
-	 *
769
-	 * @return string
770
-	 */
771
-	function getJavascriptConfig()
772
-	{
773
-		$html  = "\t<script type=\"text/javascript\">\n";
774
-		$html .= "var xajaxRequestUri=\"".$this->sRequestURI."\";\n";
775
-		$html .= "var xajaxDebug=".($this->bDebug?"true":"false").";\n";
776
-		$html .= "var xajaxStatusMessages=".($this->bStatusMessages?"true":"false").";\n";
777
-		$html .= "var xajaxWaitCursor=".($this->bWaitCursor?"true":"false").";\n";
778
-		$html .= "var xajaxDefinedGet=".XAJAX_GET.";\n";
779
-		$html .= "var xajaxDefinedPost=".XAJAX_POST.";\n";
780
-		$html .= "var xajaxLoaded=false;\n";
781
-
782
-		foreach($this->aFunctions as $sFunction => $bExists) {
783
-			$html .= $this->_wrap($sFunction,$this->aFunctionRequestTypes[$sFunction]);
784
-		}
785
-
786
-		$html .= "\t</script>\n";
787
-		return $html;
788
-	}
789
-
790
-	/**
791
-	 * Returns a string containing a Javascript include of the xajax.js file
792
-	 * along with a check to see if the file loaded after six seconds
793
-	 * (typically called internally by xajax from get/printJavascript).
794
-	 *
795
-	 * @param string the relative address of the folder where xajax has been
796
-	 *               installed. For instance, if your PHP file is
797
-	 *               "http://www.myserver.com/myfolder/mypage.php"
798
-	 *               and xajax was installed in
799
-	 *               "http://www.myserver.com/anotherfolder", then $sJsURI
800
-	 *               should be set to "../anotherfolder". Defaults to assuming
801
-	 *               xajax is in the same folder as your PHP file.
802
-	 * @param string the relative folder/file pair of the xajax Javascript
803
-	 *               engine located within the xajax installation folder.
804
-	 *               Defaults to xajax_js/xajax.js.
805
-	 * @return string
806
-	 */
807
-	function getJavascriptInclude($sJsURI="", $sJsFile=NULL)
808
-	{
809
-		if ($sJsFile == NULL) $sJsFile = "xajax_js/xajax.js";
810
-
811
-		if ($sJsURI != "" && substr($sJsURI, -1) != "/") $sJsURI .= "/";
812
-
813
-		$html = "\t<script type=\"text/javascript\" src=\"" . $sJsURI . $sJsFile . "\"></script>\n";
814
-		$html .= "\t<script type=\"text/javascript\">\n";
815
-		$html .= "window.setTimeout(function () { if (!xajaxLoaded) { alert('Error: the xajax Javascript file could not be included. Perhaps the URL is incorrect?\\nURL: {$sJsURI}{$sJsFile}'); } }, 6000);\n";
816
-		$html .= "\t</script>\n";
817
-		return $html;
818
-	}
819
-
820
-	/**
821
-	 * This method can be used to create a new xajax.js file out of the
822
-	 * xajax_uncompressed.js file (which will only happen if xajax.js doesn't
823
-	 * already exist on the filesystem).
824
-	 *
825
-	 * @param string an optional argument containing the full server file path
826
-	 *               of xajax.js.
827
-	 */
828
-	function autoCompressJavascript($sJsFullFilename=NULL)
829
-	{
830
-		$sJsFile = "xajax_js/xajax.js";
831
-
832
-		if ($sJsFullFilename) {
833
-			$realJsFile = $sJsFullFilename;
834
-		}
835
-		else {
836
-			$realPath = realpath(dirname(__FILE__));
837
-			$realJsFile = $realPath . "/". $sJsFile;
838
-		}
839
-
840
-		// Create a compressed file if necessary
841
-		if (!file_exists($realJsFile)) {
842
-			$srcFile = str_replace(".js", "_uncompressed.js", $realJsFile);
843
-			if (!file_exists($srcFile)) {
844
-				trigger_error("The xajax uncompressed Javascript file could not be found in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
845
-			}
846
-			require(dirname(__FILE__)."/xajaxCompress.php");
847
-			$javaScript = implode('', file($srcFile));
848
-			$compressedScript = xajaxCompressJavascript($javaScript);
849
-			$fH = @fopen($realJsFile, "w");
850
-			if (!$fH) {
851
-				trigger_error("The xajax compressed javascript file could not be written in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
852
-			}
853
-			else {
854
-				fwrite($fH, $compressedScript);
855
-				fclose($fH);
856
-			}
857
-		}
858
-	}
859
-
860
-	/**
861
-	 * Returns the current URL based upon the SERVER vars.
862
-	 *
863
-	 * @access private
864
-	 * @return string
865
-	 */
866
-	function _detectURI() {
867
-		$aURL = array();
868
-
869
-		// Try to get the request URL
870
-		if (!empty($_SERVER['REQUEST_URI'])) {
871
-			$aURL = parse_url($_SERVER['REQUEST_URI']);
872
-		}
873
-
874
-		// Fill in the empty values
875
-		if (empty($aURL['scheme'])) {
876
-			if (!empty($_SERVER['HTTP_SCHEME'])) {
877
-				$aURL['scheme'] = $_SERVER['HTTP_SCHEME'];
878
-			} else {
879
-				$aURL['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http';
880
-			}
881
-		}
882
-
883
-		if (empty($aURL['host'])) {
884
-			if (!empty($_SERVER['HTTP_HOST'])) {
885
-				if (strpos($_SERVER['HTTP_HOST'], ':') > 0) {
886
-					list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_HOST']);
887
-				} else {
888
-					$aURL['host'] = $_SERVER['HTTP_HOST'];
889
-				}
890
-			} else if (!empty($_SERVER['SERVER_NAME'])) {
891
-				$aURL['host'] = $_SERVER['SERVER_NAME'];
892
-			} else {
893
-				print "xajax Error: xajax failed to automatically identify your Request URI.";
894
-				print "Please set the Request URI explicitly when you instantiate the xajax object.";
895
-				exit();
896
-			}
897
-		}
898
-
899
-		if (empty($aURL['port']) && !empty($_SERVER['SERVER_PORT'])) {
900
-			$aURL['port'] = $_SERVER['SERVER_PORT'];
901
-		}
902
-
903
-		if (empty($aURL['path'])) {
904
-			if (!empty($_SERVER['PATH_INFO'])) {
905
-				$sPath = parse_url($_SERVER['PATH_INFO']);
906
-			} else {
907
-				$sPath = parse_url(api_get_self());
908
-			}
909
-			$aURL['path'] = $sPath['path'];
910
-			unset($sPath);
911
-		}
912
-
913
-		if (!empty($aURL['query'])) {
914
-			$aURL['query'] = '?'.$aURL['query'];
915
-		}
916
-
917
-		// Build the URL: Start with scheme, user and pass
918
-		$sURL = $aURL['scheme'].'://';
919
-		if (!empty($aURL['user'])) {
920
-			$sURL.= $aURL['user'];
921
-			if (!empty($aURL['pass'])) {
922
-				$sURL.= ':'.$aURL['pass'];
923
-			}
924
-			$sURL.= '@';
925
-		}
926
-
927
-		// Add the host
928
-		$sURL.= $aURL['host'];
929
-
930
-		// Add the port if needed
931
-		if (!empty($aURL['port']) && (($aURL['scheme'] == 'http' && $aURL['port'] != 80) || ($aURL['scheme'] == 'https' && $aURL['port'] != 443))) {
932
-			$sURL.= ':'.$aURL['port'];
933
-		}
934
-
935
-		// Add the path and the query string
936
-		$sURL.= $aURL['path'].@$aURL['query'];
937
-
938
-		// Clean up
939
-		unset($aURL);
940
-		return $sURL;
941
-	}
942
-
943
-	/**
944
-	 * Returns true if the function name is associated with an object callback,
945
-	 * false if not.
946
-	 *
947
-	 * @param string the name of the function
948
-	 * @access private
949
-	 * @return boolean
950
-	 */
951
-	function _isObjectCallback($sFunction)
952
-	{
953
-		if (array_key_exists($sFunction, $this->aObjects)) return true;
954
-		return false;
955
-	}
956
-
957
-	/**
958
-	 * Returns true if the function or object callback can be called, false if
959
-	 * not.
960
-	 *
961
-	 * @param string the name of the function
962
-	 * @access private
963
-	 * @return boolean
964
-	 */
965
-	function _isFunctionCallable($sFunction)
966
-	{
967
-		if ($this->_isObjectCallback($sFunction)) {
968
-			if (is_object($this->aObjects[$sFunction][0])) {
969
-				return method_exists($this->aObjects[$sFunction][0], $this->aObjects[$sFunction][1]);
970
-			}
971
-			else {
972
-				return is_callable($this->aObjects[$sFunction]);
973
-			}
974
-		}
975
-		else {
976
-			return function_exists($sFunction);
977
-		}
978
-	}
979
-
980
-	/**
981
-	 * Calls the function, class method, or object method with the supplied
982
-	 * arguments.
983
-	 *
984
-	 * @param string the name of the function
985
-	 * @param array  arguments to pass to the function
986
-	 * @access private
987
-	 * @return mixed the output of the called function or method
988
-	 */
989
-	function _callFunction($sFunction, $aArgs)
990
-	{
991
-		if ($this->_isObjectCallback($sFunction)) {
992
-			$mReturn = call_user_func_array($this->aObjects[$sFunction], $aArgs);
993
-		}
994
-		else {
995
-			$mReturn = call_user_func_array($sFunction, $aArgs);
996
-		}
997
-		return $mReturn;
998
-	}
999
-
1000
-	/**
1001
-	 * Generates the Javascript wrapper for the specified PHP function.
1002
-	 *
1003
-	 * @param string the name of the function
1004
-	 * @param mixed  the request type
1005
-	 * @access private
1006
-	 * @return string
1007
-	 */
1008
-	function _wrap($sFunction,$sRequestType=XAJAX_POST)
1009
-	{
1010
-		$js = "function ".$this->sWrapperPrefix."$sFunction(){return xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n";
1011
-		return $js;
1012
-	}
1013
-
1014
-	/**
1015
-	 * Takes a string containing xajax xjxobj XML or xjxquery XML and builds an
1016
-	 * array representation of it to pass as an argument to the PHP function
1017
-	 * being called.
1018
-	 *
1019
-	 * @param string the root tag of the XML
1020
-	 * @param string XML to convert
1021
-	 * @access private
1022
-	 * @return array
1023
-	 */
1024
-	function _xmlToArray($rootTag, $sXml)
1025
-	{
1026
-		$aArray = array();
1027
-		$sXml = str_replace("<$rootTag>","<$rootTag>|~|",$sXml);
1028
-		$sXml = str_replace("</$rootTag>","</$rootTag>|~|",$sXml);
1029
-		$sXml = str_replace("<e>","<e>|~|",$sXml);
1030
-		$sXml = str_replace("</e>","</e>|~|",$sXml);
1031
-		$sXml = str_replace("<k>","<k>|~|",$sXml);
1032
-		$sXml = str_replace("</k>","|~|</k>|~|",$sXml);
1033
-		$sXml = str_replace("<v>","<v>|~|",$sXml);
1034
-		$sXml = str_replace("</v>","|~|</v>|~|",$sXml);
1035
-		$sXml = str_replace("<q>","<q>|~|",$sXml);
1036
-		$sXml = str_replace("</q>","|~|</q>|~|",$sXml);
1037
-
1038
-		$this->aObjArray = explode("|~|",$sXml);
1039
-
1040
-		$this->iPos = 0;
1041
-		$aArray = $this->_parseObjXml($rootTag);
1042
-
1043
-		return $aArray;
1044
-	}
1045
-
1046
-	/**
1047
-	 * A recursive function that generates an array from the contents of
1048
-	 * $this->aObjArray.
1049
-	 *
1050
-	 * @param string the root tag of the XML
1051
-	 * @access private
1052
-	 * @return array
1053
-	 */
1054
-	function _parseObjXml($rootTag)
1055
-	{
1056
-		$aArray = array();
1057
-
1058
-		if ($rootTag == "xjxobj")
1059
-		{
1060
-			while(!stristr($this->aObjArray[$this->iPos],"</xjxobj>"))
1061
-			{
1062
-				$this->iPos++;
1063
-				if(stristr($this->aObjArray[$this->iPos],"<e>"))
1064
-				{
1065
-					$key = "";
1066
-					$value = null;
1067
-
1068
-					$this->iPos++;
1069
-					while(!stristr($this->aObjArray[$this->iPos],"</e>"))
1070
-					{
1071
-						if(stristr($this->aObjArray[$this->iPos],"<k>"))
1072
-						{
1073
-							$this->iPos++;
1074
-							while(!stristr($this->aObjArray[$this->iPos],"</k>"))
1075
-							{
1076
-								$key .= $this->aObjArray[$this->iPos];
1077
-								$this->iPos++;
1078
-							}
1079
-						}
1080
-						if(stristr($this->aObjArray[$this->iPos],"<v>"))
1081
-						{
1082
-							$this->iPos++;
1083
-							while(!stristr($this->aObjArray[$this->iPos],"</v>"))
1084
-							{
1085
-								if(stristr($this->aObjArray[$this->iPos],"<xjxobj>"))
1086
-								{
1087
-									$value = $this->_parseObjXml("xjxobj");
1088
-									$this->iPos++;
1089
-								}
1090
-								else
1091
-								{
1092
-									$value .= $this->aObjArray[$this->iPos];
1093
-									if ($this->bDecodeUTF8Input)
1094
-									{
1095
-										$value = $this->_decodeUTF8Data($value);
1096
-									}
1097
-								}
1098
-								$this->iPos++;
1099
-							}
1100
-						}
1101
-						$this->iPos++;
1102
-					}
1103
-
1104
-					$aArray[$key]=$value;
1105
-				}
1106
-			}
1107
-		}
1108
-
1109
-		if ($rootTag == "xjxquery")
1110
-		{
1111
-			$sQuery = "";
1112
-			$this->iPos++;
1113
-			while(!stristr($this->aObjArray[$this->iPos],"</xjxquery>"))
1114
-			{
1115
-				if (stristr($this->aObjArray[$this->iPos],"<q>") || stristr($this->aObjArray[$this->iPos],"</q>"))
1116
-				{
1117
-					$this->iPos++;
1118
-					continue;
1119
-				}
1120
-				$sQuery	.= $this->aObjArray[$this->iPos];
1121
-				$this->iPos++;
1122
-			}
1123
-
1124
-			parse_str($sQuery, $aArray);
1125
-			if ($this->bDecodeUTF8Input)
1126
-			{
1127
-				foreach($aArray as $key => $value)
1128
-				{
1129
-					$aArray[$key] = $this->_decodeUTF8Data($value);
1130
-				}
1131
-			}
1132
-			// If magic quotes is on, then we need to strip the slashes from the
1133
-			// array values because of the parse_str pass which adds slashes
1134
-			if (get_magic_quotes_gpc() == 1) {
1135
-				$newArray = array();
1136
-				foreach ($aArray as $sKey => $sValue) {
1137
-					if (is_string($sValue))
1138
-						$newArray[$sKey] = stripslashes($sValue);
1139
-					else
1140
-						$newArray[$sKey] = $sValue;
1141
-				}
1142
-				$aArray = $newArray;
1143
-			}
1144
-		}
1145
-
1146
-		return $aArray;
1147
-	}
1148
-
1149
-	/**
1150
-	 * Decodes string data from UTF-8 to the current xajax encoding.
1151
-	 *
1152
-	 * @param string data to convert
1153
-	 * @access private
1154
-	 * @return string converted data
1155
-	 */
1156
-	function _decodeUTF8Data($sData)
1157
-	{
1158
-		$sValue = $sData;
1159
-		if ($this->bDecodeUTF8Input)
1160
-		{
1161
-			$sFuncToUse = NULL;
1162
-
1163
-			// An adaptation for the Dokeos LMS, 22-AUG-2009.
1164
-			if (function_exists('api_convert_encoding'))
1165
-			{
1166
-				$sFuncToUse = "api_convert_encoding";
1167
-			}
1168
-			//if (function_exists('iconv'))
1169
-			elseif (function_exists('iconv'))
1170
-			//
1171
-			{
1172
-				$sFuncToUse = "iconv";
1173
-			}
1174
-			else if (function_exists('mb_convert_encoding'))
1175
-			{
1176
-				$sFuncToUse = "mb_convert_encoding";
1177
-			}
1178
-			else if ($this->sEncoding == "ISO-8859-1")
1179
-			{
1180
-				$sFuncToUse = "utf8_decode";
1181
-			}
1182
-			else
1183
-			{
1184
-				trigger_error("The incoming xajax data could not be converted from UTF-8", E_USER_NOTICE);
1185
-			}
1186
-
1187
-			if ($sFuncToUse)
1188
-			{
1189
-				if (is_string($sValue))
1190
-				{
1191
-					if ($sFuncToUse == "iconv")
1192
-					{
1193
-						$sValue = iconv("UTF-8", $this->sEncoding.'//TRANSLIT', $sValue);
1194
-					}
1195
-					else if ($sFuncToUse == "mb_convert_encoding")
1196
-					{
1197
-						$sValue = mb_convert_encoding($sValue, $this->sEncoding, "UTF-8");
1198
-					}
1199
-					// Added code, an adaptation for the Dokeos LMS, 22-AUG-2009.
1200
-					else if ($sFuncToUse == "api_convert_encoding")
1201
-					{
1202
-						$sValue = api_convert_encoding($sValue, $this->sEncoding, "UTF-8");
1203
-					}
1204
-					//
1205
-					else
1206
-					{
1207
-						$sValue = utf8_decode($sValue);
1208
-					}
1209
-				}
1210
-			}
1211
-		}
1212
-		return $sValue;
1213
-	}
78
+    /**
79
+     * @var array Array of PHP functions that will be callable through javascript wrappers
80
+     */
81
+    var $aFunctions;
82
+    /**
83
+     * @var array Array of object callbacks that will allow Javascript to call PHP methods (key=function name)
84
+     */
85
+    var $aObjects;
86
+    /**
87
+     * @var array Array of RequestTypes to be used with each function (key=function name)
88
+     */
89
+    var $aFunctionRequestTypes;
90
+    /**
91
+     * @var array Array of Include Files for any external functions (key=function name)
92
+     */
93
+    var $aFunctionIncludeFiles;
94
+    /**
95
+     * @var string Name of the PHP function to call if no callable function was found
96
+     */
97
+    var $sCatchAllFunction;
98
+    /**
99
+     * @var string Name of the PHP function to call before any other function
100
+     */
101
+    var $sPreFunction;
102
+    /**
103
+     * @var string The URI for making requests to the xajax object
104
+     */
105
+    var $sRequestURI;
106
+    /**
107
+     * @var string The prefix to prepend to the javascript wraper function name
108
+     */
109
+    var $sWrapperPrefix;
110
+    /**
111
+     * @var boolean Show debug messages (default false)
112
+     */
113
+    var $bDebug;
114
+    /**
115
+     * @var boolean Show messages in the client browser's status bar (default false)
116
+     */
117
+    var $bStatusMessages;
118
+    /**
119
+     * @var boolean Allow xajax to exit after processing a request (default true)
120
+     */
121
+    var $bExitAllowed;
122
+    /**
123
+     * @var boolean Use wait cursor in browser (default true)
124
+     */
125
+    var $bWaitCursor;
126
+    /**
127
+     * @var boolean Use an special xajax error handler so the errors are sent to the browser properly (default false)
128
+     */
129
+    var $bErrorHandler;
130
+    /**
131
+     * @var string Specify what, if any, file xajax should log errors to (and more information in a future release)
132
+     */
133
+    var $sLogFile;
134
+    /**
135
+     * @var boolean Clean all output buffers before outputting response (default false)
136
+     */
137
+    var $bCleanBuffer;
138
+    /**
139
+     * @var string String containing the character encoding used
140
+     */
141
+    var $sEncoding;
142
+    /**
143
+     * @var boolean Decode input request args from UTF-8 (default false)
144
+     */
145
+    var $bDecodeUTF8Input;
146
+    /**
147
+     * @var boolean Convert special characters to HTML entities (default false)
148
+     */
149
+    var $bOutputEntities;
150
+    /**
151
+     * @var array Array for parsing complex objects
152
+     */
153
+    var $aObjArray;
154
+    /**
155
+     * @var integer Position in $aObjArray
156
+     */
157
+    var $iPos;
158
+
159
+    /**#@-*/
160
+
161
+    /**
162
+     * Constructor. You can set some extra xajax options right away or use
163
+     * individual methods later to set options.
164
+     *
165
+     * @param string  defaults to the current browser URI
166
+     * @param string  defaults to "xajax_";
167
+     * @param string  defaults to XAJAX_DEFAULT_CHAR_ENCODING defined above
168
+     * @param boolean defaults to false
169
+     */
170
+    function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$sEncoding=XAJAX_DEFAULT_CHAR_ENCODING,$bDebug=false)
171
+    {
172
+        $this->aFunctions = array();
173
+        $this->aObjects = array();
174
+        $this->aFunctionIncludeFiles = array();
175
+        $this->sRequestURI = $sRequestURI;
176
+        if ($this->sRequestURI == "")
177
+            $this->sRequestURI = $this->_detectURI();
178
+        $this->sWrapperPrefix = $sWrapperPrefix;
179
+        $this->bDebug = $bDebug;
180
+        $this->bStatusMessages = false;
181
+        $this->bWaitCursor = true;
182
+        $this->bExitAllowed = true;
183
+        $this->bErrorHandler = false;
184
+        $this->sLogFile = "";
185
+        $this->bCleanBuffer = false;
186
+        $this->setCharEncoding($sEncoding);
187
+        $this->bDecodeUTF8Input = false;
188
+        $this->bOutputEntities = false;
189
+    }
190
+
191
+    /**
192
+     * Sets the URI to which requests will be made.
193
+     * <i>Usage:</i> <kbd>$xajax->setRequestURI("http://www.xajaxproject.org");</kbd>
194
+     *
195
+     * @param string the URI (can be absolute or relative) of the PHP script
196
+     *               that will be accessed when an xajax request occurs
197
+     */
198
+    function setRequestURI($sRequestURI)
199
+    {
200
+        $this->sRequestURI = $sRequestURI;
201
+    }
202
+
203
+    /**
204
+     * Sets the prefix that will be appended to the Javascript wrapper
205
+     * functions (default is "xajax_").
206
+     *
207
+     * @param string
208
+     */
209
+    //
210
+    function setWrapperPrefix($sPrefix)
211
+    {
212
+        $this->sWrapperPrefix = $sPrefix;
213
+    }
214
+
215
+    /**
216
+     * Enables debug messages for xajax.
217
+     * */
218
+    function debugOn()
219
+    {
220
+        $this->bDebug = true;
221
+    }
222
+
223
+    /**
224
+     * Disables debug messages for xajax (default behavior).
225
+     */
226
+    function debugOff()
227
+    {
228
+        $this->bDebug = false;
229
+    }
230
+
231
+    /**
232
+     * Enables messages in the browser's status bar for xajax.
233
+     */
234
+    function statusMessagesOn()
235
+    {
236
+        $this->bStatusMessages = true;
237
+    }
238
+
239
+    /**
240
+     * Disables messages in the browser's status bar for xajax (default behavior).
241
+     */
242
+    function statusMessagesOff()
243
+    {
244
+        $this->bStatusMessages = false;
245
+    }
246
+
247
+    /**
248
+     * Enables the wait cursor to be displayed in the browser (default behavior).
249
+     */
250
+    function waitCursorOn()
251
+    {
252
+        $this->bWaitCursor = true;
253
+    }
254
+
255
+    /**
256
+     * Disables the wait cursor to be displayed in the browser.
257
+     */
258
+    function waitCursorOff()
259
+    {
260
+        $this->bWaitCursor = false;
261
+    }
262
+
263
+    /**
264
+     * Enables xajax to exit immediately after processing a request and
265
+     * sending the response back to the browser (default behavior).
266
+     */
267
+    function exitAllowedOn()
268
+    {
269
+        $this->bExitAllowed = true;
270
+    }
271
+
272
+    /**
273
+     * Disables xajax's default behavior of exiting immediately after
274
+     * processing a request and sending the response back to the browser.
275
+     */
276
+    function exitAllowedOff()
277
+    {
278
+        $this->bExitAllowed = false;
279
+    }
280
+
281
+    /**
282
+     * Turns on xajax's error handling system so that PHP errors that occur
283
+     * during a request are trapped and pushed to the browser in the form of
284
+     * a Javascript alert.
285
+     */
286
+    function errorHandlerOn()
287
+    {
288
+        $this->bErrorHandler = true;
289
+    }
290
+
291
+    /**
292
+     * Turns off xajax's error handling system (default behavior).
293
+     */
294
+    function errorHandlerOff()
295
+    {
296
+        $this->bErrorHandler = false;
297
+    }
298
+
299
+    /**
300
+     * Specifies a log file that will be written to by xajax during a request
301
+     * (used only by the error handling system at present). If you don't invoke
302
+     * this method, or you pass in "", then no log file will be written to.
303
+     * <i>Usage:</i> <kbd>$xajax->setLogFile("/xajax_logs/errors.log");</kbd>
304
+     */
305
+    function setLogFile($sFilename)
306
+    {
307
+        $this->sLogFile = $sFilename;
308
+    }
309
+
310
+    /**
311
+     * Causes xajax to clean out all output buffers before outputting a
312
+     * response (default behavior).
313
+     */
314
+    function cleanBufferOn()
315
+    {
316
+        $this->bCleanBuffer = true;
317
+    }
318
+    /**
319
+     * Turns off xajax's output buffer cleaning.
320
+     */
321
+    function cleanBufferOff()
322
+    {
323
+        $this->bCleanBuffer = false;
324
+    }
325
+
326
+    /**
327
+     * Sets the character encoding for the HTTP output based on
328
+     * <kbd>$sEncoding</kbd>, which is a string containing the character
329
+     * encoding to use. You don't need to use this method normally, since the
330
+     * character encoding for the response gets set automatically based on the
331
+     * <kbd>XAJAX_DEFAULT_CHAR_ENCODING</kbd> constant.
332
+     * <i>Usage:</i> <kbd>$xajax->setCharEncoding("utf-8");</kbd>
333
+     *
334
+     * @param string the encoding type to use (utf-8, iso-8859-1, etc.)
335
+     */
336
+    function setCharEncoding($sEncoding)
337
+    {
338
+        $this->sEncoding = $sEncoding;
339
+    }
340
+
341
+    /**
342
+     * Causes xajax to decode the input request args from UTF-8 to the current
343
+     * encoding if possible. Either the iconv or mb_string extension must be
344
+     * present for optimal functionality.
345
+     */
346
+    function decodeUTF8InputOn()
347
+    {
348
+        $this->bDecodeUTF8Input = true;
349
+    }
350
+
351
+    /**
352
+     * Turns off decoding the input request args from UTF-8 (default behavior).
353
+     */
354
+    function decodeUTF8InputOff()
355
+    {
356
+        $this->bDecodeUTF8Input = false;
357
+    }
358
+
359
+    /**
360
+     * Tells the response object to convert special characters to HTML entities
361
+     * automatically (only works if the mb_string extension is available).
362
+     */
363
+    function outputEntitiesOn()
364
+    {
365
+        $this->bOutputEntities = true;
366
+    }
367
+
368
+    /**
369
+     * Tells the response object to output special characters intact. (default
370
+     * behavior).
371
+     */
372
+    function outputEntitiesOff()
373
+    {
374
+        $this->bOutputEntities = false;
375
+    }
376
+
377
+    /**
378
+     * Registers a PHP function or method to be callable through xajax in your
379
+     * Javascript. If you want to register a function, pass in the name of that
380
+     * function. If you want to register a static class method, pass in an
381
+     * array like so:
382
+     * <kbd>array("myFunctionName", "myClass", "myMethod")</kbd>
383
+     * For an object instance method, use an object variable for the second
384
+     * array element (and in PHP 4 make sure you put an & before the variable
385
+     * to pass the object by reference). Note: the function name is what you
386
+     * call via Javascript, so it can be anything as long as it doesn't
387
+     * conflict with any other registered function name.
388
+     *
389
+     * <i>Usage:</i> <kbd>$xajax->registerFunction("myFunction");</kbd>
390
+     * or: <kbd>$xajax->registerFunction(array("myFunctionName", &$myObject, "myMethod"));</kbd>
391
+     *
392
+     * @param mixed  contains the function name or an object callback array
393
+     * @param mixed  request type (XAJAX_GET/XAJAX_POST) that should be used
394
+     *               for this function.  Defaults to XAJAX_POST.
395
+     */
396
+    function registerFunction($mFunction,$sRequestType=XAJAX_POST)
397
+    {
398
+        if (is_array($mFunction)) {
399
+            $this->aFunctions[$mFunction[0]] = 1;
400
+            $this->aFunctionRequestTypes[$mFunction[0]] = $sRequestType;
401
+            $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
402
+        }
403
+        else {
404
+            $this->aFunctions[$mFunction] = 1;
405
+            $this->aFunctionRequestTypes[$mFunction] = $sRequestType;
406
+        }
407
+    }
408
+
409
+    /**
410
+     * Registers a PHP function to be callable through xajax which is located
411
+     * in some other file.  If the function is requested the external file will
412
+     * be included to define the function before the function is called.
413
+     *
414
+     * <i>Usage:</i> <kbd>$xajax->registerExternalFunction("myFunction","myFunction.inc.php",XAJAX_POST);</kbd>
415
+     *
416
+     * @param string contains the function name or an object callback array
417
+     *               ({@link xajax::registerFunction() see registerFunction} for
418
+     *               more info on object callback arrays)
419
+     * @param string contains the path and filename of the include file
420
+     * @param mixed  the RequestType (XAJAX_GET/XAJAX_POST) that should be used
421
+     *		          for this function. Defaults to XAJAX_POST.
422
+     */
423
+    function registerExternalFunction($mFunction,$sIncludeFile,$sRequestType=XAJAX_POST)
424
+    {
425
+        $this->registerFunction($mFunction, $sRequestType);
426
+
427
+        if (is_array($mFunction)) {
428
+            $this->aFunctionIncludeFiles[$mFunction[0]] = $sIncludeFile;
429
+        }
430
+        else {
431
+            $this->aFunctionIncludeFiles[$mFunction] = $sIncludeFile;
432
+        }
433
+    }
434
+
435
+    /**
436
+     * Registers a PHP function to be called when xajax cannot find the
437
+     * function being called via Javascript. Because this is technically
438
+     * impossible when using "wrapped" functions, the catch-all feature is
439
+     * only useful when you're directly using the xajax.call() Javascript
440
+     * method. Use the catch-all feature when you want more dynamic ability to
441
+     * intercept unknown calls and handle them in a custom way.
442
+     *
443
+     * <i>Usage:</i> <kbd>$xajax->registerCatchAllFunction("myCatchAllFunction");</kbd>
444
+     *
445
+     * @param string contains the function name or an object callback array
446
+     *               ({@link xajax::registerFunction() see registerFunction} for
447
+     *               more info on object callback arrays)
448
+     */
449
+    function registerCatchAllFunction($mFunction)
450
+    {
451
+        if (is_array($mFunction)) {
452
+            $this->sCatchAllFunction = $mFunction[0];
453
+            $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
454
+        }
455
+        else {
456
+            $this->sCatchAllFunction = $mFunction;
457
+        }
458
+    }
459
+
460
+    /**
461
+     * Registers a PHP function to be called before xajax calls the requested
462
+     * function. xajax will automatically add the request function's response
463
+     * to the pre-function's response to create a single response. Another
464
+     * feature is the ability to return not just a response, but an array with
465
+     * the first element being false (a boolean) and the second being the
466
+     * response. In this case, the pre-function's response will be returned to
467
+     * the browser without xajax calling the requested function.
468
+     *
469
+     * <i>Usage:</i> <kbd>$xajax->registerPreFunction("myPreFunction");</kbd>
470
+     *
471
+     * @param string contains the function name or an object callback array
472
+     *               ({@link xajax::registerFunction() see registerFunction} for
473
+     *               more info on object callback arrays)
474
+     */
475
+    function registerPreFunction($mFunction)
476
+    {
477
+        if (is_array($mFunction)) {
478
+            $this->sPreFunction = $mFunction[0];
479
+            $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
480
+        }
481
+        else {
482
+            $this->sPreFunction = $mFunction;
483
+        }
484
+    }
485
+
486
+    /**
487
+     * Returns true if xajax can process the request, false if otherwise.
488
+     * You can use this to determine if xajax needs to process the request or
489
+     * not.
490
+     *
491
+     * @return boolean
492
+     */
493
+    function canProcessRequests()
494
+    {
495
+        if ($this->getRequestMode() != -1) return true;
496
+        return false;
497
+    }
498
+
499
+    /**
500
+     * Returns the current request mode (XAJAX_GET or XAJAX_POST), or -1 if
501
+     * there is none.
502
+     *
503
+     * @return mixed
504
+     */
505
+    function getRequestMode()
506
+    {
507
+        if (!empty($_GET["xajax"]))
508
+            return XAJAX_GET;
509
+
510
+        if (!empty($_POST["xajax"]))
511
+            return XAJAX_POST;
512
+
513
+        return -1;
514
+    }
515
+
516
+    /**
517
+     * This is the main communications engine of xajax. The engine handles all
518
+     * incoming xajax requests, calls the apporiate PHP functions (or
519
+     * class/object methods) and passes the XML responses back to the
520
+     * Javascript response handler. If your RequestURI is the same as your Web
521
+     * page then this function should be called before any headers or HTML has
522
+     * been sent.
523
+     */
524
+    function processRequests()
525
+    {
526
+
527
+        $requestMode = -1;
528
+        $sFunctionName = "";
529
+        $bFoundFunction = true;
530
+        $bFunctionIsCatchAll = false;
531
+        $sFunctionNameForSpecial = "";
532
+        $aArgs = array();
533
+        $sPreResponse = "";
534
+        $bEndRequest = false;
535
+        $sResponse = "";
536
+
537
+        $requestMode = $this->getRequestMode();
538
+        if ($requestMode == -1) return;
539
+
540
+        if ($requestMode == XAJAX_POST)
541
+        {
542
+            $sFunctionName = $_POST["xajax"];
543
+
544
+            if (!empty($_POST["xajaxargs"]))
545
+                $aArgs = $_POST["xajaxargs"];
546
+        }
547
+        else
548
+        {
549
+            header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
550
+            header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
551
+            header ("Cache-Control: no-cache, must-revalidate");
552
+            header ("Pragma: no-cache");
553
+
554
+            $sFunctionName = $_GET["xajax"];
555
+
556
+            if (!empty($_GET["xajaxargs"]))
557
+                $aArgs = $_GET["xajaxargs"];
558
+        }
559
+
560
+        // Use xajax error handler if necessary
561
+        if ($this->bErrorHandler) {
562
+            $GLOBALS['xajaxErrorHandlerText'] = "";
563
+            set_error_handler("xajaxErrorHandler");
564
+        }
565
+
566
+        if ($this->sPreFunction) {
567
+            if (!$this->_isFunctionCallable($this->sPreFunction)) {
568
+                $bFoundFunction = false;
569
+                $objResponse = new xajaxResponse();
570
+                $objResponse->addAlert("Unknown Pre-Function ". $this->sPreFunction);
571
+                $sResponse = $objResponse->getXML();
572
+            }
573
+        }
574
+        //include any external dependencies associated with this function name
575
+        if (array_key_exists($sFunctionName,$this->aFunctionIncludeFiles))
576
+        {
577
+            ob_start();
578
+            include_once($this->aFunctionIncludeFiles[$sFunctionName]);
579
+            ob_end_clean();
580
+        }
581
+
582
+        if ($bFoundFunction) {
583
+            $sFunctionNameForSpecial = $sFunctionName;
584
+            if (!array_key_exists($sFunctionName, $this->aFunctions))
585
+            {
586
+                if ($this->sCatchAllFunction) {
587
+                    $sFunctionName = $this->sCatchAllFunction;
588
+                    $bFunctionIsCatchAll = true;
589
+                }
590
+                else {
591
+                    $bFoundFunction = false;
592
+                    $objResponse = new xajaxResponse();
593
+                    $objResponse->addAlert("Unknown Function $sFunctionName.");
594
+                    $sResponse = $objResponse->getXML();
595
+                }
596
+            }
597
+            else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode)
598
+            {
599
+                $bFoundFunction = false;
600
+                $objResponse = new xajaxResponse();
601
+                $objResponse->addAlert("Incorrect Request Type.");
602
+                $sResponse = $objResponse->getXML();
603
+            }
604
+        }
605
+
606
+        if ($bFoundFunction)
607
+        {
608
+            for ($i = 0; $i < sizeof($aArgs); $i++)
609
+            {
610
+                // If magic quotes is on, then we need to strip the slashes from the args
611
+                if (get_magic_quotes_gpc() == 1 && is_string($aArgs[$i])) {
612
+
613
+                    $aArgs[$i] = stripslashes($aArgs[$i]);
614
+                }
615
+                if (stristr($aArgs[$i],"<xjxobj>") != false)
616
+                {
617
+                    $aArgs[$i] = $this->_xmlToArray("xjxobj",$aArgs[$i]);
618
+                }
619
+                else if (stristr($aArgs[$i],"<xjxquery>") != false)
620
+                {
621
+                    $aArgs[$i] = $this->_xmlToArray("xjxquery",$aArgs[$i]);
622
+                }
623
+                else if ($this->bDecodeUTF8Input)
624
+                {
625
+                    $aArgs[$i] = $this->_decodeUTF8Data($aArgs[$i]);
626
+                }
627
+            }
628
+
629
+            if ($this->sPreFunction) {
630
+                $mPreResponse = $this->_callFunction($this->sPreFunction, array($sFunctionNameForSpecial, $aArgs));
631
+                if (is_array($mPreResponse) && $mPreResponse[0] === false) {
632
+                    $bEndRequest = true;
633
+                    $sPreResponse = $mPreResponse[1];
634
+                }
635
+                else {
636
+                    $sPreResponse = $mPreResponse;
637
+                }
638
+                if (is_a($sPreResponse, "xajaxResponse")) {
639
+                    $sPreResponse = $sPreResponse->getXML();
640
+                }
641
+                if ($bEndRequest) $sResponse = $sPreResponse;
642
+            }
643
+
644
+            if (!$bEndRequest) {
645
+                if (!$this->_isFunctionCallable($sFunctionName)) {
646
+                    $objResponse = new xajaxResponse();
647
+                    $objResponse->addAlert("The Registered Function $sFunctionName Could Not Be Found.");
648
+                    $sResponse = $objResponse->getXML();
649
+                }
650
+                else {
651
+                    if ($bFunctionIsCatchAll) {
652
+                        $aArgs = array($sFunctionNameForSpecial, $aArgs);
653
+                    }
654
+                    $sResponse = $this->_callFunction($sFunctionName, $aArgs);
655
+                }
656
+                if (is_a($sResponse, "xajaxResponse")) {
657
+                    $sResponse = $sResponse->getXML();
658
+                }
659
+                if (!is_string($sResponse) || strpos($sResponse, "<xjx>") === FALSE) {
660
+                    $objResponse = new xajaxResponse();
661
+                    $objResponse->addAlert("No XML Response Was Returned By Function $sFunctionName.");
662
+                    $sResponse = $objResponse->getXML();
663
+                }
664
+                else if ($sPreResponse != "") {
665
+                    $sNewResponse = new xajaxResponse($this->sEncoding, $this->bOutputEntities);
666
+                    $sNewResponse->loadXML($sPreResponse);
667
+                    $sNewResponse->loadXML($sResponse);
668
+                    $sResponse = $sNewResponse->getXML();
669
+                }
670
+            }
671
+        }
672
+
673
+        $sContentHeader = "Content-type: text/xml;";
674
+        if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0)
675
+            $sContentHeader .= " charset=".$this->sEncoding;
676
+        header($sContentHeader);
677
+        if ($this->bErrorHandler && !empty( $GLOBALS['xajaxErrorHandlerText'] )) {
678
+            $sErrorResponse = new xajaxResponse();
679
+            $sErrorResponse->addAlert("** PHP Error Messages: **" . $GLOBALS['xajaxErrorHandlerText']);
680
+            if ($this->sLogFile) {
681
+                $fH = @fopen($this->sLogFile, "a");
682
+                if (!$fH) {
683
+                    $sErrorResponse->addAlert("** Logging Error **\n\nxajax was unable to write to the error log file:\n" . $this->sLogFile);
684
+                }
685
+                else {
686
+                    fwrite($fH, "** xajax Error Log - " . strftime("%b %e %Y %I:%M:%S %p") . " **" . $GLOBALS['xajaxErrorHandlerText'] . "\n\n\n");
687
+                    fclose($fH);
688
+                }
689
+            }
690
+
691
+            $sErrorResponse->loadXML($sResponse);
692
+            $sResponse = $sErrorResponse->getXML();
693
+
694
+        }
695
+        if ($this->bCleanBuffer) while (@ob_end_clean());
696
+        print $sResponse;
697
+        if ($this->bErrorHandler) restore_error_handler();
698
+
699
+        if ($this->bExitAllowed)
700
+            exit();
701
+    }
702
+
703
+    /**
704
+     * Prints the xajax Javascript header and wrapper code into your page by
705
+     * printing the output of the getJavascript() method. It should only be
706
+     * called between the <pre><head> </head></pre> tags in your HTML page.
707
+     * Remember, if you only want to obtain the result of this function, use
708
+     * {@link xajax::getJavascript()} instead.
709
+     *
710
+     * <i>Usage:</i>
711
+     * <code>
712
+     *  <head>
713
+     *		...
714
+     *		< ?php $xajax->printJavascript(); ? >
715
+     * </code>
716
+     *
717
+     * @param string the relative address of the folder where xajax has been
718
+     *               installed. For instance, if your PHP file is
719
+     *               "http://www.myserver.com/myfolder/mypage.php"
720
+     *               and xajax was installed in
721
+     *               "http://www.myserver.com/anotherfolder", then $sJsURI
722
+     *               should be set to "../anotherfolder". Defaults to assuming
723
+     *               xajax is in the same folder as your PHP file.
724
+     * @param string the relative folder/file pair of the xajax Javascript
725
+     *               engine located within the xajax installation folder.
726
+     *               Defaults to xajax_js/xajax.js.
727
+     */
728
+    function printJavascript($sJsURI="", $sJsFile=NULL)
729
+    {
730
+        print $this->getJavascript($sJsURI, $sJsFile);
731
+    }
732
+
733
+    /**
734
+     * Returns the xajax Javascript code that should be added to your HTML page
735
+     * between the <kbd><head> </head></kbd> tags.
736
+     *
737
+     * <i>Usage:</i>
738
+     * <code>
739
+     *  < ?php $xajaxJSHead = $xajax->getJavascript(); ? >
740
+     *	<head>
741
+     *		...
742
+     *		< ?php echo $xajaxJSHead; ? >
743
+     * </code>
744
+     *
745
+     * @param string the relative address of the folder where xajax has been
746
+     *               installed. For instance, if your PHP file is
747
+     *               "http://www.myserver.com/myfolder/mypage.php"
748
+     *               and xajax was installed in
749
+     *               "http://www.myserver.com/anotherfolder", then $sJsURI
750
+     *               should be set to "../anotherfolder". Defaults to assuming
751
+     *               xajax is in the same folder as your PHP file.
752
+     * @param string the relative folder/file pair of the xajax Javascript
753
+     *               engine located within the xajax installation folder.
754
+     *               Defaults to xajax_js/xajax.js.
755
+     * @return string
756
+     */
757
+    function getJavascript($sJsURI="", $sJsFile=NULL)
758
+    {
759
+        $html = $this->getJavascriptConfig();
760
+        $html .= $this->getJavascriptInclude($sJsURI, $sJsFile);
761
+
762
+        return $html;
763
+    }
764
+
765
+    /**
766
+     * Returns a string containing inline Javascript that sets up the xajax
767
+     * runtime (typically called internally by xajax from get/printJavascript).
768
+     *
769
+     * @return string
770
+     */
771
+    function getJavascriptConfig()
772
+    {
773
+        $html  = "\t<script type=\"text/javascript\">\n";
774
+        $html .= "var xajaxRequestUri=\"".$this->sRequestURI."\";\n";
775
+        $html .= "var xajaxDebug=".($this->bDebug?"true":"false").";\n";
776
+        $html .= "var xajaxStatusMessages=".($this->bStatusMessages?"true":"false").";\n";
777
+        $html .= "var xajaxWaitCursor=".($this->bWaitCursor?"true":"false").";\n";
778
+        $html .= "var xajaxDefinedGet=".XAJAX_GET.";\n";
779
+        $html .= "var xajaxDefinedPost=".XAJAX_POST.";\n";
780
+        $html .= "var xajaxLoaded=false;\n";
781
+
782
+        foreach($this->aFunctions as $sFunction => $bExists) {
783
+            $html .= $this->_wrap($sFunction,$this->aFunctionRequestTypes[$sFunction]);
784
+        }
785
+
786
+        $html .= "\t</script>\n";
787
+        return $html;
788
+    }
789
+
790
+    /**
791
+     * Returns a string containing a Javascript include of the xajax.js file
792
+     * along with a check to see if the file loaded after six seconds
793
+     * (typically called internally by xajax from get/printJavascript).
794
+     *
795
+     * @param string the relative address of the folder where xajax has been
796
+     *               installed. For instance, if your PHP file is
797
+     *               "http://www.myserver.com/myfolder/mypage.php"
798
+     *               and xajax was installed in
799
+     *               "http://www.myserver.com/anotherfolder", then $sJsURI
800
+     *               should be set to "../anotherfolder". Defaults to assuming
801
+     *               xajax is in the same folder as your PHP file.
802
+     * @param string the relative folder/file pair of the xajax Javascript
803
+     *               engine located within the xajax installation folder.
804
+     *               Defaults to xajax_js/xajax.js.
805
+     * @return string
806
+     */
807
+    function getJavascriptInclude($sJsURI="", $sJsFile=NULL)
808
+    {
809
+        if ($sJsFile == NULL) $sJsFile = "xajax_js/xajax.js";
810
+
811
+        if ($sJsURI != "" && substr($sJsURI, -1) != "/") $sJsURI .= "/";
812
+
813
+        $html = "\t<script type=\"text/javascript\" src=\"" . $sJsURI . $sJsFile . "\"></script>\n";
814
+        $html .= "\t<script type=\"text/javascript\">\n";
815
+        $html .= "window.setTimeout(function () { if (!xajaxLoaded) { alert('Error: the xajax Javascript file could not be included. Perhaps the URL is incorrect?\\nURL: {$sJsURI}{$sJsFile}'); } }, 6000);\n";
816
+        $html .= "\t</script>\n";
817
+        return $html;
818
+    }
819
+
820
+    /**
821
+     * This method can be used to create a new xajax.js file out of the
822
+     * xajax_uncompressed.js file (which will only happen if xajax.js doesn't
823
+     * already exist on the filesystem).
824
+     *
825
+     * @param string an optional argument containing the full server file path
826
+     *               of xajax.js.
827
+     */
828
+    function autoCompressJavascript($sJsFullFilename=NULL)
829
+    {
830
+        $sJsFile = "xajax_js/xajax.js";
831
+
832
+        if ($sJsFullFilename) {
833
+            $realJsFile = $sJsFullFilename;
834
+        }
835
+        else {
836
+            $realPath = realpath(dirname(__FILE__));
837
+            $realJsFile = $realPath . "/". $sJsFile;
838
+        }
839
+
840
+        // Create a compressed file if necessary
841
+        if (!file_exists($realJsFile)) {
842
+            $srcFile = str_replace(".js", "_uncompressed.js", $realJsFile);
843
+            if (!file_exists($srcFile)) {
844
+                trigger_error("The xajax uncompressed Javascript file could not be found in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
845
+            }
846
+            require(dirname(__FILE__)."/xajaxCompress.php");
847
+            $javaScript = implode('', file($srcFile));
848
+            $compressedScript = xajaxCompressJavascript($javaScript);
849
+            $fH = @fopen($realJsFile, "w");
850
+            if (!$fH) {
851
+                trigger_error("The xajax compressed javascript file could not be written in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
852
+            }
853
+            else {
854
+                fwrite($fH, $compressedScript);
855
+                fclose($fH);
856
+            }
857
+        }
858
+    }
859
+
860
+    /**
861
+     * Returns the current URL based upon the SERVER vars.
862
+     *
863
+     * @access private
864
+     * @return string
865
+     */
866
+    function _detectURI() {
867
+        $aURL = array();
868
+
869
+        // Try to get the request URL
870
+        if (!empty($_SERVER['REQUEST_URI'])) {
871
+            $aURL = parse_url($_SERVER['REQUEST_URI']);
872
+        }
873
+
874
+        // Fill in the empty values
875
+        if (empty($aURL['scheme'])) {
876
+            if (!empty($_SERVER['HTTP_SCHEME'])) {
877
+                $aURL['scheme'] = $_SERVER['HTTP_SCHEME'];
878
+            } else {
879
+                $aURL['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http';
880
+            }
881
+        }
882
+
883
+        if (empty($aURL['host'])) {
884
+            if (!empty($_SERVER['HTTP_HOST'])) {
885
+                if (strpos($_SERVER['HTTP_HOST'], ':') > 0) {
886
+                    list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_HOST']);
887
+                } else {
888
+                    $aURL['host'] = $_SERVER['HTTP_HOST'];
889
+                }
890
+            } else if (!empty($_SERVER['SERVER_NAME'])) {
891
+                $aURL['host'] = $_SERVER['SERVER_NAME'];
892
+            } else {
893
+                print "xajax Error: xajax failed to automatically identify your Request URI.";
894
+                print "Please set the Request URI explicitly when you instantiate the xajax object.";
895
+                exit();
896
+            }
897
+        }
898
+
899
+        if (empty($aURL['port']) && !empty($_SERVER['SERVER_PORT'])) {
900
+            $aURL['port'] = $_SERVER['SERVER_PORT'];
901
+        }
902
+
903
+        if (empty($aURL['path'])) {
904
+            if (!empty($_SERVER['PATH_INFO'])) {
905
+                $sPath = parse_url($_SERVER['PATH_INFO']);
906
+            } else {
907
+                $sPath = parse_url(api_get_self());
908
+            }
909
+            $aURL['path'] = $sPath['path'];
910
+            unset($sPath);
911
+        }
912
+
913
+        if (!empty($aURL['query'])) {
914
+            $aURL['query'] = '?'.$aURL['query'];
915
+        }
916
+
917
+        // Build the URL: Start with scheme, user and pass
918
+        $sURL = $aURL['scheme'].'://';
919
+        if (!empty($aURL['user'])) {
920
+            $sURL.= $aURL['user'];
921
+            if (!empty($aURL['pass'])) {
922
+                $sURL.= ':'.$aURL['pass'];
923
+            }
924
+            $sURL.= '@';
925
+        }
926
+
927
+        // Add the host
928
+        $sURL.= $aURL['host'];
929
+
930
+        // Add the port if needed
931
+        if (!empty($aURL['port']) && (($aURL['scheme'] == 'http' && $aURL['port'] != 80) || ($aURL['scheme'] == 'https' && $aURL['port'] != 443))) {
932
+            $sURL.= ':'.$aURL['port'];
933
+        }
934
+
935
+        // Add the path and the query string
936
+        $sURL.= $aURL['path'].@$aURL['query'];
937
+
938
+        // Clean up
939
+        unset($aURL);
940
+        return $sURL;
941
+    }
942
+
943
+    /**
944
+     * Returns true if the function name is associated with an object callback,
945
+     * false if not.
946
+     *
947
+     * @param string the name of the function
948
+     * @access private
949
+     * @return boolean
950
+     */
951
+    function _isObjectCallback($sFunction)
952
+    {
953
+        if (array_key_exists($sFunction, $this->aObjects)) return true;
954
+        return false;
955
+    }
956
+
957
+    /**
958
+     * Returns true if the function or object callback can be called, false if
959
+     * not.
960
+     *
961
+     * @param string the name of the function
962
+     * @access private
963
+     * @return boolean
964
+     */
965
+    function _isFunctionCallable($sFunction)
966
+    {
967
+        if ($this->_isObjectCallback($sFunction)) {
968
+            if (is_object($this->aObjects[$sFunction][0])) {
969
+                return method_exists($this->aObjects[$sFunction][0], $this->aObjects[$sFunction][1]);
970
+            }
971
+            else {
972
+                return is_callable($this->aObjects[$sFunction]);
973
+            }
974
+        }
975
+        else {
976
+            return function_exists($sFunction);
977
+        }
978
+    }
979
+
980
+    /**
981
+     * Calls the function, class method, or object method with the supplied
982
+     * arguments.
983
+     *
984
+     * @param string the name of the function
985
+     * @param array  arguments to pass to the function
986
+     * @access private
987
+     * @return mixed the output of the called function or method
988
+     */
989
+    function _callFunction($sFunction, $aArgs)
990
+    {
991
+        if ($this->_isObjectCallback($sFunction)) {
992
+            $mReturn = call_user_func_array($this->aObjects[$sFunction], $aArgs);
993
+        }
994
+        else {
995
+            $mReturn = call_user_func_array($sFunction, $aArgs);
996
+        }
997
+        return $mReturn;
998
+    }
999
+
1000
+    /**
1001
+     * Generates the Javascript wrapper for the specified PHP function.
1002
+     *
1003
+     * @param string the name of the function
1004
+     * @param mixed  the request type
1005
+     * @access private
1006
+     * @return string
1007
+     */
1008
+    function _wrap($sFunction,$sRequestType=XAJAX_POST)
1009
+    {
1010
+        $js = "function ".$this->sWrapperPrefix."$sFunction(){return xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n";
1011
+        return $js;
1012
+    }
1013
+
1014
+    /**
1015
+     * Takes a string containing xajax xjxobj XML or xjxquery XML and builds an
1016
+     * array representation of it to pass as an argument to the PHP function
1017
+     * being called.
1018
+     *
1019
+     * @param string the root tag of the XML
1020
+     * @param string XML to convert
1021
+     * @access private
1022
+     * @return array
1023
+     */
1024
+    function _xmlToArray($rootTag, $sXml)
1025
+    {
1026
+        $aArray = array();
1027
+        $sXml = str_replace("<$rootTag>","<$rootTag>|~|",$sXml);
1028
+        $sXml = str_replace("</$rootTag>","</$rootTag>|~|",$sXml);
1029
+        $sXml = str_replace("<e>","<e>|~|",$sXml);
1030
+        $sXml = str_replace("</e>","</e>|~|",$sXml);
1031
+        $sXml = str_replace("<k>","<k>|~|",$sXml);
1032
+        $sXml = str_replace("</k>","|~|</k>|~|",$sXml);
1033
+        $sXml = str_replace("<v>","<v>|~|",$sXml);
1034
+        $sXml = str_replace("</v>","|~|</v>|~|",$sXml);
1035
+        $sXml = str_replace("<q>","<q>|~|",$sXml);
1036
+        $sXml = str_replace("</q>","|~|</q>|~|",$sXml);
1037
+
1038
+        $this->aObjArray = explode("|~|",$sXml);
1039
+
1040
+        $this->iPos = 0;
1041
+        $aArray = $this->_parseObjXml($rootTag);
1042
+
1043
+        return $aArray;
1044
+    }
1045
+
1046
+    /**
1047
+     * A recursive function that generates an array from the contents of
1048
+     * $this->aObjArray.
1049
+     *
1050
+     * @param string the root tag of the XML
1051
+     * @access private
1052
+     * @return array
1053
+     */
1054
+    function _parseObjXml($rootTag)
1055
+    {
1056
+        $aArray = array();
1057
+
1058
+        if ($rootTag == "xjxobj")
1059
+        {
1060
+            while(!stristr($this->aObjArray[$this->iPos],"</xjxobj>"))
1061
+            {
1062
+                $this->iPos++;
1063
+                if(stristr($this->aObjArray[$this->iPos],"<e>"))
1064
+                {
1065
+                    $key = "";
1066
+                    $value = null;
1067
+
1068
+                    $this->iPos++;
1069
+                    while(!stristr($this->aObjArray[$this->iPos],"</e>"))
1070
+                    {
1071
+                        if(stristr($this->aObjArray[$this->iPos],"<k>"))
1072
+                        {
1073
+                            $this->iPos++;
1074
+                            while(!stristr($this->aObjArray[$this->iPos],"</k>"))
1075
+                            {
1076
+                                $key .= $this->aObjArray[$this->iPos];
1077
+                                $this->iPos++;
1078
+                            }
1079
+                        }
1080
+                        if(stristr($this->aObjArray[$this->iPos],"<v>"))
1081
+                        {
1082
+                            $this->iPos++;
1083
+                            while(!stristr($this->aObjArray[$this->iPos],"</v>"))
1084
+                            {
1085
+                                if(stristr($this->aObjArray[$this->iPos],"<xjxobj>"))
1086
+                                {
1087
+                                    $value = $this->_parseObjXml("xjxobj");
1088
+                                    $this->iPos++;
1089
+                                }
1090
+                                else
1091
+                                {
1092
+                                    $value .= $this->aObjArray[$this->iPos];
1093
+                                    if ($this->bDecodeUTF8Input)
1094
+                                    {
1095
+                                        $value = $this->_decodeUTF8Data($value);
1096
+                                    }
1097
+                                }
1098
+                                $this->iPos++;
1099
+                            }
1100
+                        }
1101
+                        $this->iPos++;
1102
+                    }
1103
+
1104
+                    $aArray[$key]=$value;
1105
+                }
1106
+            }
1107
+        }
1108
+
1109
+        if ($rootTag == "xjxquery")
1110
+        {
1111
+            $sQuery = "";
1112
+            $this->iPos++;
1113
+            while(!stristr($this->aObjArray[$this->iPos],"</xjxquery>"))
1114
+            {
1115
+                if (stristr($this->aObjArray[$this->iPos],"<q>") || stristr($this->aObjArray[$this->iPos],"</q>"))
1116
+                {
1117
+                    $this->iPos++;
1118
+                    continue;
1119
+                }
1120
+                $sQuery	.= $this->aObjArray[$this->iPos];
1121
+                $this->iPos++;
1122
+            }
1123
+
1124
+            parse_str($sQuery, $aArray);
1125
+            if ($this->bDecodeUTF8Input)
1126
+            {
1127
+                foreach($aArray as $key => $value)
1128
+                {
1129
+                    $aArray[$key] = $this->_decodeUTF8Data($value);
1130
+                }
1131
+            }
1132
+            // If magic quotes is on, then we need to strip the slashes from the
1133
+            // array values because of the parse_str pass which adds slashes
1134
+            if (get_magic_quotes_gpc() == 1) {
1135
+                $newArray = array();
1136
+                foreach ($aArray as $sKey => $sValue) {
1137
+                    if (is_string($sValue))
1138
+                        $newArray[$sKey] = stripslashes($sValue);
1139
+                    else
1140
+                        $newArray[$sKey] = $sValue;
1141
+                }
1142
+                $aArray = $newArray;
1143
+            }
1144
+        }
1145
+
1146
+        return $aArray;
1147
+    }
1148
+
1149
+    /**
1150
+     * Decodes string data from UTF-8 to the current xajax encoding.
1151
+     *
1152
+     * @param string data to convert
1153
+     * @access private
1154
+     * @return string converted data
1155
+     */
1156
+    function _decodeUTF8Data($sData)
1157
+    {
1158
+        $sValue = $sData;
1159
+        if ($this->bDecodeUTF8Input)
1160
+        {
1161
+            $sFuncToUse = NULL;
1162
+
1163
+            // An adaptation for the Dokeos LMS, 22-AUG-2009.
1164
+            if (function_exists('api_convert_encoding'))
1165
+            {
1166
+                $sFuncToUse = "api_convert_encoding";
1167
+            }
1168
+            //if (function_exists('iconv'))
1169
+            elseif (function_exists('iconv'))
1170
+            //
1171
+            {
1172
+                $sFuncToUse = "iconv";
1173
+            }
1174
+            else if (function_exists('mb_convert_encoding'))
1175
+            {
1176
+                $sFuncToUse = "mb_convert_encoding";
1177
+            }
1178
+            else if ($this->sEncoding == "ISO-8859-1")
1179
+            {
1180
+                $sFuncToUse = "utf8_decode";
1181
+            }
1182
+            else
1183
+            {
1184
+                trigger_error("The incoming xajax data could not be converted from UTF-8", E_USER_NOTICE);
1185
+            }
1186
+
1187
+            if ($sFuncToUse)
1188
+            {
1189
+                if (is_string($sValue))
1190
+                {
1191
+                    if ($sFuncToUse == "iconv")
1192
+                    {
1193
+                        $sValue = iconv("UTF-8", $this->sEncoding.'//TRANSLIT', $sValue);
1194
+                    }
1195
+                    else if ($sFuncToUse == "mb_convert_encoding")
1196
+                    {
1197
+                        $sValue = mb_convert_encoding($sValue, $this->sEncoding, "UTF-8");
1198
+                    }
1199
+                    // Added code, an adaptation for the Dokeos LMS, 22-AUG-2009.
1200
+                    else if ($sFuncToUse == "api_convert_encoding")
1201
+                    {
1202
+                        $sValue = api_convert_encoding($sValue, $this->sEncoding, "UTF-8");
1203
+                    }
1204
+                    //
1205
+                    else
1206
+                    {
1207
+                        $sValue = utf8_decode($sValue);
1208
+                    }
1209
+                }
1210
+            }
1211
+        }
1212
+        return $sValue;
1213
+    }
1214 1214
 
1215 1215
 }// end class xajax
1216 1216
 
@@ -1220,31 +1220,31 @@  discard block
 block discarded – undo
1220 1220
  */
1221 1221
 function xajaxErrorHandler($errno, $errstr, $errfile, $errline)
1222 1222
 {
1223
-	$errorReporting = error_reporting();
1224
-	if (($errno & $errorReporting) == 0) return;
1225
-
1226
-	if ($errno == E_NOTICE) {
1227
-		$errTypeStr = "NOTICE";
1228
-	}
1229
-	else if ($errno == E_WARNING) {
1230
-		$errTypeStr = "WARNING";
1231
-	}
1232
-	else if ($errno == E_USER_NOTICE) {
1233
-		$errTypeStr = "USER NOTICE";
1234
-	}
1235
-	else if ($errno == E_USER_WARNING) {
1236
-		$errTypeStr = "USER WARNING";
1237
-	}
1238
-	else if ($errno == E_USER_ERROR) {
1239
-		$errTypeStr = "USER FATAL ERROR";
1240
-	}
1241
-	else if ($errno == E_STRICT) {
1242
-		return;
1243
-	}
1244
-	else {
1245
-		$errTypeStr = "UNKNOWN: $errno";
1246
-	}
1247
-	$GLOBALS['xajaxErrorHandlerText'] .= "\n----\n[$errTypeStr] $errstr\nerror in line $errline of file $errfile";
1223
+    $errorReporting = error_reporting();
1224
+    if (($errno & $errorReporting) == 0) return;
1225
+
1226
+    if ($errno == E_NOTICE) {
1227
+        $errTypeStr = "NOTICE";
1228
+    }
1229
+    else if ($errno == E_WARNING) {
1230
+        $errTypeStr = "WARNING";
1231
+    }
1232
+    else if ($errno == E_USER_NOTICE) {
1233
+        $errTypeStr = "USER NOTICE";
1234
+    }
1235
+    else if ($errno == E_USER_WARNING) {
1236
+        $errTypeStr = "USER WARNING";
1237
+    }
1238
+    else if ($errno == E_USER_ERROR) {
1239
+        $errTypeStr = "USER FATAL ERROR";
1240
+    }
1241
+    else if ($errno == E_STRICT) {
1242
+        return;
1243
+    }
1244
+    else {
1245
+        $errTypeStr = "UNKNOWN: $errno";
1246
+    }
1247
+    $GLOBALS['xajaxErrorHandlerText'] .= "\n----\n[$errTypeStr] $errstr\nerror in line $errline of file $errfile";
1248 1248
 }
1249 1249
 
1250 1250
 ?>
Please login to merge, or discard this patch.
main/inc/lib/xajax/xajaxResponse.inc.php 1 patch
Indentation   +512 added lines, -512 removed lines patch added patch discarded remove patch
@@ -67,521 +67,521 @@
 block discarded – undo
67 67
  */
68 68
 class xajaxResponse
69 69
 {
70
-	/**#@+
70
+    /**#@+
71 71
 	 * @access protected
72 72
 	 */
73
-	/**
74
-	 * @var string internal XML storage
75
-	 */
76
-	var $xml;
77
-	/**
78
-	 * @var string the encoding type to use
79
-	 */
80
-	var $sEncoding;
81
-	/**
82
-	 * @var boolean if special characters in the XML should be converted to
83
-	 *              entities
84
-	 */
85
-	var $bOutputEntities;
86
-
87
-	/**#@-*/
88
-
89
-	/**
90
-	 * The constructor's main job is to set the character encoding for the
91
-	 * response.
92
-	 *
93
-	 * <i>Note:</i> to change the character encoding for all of the
94
-	 * responses, set the XAJAX_DEFAULT_ENCODING constant before you
95
-	 * instantiate xajax.
96
-	 *
97
-	 * @param string  contains the character encoding string to use
98
-	 * @param boolean lets you set if you want special characters in the output
99
-	 *                converted to HTML entities
100
-	 *
101
-	 */
102
-	function xajaxResponse($sEncoding=XAJAX_DEFAULT_CHAR_ENCODING, $bOutputEntities=false)
103
-	{
104
-		$this->setCharEncoding($sEncoding);
105
-		$this->bOutputEntities = $bOutputEntities;
106
-	}
107
-
108
-	/**
109
-	 * Sets the character encoding for the response based on $sEncoding, which
110
-	 * is a string containing the character encoding to use. You don't need to
111
-	 * use this method normally, since the character encoding for the response
112
-	 * gets set automatically based on the XAJAX_DEFAULT_CHAR_ENCODING
113
-	 * constant.
114
-	 *
115
-	 * @param string
116
-	 */
117
-	function setCharEncoding($sEncoding)
118
-	{
119
-		$this->sEncoding = $sEncoding;
120
-	}
121
-
122
-	/**
123
-	 * Tells the response object to convert special characters to HTML entities
124
-	 * automatically (only works if the mb_string extension is available).
125
-	 */
126
-	function outputEntitiesOn()
127
-	{
128
-		$this->bOutputEntities = true;
129
-	}
130
-
131
-	/**
132
-	 * Tells the response object to output special characters intact. (default
133
-	 * behavior)
134
-	 */
135
-	function outputEntitiesOff()
136
-	{
137
-		$this->bOutputEntities = false;
138
-	}
139
-
140
-	/**
141
-	 * Adds a confirm commands command message to the XML response.
142
-	 *
143
-	 * <i>Usage:</i> <kbd>$objResponse->addConfirmCommands(1, "Do you want to preview the new data?");</kbd>
144
-	 *
145
-	 * @param integer the number of commands to skip if the user presses
146
-	 *                Cancel in the browsers's confirm dialog
147
-	 * @param string  the message to show in the browser's confirm dialog
148
-	 */
149
-	function addConfirmCommands($iCmdNumber, $sMessage)
150
-	{
151
-		$this->xml .= $this->_cmdXML(array("n"=>"cc","t"=>$iCmdNumber),$sMessage);
152
-	}
153
-
154
-	/**
155
-	 * Adds an assign command message to the XML response.
156
-	 *
157
-	 * <i>Usage:</i> <kbd>$objResponse->addAssign("contentDiv", "innerHTML", "Some Text");</kbd>
158
-	 *
159
-	 * @param string contains the id of an HTML element
160
-	 * @param string the part of the element you wish to modify ("innerHTML",
161
-	 *               "value", etc.)
162
-	 * @param string the data you want to set the attribute to
163
-	 */
164
-	function addAssign($sTarget,$sAttribute,$sData)
165
-	{
166
-		$this->xml .= $this->_cmdXML(array("n"=>"as","t"=>$sTarget,"p"=>$sAttribute),$sData);
167
-	}
168
-
169
-	/**
170
-	 * Adds an append command message to the XML response.
171
-	 *
172
-	 * <i>Usage:</i> <kbd>$objResponse->addAppend("contentDiv", "innerHTML", "Some New Text");</kbd>
173
-	 *
174
-	 * @param string contains the id of an HTML element
175
-	 * @param string the part of the element you wish to modify ("innerHTML",
176
-	 *               "value", etc.)
177
-	 * @param string the data you want to append to the end of the attribute
178
-	 */
179
-	function addAppend($sTarget,$sAttribute,$sData)
180
-	{
181
-		$this->xml .= $this->_cmdXML(array("n"=>"ap","t"=>$sTarget,"p"=>$sAttribute),$sData);
182
-	}
183
-
184
-	/**
185
-	 * Adds an prepend command message to the XML response.
186
-	 *
187
-	 * <i>Usage:</i> <kbd>$objResponse->addPrepend("contentDiv", "innerHTML", "Some Starting Text");</kbd>
188
-	 *
189
-	 * @param string contains the id of an HTML element
190
-	 * @param string the part of the element you wish to modify ("innerHTML",
191
-	 *               "value", etc.)
192
-	 * @param string the data you want to prepend to the beginning of the
193
-	 *               attribute
194
-	 */
195
-	function addPrepend($sTarget,$sAttribute,$sData)
196
-	{
197
-		$this->xml .= $this->_cmdXML(array("n"=>"pp","t"=>$sTarget,"p"=>$sAttribute),$sData);
198
-	}
199
-
200
-	/**
201
-	 * Adds a replace command message to the XML response.
202
-	 *
203
-	 * <i>Usage:</i> <kbd>$objResponse->addReplace("contentDiv", "innerHTML", "text", "<b>text</b>");</kbd>
204
-	 *
205
-	 * @param string contains the id of an HTML element
206
-	 * @param string the part of the element you wish to modify ("innerHTML",
207
-	 *               "value", etc.)
208
-	 * @param string the string to search for
209
-	 * @param string the string to replace the search string when found in the
210
-	 *               attribute
211
-	 */
212
-	function addReplace($sTarget,$sAttribute,$sSearch,$sData)
213
-	{
214
-		$sDta = "<s><![CDATA[$sSearch]]></s><r><![CDATA[$sData]]></r>";
215
-		$this->xml .= $this->_cmdXML(array("n"=>"rp","t"=>$sTarget,"p"=>$sAttribute),$sDta);
216
-	}
217
-
218
-	/**
219
-	 * Adds a clear command message to the XML response.
220
-	 *
221
-	 * <i>Usage:</i> <kbd>$objResponse->addClear("contentDiv", "innerHTML");</kbd>
222
-	 *
223
-	 * @param string contains the id of an HTML element
224
-	 * @param string the part of the element you wish to clear ("innerHTML",
225
-	 *               "value", etc.)
226
-	 */
227
-	function addClear($sTarget,$sAttribute)
228
-	{
229
-		$this->addAssign($sTarget,$sAttribute,'');
230
-	}
231
-
232
-	/**
233
-	 * Adds an alert command message to the XML response.
234
-	 *
235
-	 * <i>Usage:</i> <kbd>$objResponse->addAlert("This is important information");</kbd>
236
-	 *
237
-	 * @param string the text to be displayed in the Javascript alert box
238
-	 */
239
-	function addAlert($sMsg)
240
-	{
241
-		$this->xml .= $this->_cmdXML(array("n"=>"al"),$sMsg);
242
-	}
243
-
244
-	/**
245
-	 * Uses the addScript() method to add a Javascript redirect to another URL.
246
-	 *
247
-	 * <i>Usage:</i> <kbd>$objResponse->addRedirect("http://www.xajaxproject.org");</kbd>
248
-	 *
249
-	 * @param string the URL to redirect the client browser to
250
-	 */
251
-	function addRedirect($sURL)
252
-	{
253
-		//we need to parse the query part so that the values are rawurlencode()'ed
254
-		//can't just use parse_url() cos we could be dealing with a relative URL which
255
-		//  parse_url() can't deal with.
256
-		$queryStart = strpos($sURL, '?', strrpos($sURL, '/'));
257
-		if ($queryStart !== FALSE)
258
-		{
259
-			$queryStart++;
260
-			$queryEnd = strpos($sURL, '#', $queryStart);
261
-			if ($queryEnd === FALSE)
262
-				$queryEnd = strlen($sURL);
263
-			$queryPart = substr($sURL, $queryStart, $queryEnd-$queryStart);
73
+    /**
74
+     * @var string internal XML storage
75
+     */
76
+    var $xml;
77
+    /**
78
+     * @var string the encoding type to use
79
+     */
80
+    var $sEncoding;
81
+    /**
82
+     * @var boolean if special characters in the XML should be converted to
83
+     *              entities
84
+     */
85
+    var $bOutputEntities;
86
+
87
+    /**#@-*/
88
+
89
+    /**
90
+     * The constructor's main job is to set the character encoding for the
91
+     * response.
92
+     *
93
+     * <i>Note:</i> to change the character encoding for all of the
94
+     * responses, set the XAJAX_DEFAULT_ENCODING constant before you
95
+     * instantiate xajax.
96
+     *
97
+     * @param string  contains the character encoding string to use
98
+     * @param boolean lets you set if you want special characters in the output
99
+     *                converted to HTML entities
100
+     *
101
+     */
102
+    function xajaxResponse($sEncoding=XAJAX_DEFAULT_CHAR_ENCODING, $bOutputEntities=false)
103
+    {
104
+        $this->setCharEncoding($sEncoding);
105
+        $this->bOutputEntities = $bOutputEntities;
106
+    }
107
+
108
+    /**
109
+     * Sets the character encoding for the response based on $sEncoding, which
110
+     * is a string containing the character encoding to use. You don't need to
111
+     * use this method normally, since the character encoding for the response
112
+     * gets set automatically based on the XAJAX_DEFAULT_CHAR_ENCODING
113
+     * constant.
114
+     *
115
+     * @param string
116
+     */
117
+    function setCharEncoding($sEncoding)
118
+    {
119
+        $this->sEncoding = $sEncoding;
120
+    }
121
+
122
+    /**
123
+     * Tells the response object to convert special characters to HTML entities
124
+     * automatically (only works if the mb_string extension is available).
125
+     */
126
+    function outputEntitiesOn()
127
+    {
128
+        $this->bOutputEntities = true;
129
+    }
130
+
131
+    /**
132
+     * Tells the response object to output special characters intact. (default
133
+     * behavior)
134
+     */
135
+    function outputEntitiesOff()
136
+    {
137
+        $this->bOutputEntities = false;
138
+    }
139
+
140
+    /**
141
+     * Adds a confirm commands command message to the XML response.
142
+     *
143
+     * <i>Usage:</i> <kbd>$objResponse->addConfirmCommands(1, "Do you want to preview the new data?");</kbd>
144
+     *
145
+     * @param integer the number of commands to skip if the user presses
146
+     *                Cancel in the browsers's confirm dialog
147
+     * @param string  the message to show in the browser's confirm dialog
148
+     */
149
+    function addConfirmCommands($iCmdNumber, $sMessage)
150
+    {
151
+        $this->xml .= $this->_cmdXML(array("n"=>"cc","t"=>$iCmdNumber),$sMessage);
152
+    }
153
+
154
+    /**
155
+     * Adds an assign command message to the XML response.
156
+     *
157
+     * <i>Usage:</i> <kbd>$objResponse->addAssign("contentDiv", "innerHTML", "Some Text");</kbd>
158
+     *
159
+     * @param string contains the id of an HTML element
160
+     * @param string the part of the element you wish to modify ("innerHTML",
161
+     *               "value", etc.)
162
+     * @param string the data you want to set the attribute to
163
+     */
164
+    function addAssign($sTarget,$sAttribute,$sData)
165
+    {
166
+        $this->xml .= $this->_cmdXML(array("n"=>"as","t"=>$sTarget,"p"=>$sAttribute),$sData);
167
+    }
168
+
169
+    /**
170
+     * Adds an append command message to the XML response.
171
+     *
172
+     * <i>Usage:</i> <kbd>$objResponse->addAppend("contentDiv", "innerHTML", "Some New Text");</kbd>
173
+     *
174
+     * @param string contains the id of an HTML element
175
+     * @param string the part of the element you wish to modify ("innerHTML",
176
+     *               "value", etc.)
177
+     * @param string the data you want to append to the end of the attribute
178
+     */
179
+    function addAppend($sTarget,$sAttribute,$sData)
180
+    {
181
+        $this->xml .= $this->_cmdXML(array("n"=>"ap","t"=>$sTarget,"p"=>$sAttribute),$sData);
182
+    }
183
+
184
+    /**
185
+     * Adds an prepend command message to the XML response.
186
+     *
187
+     * <i>Usage:</i> <kbd>$objResponse->addPrepend("contentDiv", "innerHTML", "Some Starting Text");</kbd>
188
+     *
189
+     * @param string contains the id of an HTML element
190
+     * @param string the part of the element you wish to modify ("innerHTML",
191
+     *               "value", etc.)
192
+     * @param string the data you want to prepend to the beginning of the
193
+     *               attribute
194
+     */
195
+    function addPrepend($sTarget,$sAttribute,$sData)
196
+    {
197
+        $this->xml .= $this->_cmdXML(array("n"=>"pp","t"=>$sTarget,"p"=>$sAttribute),$sData);
198
+    }
199
+
200
+    /**
201
+     * Adds a replace command message to the XML response.
202
+     *
203
+     * <i>Usage:</i> <kbd>$objResponse->addReplace("contentDiv", "innerHTML", "text", "<b>text</b>");</kbd>
204
+     *
205
+     * @param string contains the id of an HTML element
206
+     * @param string the part of the element you wish to modify ("innerHTML",
207
+     *               "value", etc.)
208
+     * @param string the string to search for
209
+     * @param string the string to replace the search string when found in the
210
+     *               attribute
211
+     */
212
+    function addReplace($sTarget,$sAttribute,$sSearch,$sData)
213
+    {
214
+        $sDta = "<s><![CDATA[$sSearch]]></s><r><![CDATA[$sData]]></r>";
215
+        $this->xml .= $this->_cmdXML(array("n"=>"rp","t"=>$sTarget,"p"=>$sAttribute),$sDta);
216
+    }
217
+
218
+    /**
219
+     * Adds a clear command message to the XML response.
220
+     *
221
+     * <i>Usage:</i> <kbd>$objResponse->addClear("contentDiv", "innerHTML");</kbd>
222
+     *
223
+     * @param string contains the id of an HTML element
224
+     * @param string the part of the element you wish to clear ("innerHTML",
225
+     *               "value", etc.)
226
+     */
227
+    function addClear($sTarget,$sAttribute)
228
+    {
229
+        $this->addAssign($sTarget,$sAttribute,'');
230
+    }
231
+
232
+    /**
233
+     * Adds an alert command message to the XML response.
234
+     *
235
+     * <i>Usage:</i> <kbd>$objResponse->addAlert("This is important information");</kbd>
236
+     *
237
+     * @param string the text to be displayed in the Javascript alert box
238
+     */
239
+    function addAlert($sMsg)
240
+    {
241
+        $this->xml .= $this->_cmdXML(array("n"=>"al"),$sMsg);
242
+    }
243
+
244
+    /**
245
+     * Uses the addScript() method to add a Javascript redirect to another URL.
246
+     *
247
+     * <i>Usage:</i> <kbd>$objResponse->addRedirect("http://www.xajaxproject.org");</kbd>
248
+     *
249
+     * @param string the URL to redirect the client browser to
250
+     */
251
+    function addRedirect($sURL)
252
+    {
253
+        //we need to parse the query part so that the values are rawurlencode()'ed
254
+        //can't just use parse_url() cos we could be dealing with a relative URL which
255
+        //  parse_url() can't deal with.
256
+        $queryStart = strpos($sURL, '?', strrpos($sURL, '/'));
257
+        if ($queryStart !== FALSE)
258
+        {
259
+            $queryStart++;
260
+            $queryEnd = strpos($sURL, '#', $queryStart);
261
+            if ($queryEnd === FALSE)
262
+                $queryEnd = strlen($sURL);
263
+            $queryPart = substr($sURL, $queryStart, $queryEnd-$queryStart);
264 264
             $queryParts = array();
265
-			parse_str($queryPart, $queryParts);
266
-			$newQueryPart = "";
267
-			foreach($queryParts as $key => $value)
268
-			{
269
-				$newQueryPart .= rawurlencode($key).'='.rawurlencode($value).ini_get('arg_separator.output');
270
-			}
271
-			$sURL = str_replace($queryPart, $newQueryPart, $sURL);
272
-		}
273
-		$this->addScript('window.location = "'.$sURL.'";');
274
-	}
275
-
276
-	/**
277
-	 * Adds a Javascript command message to the XML response.
278
-	 *
279
-	 * <i>Usage:</i> <kbd>$objResponse->addScript("var x = prompt('get some text');");</kbd>
280
-	 *
281
-	 * @param string contains Javascript code to be executed
282
-	 */
283
-	function addScript($sJS)
284
-	{
285
-		$this->xml .= $this->_cmdXML(array("n"=>"js"),$sJS);
286
-	}
287
-
288
-	/**
289
-	 * Adds a Javascript function call command message to the XML response.
290
-	 *
291
-	 * <i>Usage:</i> <kbd>$objResponse->addScriptCall("myJSFunction", "arg 1", "arg 2", 12345);</kbd>
292
-	 *
293
-	 * @param string $sFunc the name of a Javascript function
294
-	 * @param mixed $args,... optional arguments to pass to the Javascript function
295
-	 */
296
-	function addScriptCall() {
297
-		$arguments = func_get_args();
298
-		$sFunc = array_shift($arguments);
299
-		$sData = $this->_buildObjXml($arguments);
300
-		$this->xml .= $this->_cmdXML(array("n"=>"jc","t"=>$sFunc),$sData);
301
-	}
302
-
303
-	/**
304
-	 * Adds a remove element command message to the XML response.
305
-	 *
306
-	 * <i>Usage:</i> <kbd>$objResponse->addRemove("Div2");</kbd>
307
-	 *
308
-	 * @param string contains the id of an HTML element to be removed
309
-	 */
310
-	function addRemove($sTarget)
311
-	{
312
-		$this->xml .= $this->_cmdXML(array("n"=>"rm","t"=>$sTarget),'');
313
-	}
314
-
315
-	/**
316
-	 * Adds a create element command message to the XML response.
317
-	 *
318
-	 * <i>Usage:</i> <kbd>$objResponse->addCreate("parentDiv", "h3", "myid");</kbd>
319
-	 *
320
-	 * @param string contains the id of an HTML element to to which the new
321
-	 *               element will be appended.
322
-	 * @param string the tag to be added
323
-	 * @param string the id to be assigned to the new element
324
-	 * @param string deprecated, use the addCreateInput() method instead
325
-	 */
326
-	function addCreate($sParent, $sTag, $sId, $sType="")
327
-	{
328
-		if ($sType)
329
-		{
330
-			trigger_error("The \$sType parameter of addCreate has been deprecated.  Use the addCreateInput() method instead.", E_USER_WARNING);
331
-			return;
332
-		}
333
-		$this->xml .= $this->_cmdXML(array("n"=>"ce","t"=>$sParent,"p"=>$sId),$sTag);
334
-	}
335
-
336
-	/**
337
-	 * Adds a insert element command message to the XML response.
338
-	 *
339
-	 * <i>Usage:</i> <kbd>$objResponse->addInsert("childDiv", "h3", "myid");</kbd>
340
-	 *
341
-	 * @param string contains the id of the child before which the new element
342
-	 *               will be inserted
343
-	 * @param string the tag to be added
344
-	 * @param string the id to be assigned to the new element
345
-	 */
346
-	function addInsert($sBefore, $sTag, $sId)
347
-	{
348
-		$this->xml .= $this->_cmdXML(array("n"=>"ie","t"=>$sBefore,"p"=>$sId),$sTag);
349
-	}
350
-
351
-	/**
352
-	 * Adds a insert element command message to the XML response.
353
-	 *
354
-	 * <i>Usage:</i> <kbd>$objResponse->addInsertAfter("childDiv", "h3", "myid");</kbd>
355
-	 *
356
-	 * @param string contains the id of the child after which the new element
357
-	 *               will be inserted
358
-	 * @param string the tag to be added
359
-	 * @param string the id to be assigned to the new element
360
-	 */
361
-	function addInsertAfter($sAfter, $sTag, $sId)
362
-	{
363
-		$this->xml .= $this->_cmdXML(array("n"=>"ia","t"=>$sAfter,"p"=>$sId),$sTag);
364
-	}
365
-
366
-	/**
367
-	 * Adds a create input command message to the XML response.
368
-	 *
369
-	 * <i>Usage:</i> <kbd>$objResponse->addCreateInput("form1", "text", "username", "input1");</kbd>
370
-	 *
371
-	 * @param string contains the id of an HTML element to which the new input
372
-	 *               will be appended
373
-	 * @param string the type of input to be created (text, radio, checkbox,
374
-	 *               etc.)
375
-	 * @param string the name to be assigned to the new input and the variable
376
-	 *               name when it is submitted
377
-	 * @param string the id to be assigned to the new input
378
-	 */
379
-	function addCreateInput($sParent, $sType, $sName, $sId)
380
-	{
381
-		$this->xml .= $this->_cmdXML(array("n"=>"ci","t"=>$sParent,"p"=>$sId,"c"=>$sType),$sName);
382
-	}
383
-
384
-	/**
385
-	 * Adds an insert input command message to the XML response.
386
-	 *
387
-	 * <i>Usage:</i> <kbd>$objResponse->addInsertInput("input5", "text", "username", "input1");</kbd>
388
-	 *
389
-	 * @param string contains the id of the child before which the new element
390
-	 *               will be inserted
391
-	 * @param string the type of input to be created (text, radio, checkbox,
392
-	 *               etc.)
393
-	 * @param string the name to be assigned to the new input and the variable
394
-	 *               name when it is submitted
395
-	 * @param string the id to be assigned to the new input
396
-	 */
397
-	function addInsertInput($sBefore, $sType, $sName, $sId)
398
-	{
399
-		$this->xml .= $this->_cmdXML(array("n"=>"ii","t"=>$sBefore,"p"=>$sId,"c"=>$sType),$sName);
400
-	}
401
-
402
-	/**
403
-	 * Adds an insert input command message to the XML response.
404
-	 *
405
-	 * <i>Usage:</i> <kbd>$objResponse->addInsertInputAfter("input7", "text", "email", "input2");</kbd>
406
-	 *
407
-	 * @param string contains the id of the child after which the new element
408
-	 *               will be inserted
409
-	 * @param string the type of input to be created (text, radio, checkbox,
410
-	 *               etc.)
411
-	 * @param string the name to be assigned to the new input and the variable
412
-	 *               name when it is submitted
413
-	 * @param string the id to be assigned to the new input
414
-	 */
415
-	function addInsertInputAfter($sAfter, $sType, $sName, $sId)
416
-	{
417
-		$this->xml .= $this->_cmdXML(array("n"=>"iia","t"=>$sAfter,"p"=>$sId,"c"=>$sType),$sName);
418
-	}
419
-
420
-	/**
421
-	 * Adds an event command message to the XML response.
422
-	 *
423
-	 * <i>Usage:</i> <kbd>$objResponse->addEvent("contentDiv", "onclick", "alert(\'Hello World\');");</kbd>
424
-	 *
425
-	 * @param string contains the id of an HTML element
426
-	 * @param string the event you wish to set ("onclick", "onmouseover", etc.)
427
-	 * @param string the Javascript string you want the event to invoke
428
-	 */
429
-	function addEvent($sTarget,$sEvent,$sScript)
430
-	{
431
-		$this->xml .= $this->_cmdXML(array("n"=>"ev","t"=>$sTarget,"p"=>$sEvent),$sScript);
432
-	}
433
-
434
-	/**
435
-	 * Adds a handler command message to the XML response.
436
-	 *
437
-	 * <i>Usage:</i> <kbd>$objResponse->addHandler("contentDiv", "onclick", "content_click");</kbd>
438
-	 *
439
-	 * @param string contains the id of an HTML element
440
-	 * @param string the event you wish to set ("onclick", "onmouseover", etc.)
441
-	 * @param string the name of a Javascript function that will handle the
442
-	 *               event. Multiple handlers can be added for the same event
443
-	 */
444
-	function addHandler($sTarget,$sEvent,$sHandler)
445
-	{
446
-		$this->xml .= $this->_cmdXML(array("n"=>"ah","t"=>$sTarget,"p"=>$sEvent),$sHandler);
447
-	}
448
-
449
-	/**
450
-	 * Adds a remove handler command message to the XML response.
451
-	 *
452
-	 * <i>Usage:</i> <kbd>$objResponse->addRemoveHandler("contentDiv", "onclick", "content_click");</kbd>
453
-	 *
454
-	 * @param string contains the id of an HTML element
455
-	 * @param string the event you wish to remove ("onclick", "onmouseover",
456
-	 *               etc.)
457
-	 * @param string the name of a Javascript handler function that you want to
458
-	 *               remove
459
-	 */
460
-	function addRemoveHandler($sTarget,$sEvent,$sHandler)
461
-	{
462
-		$this->xml .= $this->_cmdXML(array("n"=>"rh","t"=>$sTarget,"p"=>$sEvent),$sHandler);
463
-	}
464
-
465
-	/**
466
-	 * Adds an include script command message to the XML response.
467
-	 *
468
-	 * <i>Usage:</i> <kbd>$objResponse->addIncludeScript("functions.js");</kbd>
469
-	 *
470
-	 * @param string URL of the Javascript file to include
471
-	 */
472
-	function addIncludeScript($sFileName)
473
-	{
474
-		$this->xml .= $this->_cmdXML(array("n"=>"in"),$sFileName);
475
-	}
476
-
477
-	/**
478
-	 * Returns the XML to be returned from your function to the xajax processor
479
-	 * on your page. Since xajax 0.2, you can also return an xajaxResponse
480
-	 * object from your function directly, and xajax will automatically request
481
-	 * the XML using this method call.
482
-	 *
483
-	 * <i>Usage:</i> <kbd>return $objResponse->getXML();</kbd>
484
-	 *
485
-	 * @return string response XML data
486
-	 */
487
-	function getXML()
488
-	{
489
-		$sXML = "<?xml version=\"1.0\"";
490
-		if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0)
491
-			$sXML .= " encoding=\"".$this->sEncoding."\"";
492
-		$sXML .= " ?"."><xjx>" . $this->xml . "</xjx>";
493
-
494
-		return $sXML;
495
-	}
496
-
497
-	/**
498
-	 * Adds the commands of the provided response XML output to this response
499
-	 * object
500
-	 *
501
-	 * <i>Usage:</i>
502
-	 * <code>$r1 = $objResponse1->getXML();
503
-	 * $objResponse2->loadXML($r1);
504
-	 * return $objResponse2->getXML();</code>
505
-	 *
506
-	 * @param string the response XML (returned from a getXML() method) to add
507
-	 *               to the end of this response object
508
-	 */
509
-	function loadXML($mXML)
510
-	{
511
-		if (is_a($mXML, "xajaxResponse")) {
512
-			$mXML = $mXML->getXML();
513
-		}
514
-		$sNewXML = "";
515
-		$iStartPos = strpos($mXML, "<xjx>") + 5;
516
-		$sNewXML = substr($mXML, $iStartPos);
517
-		$iEndPos = strpos($sNewXML, "</xjx>");
518
-		$sNewXML = substr($sNewXML, 0, $iEndPos);
519
-		$this->xml .= $sNewXML;
520
-	}
521
-
522
-	/**
523
-	 * Generates XML from command data
524
-	 *
525
-	 * @access private
526
-	 * @param array associative array of attributes
527
-	 * @param string data
528
-	 * @return string XML command
529
-	 */
530
-	function _cmdXML($aAttributes, $sData)
531
-	{
532
-		if ($this->bOutputEntities) {
533
-			// An adaptation for the Dokeos LMS, 22-AUG-2009.
534
-			if (function_exists('api_convert_encoding')) {
535
-				$sData = call_user_func_array('api_convert_encoding', array(&$sData, 'HTML-ENTITIES', $this->sEncoding));
536
-			}
537
-			//if (function_exists('mb_convert_encoding')) {
538
-			elseif (function_exists('mb_convert_encoding')) {
539
-			//
540
-				$sData = call_user_func_array('mb_convert_encoding', array(&$sData, 'HTML-ENTITIES', $this->sEncoding));
541
-			}
542
-			else {
543
-				trigger_error("The xajax XML response output could not be converted to HTML entities because the mb_convert_encoding function is not available", E_USER_NOTICE);
544
-			}
545
-		}
546
-		$xml = "<cmd";
547
-		foreach($aAttributes as $sAttribute => $sValue)
548
-			$xml .= " $sAttribute=\"$sValue\"";
549
-		if ($sData !== null && !stristr($sData,'<![CDATA['))
550
-			$xml .= "><![CDATA[$sData]]></cmd>";
551
-		else if ($sData !== null)
552
-			$xml .= ">$sData</cmd>";
553
-		else
554
-			$xml .= "></cmd>";
555
-
556
-		return $xml;
557
-	}
558
-
559
-	/**
560
-	 * Recursively serializes a data structure in XML so it can be sent to
561
-	 * the client. It could be thought of as the opposite of
562
-	 * {@link xajax::_parseObjXml()}.
563
-	 *
564
-	 * @access private
565
-	 * @param mixed data structure to serialize to XML
566
-	 * @return string serialized XML
567
-	 */
568
-	function _buildObjXml($var) {
569
-		if (gettype($var) == "object") $var = get_object_vars($var);
570
-		if (!is_array($var)) {
571
-			return "<![CDATA[$var]]>";
572
-		}
573
-		else {
574
-			$data = "<xjxobj>";
575
-			foreach ($var as $key => $value) {
576
-				$data .= "<e>";
577
-				$data .= "<k>" . htmlspecialchars($key) . "</k>";
578
-				$data .= "<v>" . $this->_buildObjXml($value) . "</v>";
579
-				$data .= "</e>";
580
-			}
581
-			$data .= "</xjxobj>";
582
-			return $data;
583
-		}
584
-	}
265
+            parse_str($queryPart, $queryParts);
266
+            $newQueryPart = "";
267
+            foreach($queryParts as $key => $value)
268
+            {
269
+                $newQueryPart .= rawurlencode($key).'='.rawurlencode($value).ini_get('arg_separator.output');
270
+            }
271
+            $sURL = str_replace($queryPart, $newQueryPart, $sURL);
272
+        }
273
+        $this->addScript('window.location = "'.$sURL.'";');
274
+    }
275
+
276
+    /**
277
+     * Adds a Javascript command message to the XML response.
278
+     *
279
+     * <i>Usage:</i> <kbd>$objResponse->addScript("var x = prompt('get some text');");</kbd>
280
+     *
281
+     * @param string contains Javascript code to be executed
282
+     */
283
+    function addScript($sJS)
284
+    {
285
+        $this->xml .= $this->_cmdXML(array("n"=>"js"),$sJS);
286
+    }
287
+
288
+    /**
289
+     * Adds a Javascript function call command message to the XML response.
290
+     *
291
+     * <i>Usage:</i> <kbd>$objResponse->addScriptCall("myJSFunction", "arg 1", "arg 2", 12345);</kbd>
292
+     *
293
+     * @param string $sFunc the name of a Javascript function
294
+     * @param mixed $args,... optional arguments to pass to the Javascript function
295
+     */
296
+    function addScriptCall() {
297
+        $arguments = func_get_args();
298
+        $sFunc = array_shift($arguments);
299
+        $sData = $this->_buildObjXml($arguments);
300
+        $this->xml .= $this->_cmdXML(array("n"=>"jc","t"=>$sFunc),$sData);
301
+    }
302
+
303
+    /**
304
+     * Adds a remove element command message to the XML response.
305
+     *
306
+     * <i>Usage:</i> <kbd>$objResponse->addRemove("Div2");</kbd>
307
+     *
308
+     * @param string contains the id of an HTML element to be removed
309
+     */
310
+    function addRemove($sTarget)
311
+    {
312
+        $this->xml .= $this->_cmdXML(array("n"=>"rm","t"=>$sTarget),'');
313
+    }
314
+
315
+    /**
316
+     * Adds a create element command message to the XML response.
317
+     *
318
+     * <i>Usage:</i> <kbd>$objResponse->addCreate("parentDiv", "h3", "myid");</kbd>
319
+     *
320
+     * @param string contains the id of an HTML element to to which the new
321
+     *               element will be appended.
322
+     * @param string the tag to be added
323
+     * @param string the id to be assigned to the new element
324
+     * @param string deprecated, use the addCreateInput() method instead
325
+     */
326
+    function addCreate($sParent, $sTag, $sId, $sType="")
327
+    {
328
+        if ($sType)
329
+        {
330
+            trigger_error("The \$sType parameter of addCreate has been deprecated.  Use the addCreateInput() method instead.", E_USER_WARNING);
331
+            return;
332
+        }
333
+        $this->xml .= $this->_cmdXML(array("n"=>"ce","t"=>$sParent,"p"=>$sId),$sTag);
334
+    }
335
+
336
+    /**
337
+     * Adds a insert element command message to the XML response.
338
+     *
339
+     * <i>Usage:</i> <kbd>$objResponse->addInsert("childDiv", "h3", "myid");</kbd>
340
+     *
341
+     * @param string contains the id of the child before which the new element
342
+     *               will be inserted
343
+     * @param string the tag to be added
344
+     * @param string the id to be assigned to the new element
345
+     */
346
+    function addInsert($sBefore, $sTag, $sId)
347
+    {
348
+        $this->xml .= $this->_cmdXML(array("n"=>"ie","t"=>$sBefore,"p"=>$sId),$sTag);
349
+    }
350
+
351
+    /**
352
+     * Adds a insert element command message to the XML response.
353
+     *
354
+     * <i>Usage:</i> <kbd>$objResponse->addInsertAfter("childDiv", "h3", "myid");</kbd>
355
+     *
356
+     * @param string contains the id of the child after which the new element
357
+     *               will be inserted
358
+     * @param string the tag to be added
359
+     * @param string the id to be assigned to the new element
360
+     */
361
+    function addInsertAfter($sAfter, $sTag, $sId)
362
+    {
363
+        $this->xml .= $this->_cmdXML(array("n"=>"ia","t"=>$sAfter,"p"=>$sId),$sTag);
364
+    }
365
+
366
+    /**
367
+     * Adds a create input command message to the XML response.
368
+     *
369
+     * <i>Usage:</i> <kbd>$objResponse->addCreateInput("form1", "text", "username", "input1");</kbd>
370
+     *
371
+     * @param string contains the id of an HTML element to which the new input
372
+     *               will be appended
373
+     * @param string the type of input to be created (text, radio, checkbox,
374
+     *               etc.)
375
+     * @param string the name to be assigned to the new input and the variable
376
+     *               name when it is submitted
377
+     * @param string the id to be assigned to the new input
378
+     */
379
+    function addCreateInput($sParent, $sType, $sName, $sId)
380
+    {
381
+        $this->xml .= $this->_cmdXML(array("n"=>"ci","t"=>$sParent,"p"=>$sId,"c"=>$sType),$sName);
382
+    }
383
+
384
+    /**
385
+     * Adds an insert input command message to the XML response.
386
+     *
387
+     * <i>Usage:</i> <kbd>$objResponse->addInsertInput("input5", "text", "username", "input1");</kbd>
388
+     *
389
+     * @param string contains the id of the child before which the new element
390
+     *               will be inserted
391
+     * @param string the type of input to be created (text, radio, checkbox,
392
+     *               etc.)
393
+     * @param string the name to be assigned to the new input and the variable
394
+     *               name when it is submitted
395
+     * @param string the id to be assigned to the new input
396
+     */
397
+    function addInsertInput($sBefore, $sType, $sName, $sId)
398
+    {
399
+        $this->xml .= $this->_cmdXML(array("n"=>"ii","t"=>$sBefore,"p"=>$sId,"c"=>$sType),$sName);
400
+    }
401
+
402
+    /**
403
+     * Adds an insert input command message to the XML response.
404
+     *
405
+     * <i>Usage:</i> <kbd>$objResponse->addInsertInputAfter("input7", "text", "email", "input2");</kbd>
406
+     *
407
+     * @param string contains the id of the child after which the new element
408
+     *               will be inserted
409
+     * @param string the type of input to be created (text, radio, checkbox,
410
+     *               etc.)
411
+     * @param string the name to be assigned to the new input and the variable
412
+     *               name when it is submitted
413
+     * @param string the id to be assigned to the new input
414
+     */
415
+    function addInsertInputAfter($sAfter, $sType, $sName, $sId)
416
+    {
417
+        $this->xml .= $this->_cmdXML(array("n"=>"iia","t"=>$sAfter,"p"=>$sId,"c"=>$sType),$sName);
418
+    }
419
+
420
+    /**
421
+     * Adds an event command message to the XML response.
422
+     *
423
+     * <i>Usage:</i> <kbd>$objResponse->addEvent("contentDiv", "onclick", "alert(\'Hello World\');");</kbd>
424
+     *
425
+     * @param string contains the id of an HTML element
426
+     * @param string the event you wish to set ("onclick", "onmouseover", etc.)
427
+     * @param string the Javascript string you want the event to invoke
428
+     */
429
+    function addEvent($sTarget,$sEvent,$sScript)
430
+    {
431
+        $this->xml .= $this->_cmdXML(array("n"=>"ev","t"=>$sTarget,"p"=>$sEvent),$sScript);
432
+    }
433
+
434
+    /**
435
+     * Adds a handler command message to the XML response.
436
+     *
437
+     * <i>Usage:</i> <kbd>$objResponse->addHandler("contentDiv", "onclick", "content_click");</kbd>
438
+     *
439
+     * @param string contains the id of an HTML element
440
+     * @param string the event you wish to set ("onclick", "onmouseover", etc.)
441
+     * @param string the name of a Javascript function that will handle the
442
+     *               event. Multiple handlers can be added for the same event
443
+     */
444
+    function addHandler($sTarget,$sEvent,$sHandler)
445
+    {
446
+        $this->xml .= $this->_cmdXML(array("n"=>"ah","t"=>$sTarget,"p"=>$sEvent),$sHandler);
447
+    }
448
+
449
+    /**
450
+     * Adds a remove handler command message to the XML response.
451
+     *
452
+     * <i>Usage:</i> <kbd>$objResponse->addRemoveHandler("contentDiv", "onclick", "content_click");</kbd>
453
+     *
454
+     * @param string contains the id of an HTML element
455
+     * @param string the event you wish to remove ("onclick", "onmouseover",
456
+     *               etc.)
457
+     * @param string the name of a Javascript handler function that you want to
458
+     *               remove
459
+     */
460
+    function addRemoveHandler($sTarget,$sEvent,$sHandler)
461
+    {
462
+        $this->xml .= $this->_cmdXML(array("n"=>"rh","t"=>$sTarget,"p"=>$sEvent),$sHandler);
463
+    }
464
+
465
+    /**
466
+     * Adds an include script command message to the XML response.
467
+     *
468
+     * <i>Usage:</i> <kbd>$objResponse->addIncludeScript("functions.js");</kbd>
469
+     *
470
+     * @param string URL of the Javascript file to include
471
+     */
472
+    function addIncludeScript($sFileName)
473
+    {
474
+        $this->xml .= $this->_cmdXML(array("n"=>"in"),$sFileName);
475
+    }
476
+
477
+    /**
478
+     * Returns the XML to be returned from your function to the xajax processor
479
+     * on your page. Since xajax 0.2, you can also return an xajaxResponse
480
+     * object from your function directly, and xajax will automatically request
481
+     * the XML using this method call.
482
+     *
483
+     * <i>Usage:</i> <kbd>return $objResponse->getXML();</kbd>
484
+     *
485
+     * @return string response XML data
486
+     */
487
+    function getXML()
488
+    {
489
+        $sXML = "<?xml version=\"1.0\"";
490
+        if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0)
491
+            $sXML .= " encoding=\"".$this->sEncoding."\"";
492
+        $sXML .= " ?"."><xjx>" . $this->xml . "</xjx>";
493
+
494
+        return $sXML;
495
+    }
496
+
497
+    /**
498
+     * Adds the commands of the provided response XML output to this response
499
+     * object
500
+     *
501
+     * <i>Usage:</i>
502
+     * <code>$r1 = $objResponse1->getXML();
503
+     * $objResponse2->loadXML($r1);
504
+     * return $objResponse2->getXML();</code>
505
+     *
506
+     * @param string the response XML (returned from a getXML() method) to add
507
+     *               to the end of this response object
508
+     */
509
+    function loadXML($mXML)
510
+    {
511
+        if (is_a($mXML, "xajaxResponse")) {
512
+            $mXML = $mXML->getXML();
513
+        }
514
+        $sNewXML = "";
515
+        $iStartPos = strpos($mXML, "<xjx>") + 5;
516
+        $sNewXML = substr($mXML, $iStartPos);
517
+        $iEndPos = strpos($sNewXML, "</xjx>");
518
+        $sNewXML = substr($sNewXML, 0, $iEndPos);
519
+        $this->xml .= $sNewXML;
520
+    }
521
+
522
+    /**
523
+     * Generates XML from command data
524
+     *
525
+     * @access private
526
+     * @param array associative array of attributes
527
+     * @param string data
528
+     * @return string XML command
529
+     */
530
+    function _cmdXML($aAttributes, $sData)
531
+    {
532
+        if ($this->bOutputEntities) {
533
+            // An adaptation for the Dokeos LMS, 22-AUG-2009.
534
+            if (function_exists('api_convert_encoding')) {
535
+                $sData = call_user_func_array('api_convert_encoding', array(&$sData, 'HTML-ENTITIES', $this->sEncoding));
536
+            }
537
+            //if (function_exists('mb_convert_encoding')) {
538
+            elseif (function_exists('mb_convert_encoding')) {
539
+            //
540
+                $sData = call_user_func_array('mb_convert_encoding', array(&$sData, 'HTML-ENTITIES', $this->sEncoding));
541
+            }
542
+            else {
543
+                trigger_error("The xajax XML response output could not be converted to HTML entities because the mb_convert_encoding function is not available", E_USER_NOTICE);
544
+            }
545
+        }
546
+        $xml = "<cmd";
547
+        foreach($aAttributes as $sAttribute => $sValue)
548
+            $xml .= " $sAttribute=\"$sValue\"";
549
+        if ($sData !== null && !stristr($sData,'<![CDATA['))
550
+            $xml .= "><![CDATA[$sData]]></cmd>";
551
+        else if ($sData !== null)
552
+            $xml .= ">$sData</cmd>";
553
+        else
554
+            $xml .= "></cmd>";
555
+
556
+        return $xml;
557
+    }
558
+
559
+    /**
560
+     * Recursively serializes a data structure in XML so it can be sent to
561
+     * the client. It could be thought of as the opposite of
562
+     * {@link xajax::_parseObjXml()}.
563
+     *
564
+     * @access private
565
+     * @param mixed data structure to serialize to XML
566
+     * @return string serialized XML
567
+     */
568
+    function _buildObjXml($var) {
569
+        if (gettype($var) == "object") $var = get_object_vars($var);
570
+        if (!is_array($var)) {
571
+            return "<![CDATA[$var]]>";
572
+        }
573
+        else {
574
+            $data = "<xjxobj>";
575
+            foreach ($var as $key => $value) {
576
+                $data .= "<e>";
577
+                $data .= "<k>" . htmlspecialchars($key) . "</k>";
578
+                $data .= "<v>" . $this->_buildObjXml($value) . "</v>";
579
+                $data .= "</e>";
580
+            }
581
+            $data .= "</xjxobj>";
582
+            return $data;
583
+        }
584
+    }
585 585
 
586 586
 }// end class xajaxResponse
587 587
 ?>
Please login to merge, or discard this patch.
main/inc/lib/xajax/xajaxCompress.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -42,141 +42,141 @@
 block discarded – undo
42 42
  */
43 43
 function xajaxCompressJavascript($sJS)
44 44
 {
45
-	//remove windows cariage returns
46
-	$sJS = str_replace("\r","",$sJS);
47
-
48
-	//array to store replaced literal strings
49
-	$literal_strings = array();
50
-
51
-	//explode the string into lines
52
-	$lines = explode("\n",$sJS);
53
-	//loop through all the lines, building a new string at the same time as removing literal strings
54
-	$clean = "";
55
-	$inComment = false;
56
-	$literal = "";
57
-	$inQuote = false;
58
-	$escaped = false;
59
-	$quoteChar = "";
60
-
61
-	for($i=0;$i<count($lines);$i++)
62
-	{
63
-		$line = $lines[$i];
64
-		$inNormalComment = false;
65
-
66
-		//loop through line's characters and take out any literal strings, replace them with ___i___ where i is the index of this string
67
-		for($j=0;$j<strlen($line);$j++)
68
-		{
69
-			$c = substr($line,$j,1);
70
-			$d = substr($line,$j,2);
71
-
72
-			//look for start of quote
73
-			if(!$inQuote && !$inComment)
74
-			{
75
-				//is this character a quote or a comment
76
-				if(($c=="\"" || $c=="'") && !$inComment && !$inNormalComment)
77
-				{
78
-					$inQuote = true;
79
-					$inComment = false;
80
-					$escaped = false;
81
-					$quoteChar = $c;
82
-					$literal = $c;
83
-				}
84
-				else if($d=="/*" && !$inNormalComment)
85
-				{
86
-					$inQuote = false;
87
-					$inComment = true;
88
-					$escaped = false;
89
-					$quoteChar = $d;
90
-					$literal = $d;
91
-					$j++;
92
-				}
93
-				else if($d=="//") //ignore string markers that are found inside comments
94
-				{
95
-					$inNormalComment = true;
96
-					$clean .= $c;
97
-				}
98
-				else
99
-				{
100
-					$clean .= $c;
101
-				}
102
-			}
103
-			else //allready in a string so find end quote
104
-			{
105
-				if($c == $quoteChar && !$escaped && !$inComment)
106
-				{
107
-					$inQuote = false;
108
-					$literal .= $c;
109
-
110
-					//subsitute in a marker for the string
111
-					$clean .= "___" . count($literal_strings) . "___";
112
-
113
-					//push the string onto our array
114
-					array_push($literal_strings,$literal);
115
-
116
-				}
117
-				else if($inComment && $d=="*/")
118
-				{
119
-					$inComment = false;
120
-					$literal .= $d;
121
-
122
-					//subsitute in a marker for the string
123
-					$clean .= "___" . count($literal_strings) . "___";
124
-
125
-					//push the string onto our array
126
-					array_push($literal_strings,$literal);
127
-
128
-					$j++;
129
-				}
130
-				else if($c == "\\" && !$escaped)
131
-					$escaped = true;
132
-				else
133
-					$escaped = false;
134
-
135
-				$literal .= $c;
136
-			}
137
-		}
138
-		if($inComment) $literal .= "\n";
139
-		$clean .= "\n";
140
-	}
141
-	//explode the clean string into lines again
142
-	$lines = explode("\n",$clean);
143
-
144
-	//now process each line at a time
145
-	for($i=0;$i<count($lines);$i++)
146
-	{
147
-		$line = $lines[$i];
148
-
149
-		//remove comments
150
-		$line = preg_replace("/\/\/(.*)/","",$line);
151
-
152
-		//strip leading and trailing whitespace
153
-		$line = trim($line);
154
-
155
-		//remove all whitespace with a single space
156
-		$line = preg_replace("/\s+/"," ",$line);
157
-
158
-		//remove any whitespace that occurs after/before an operator
159
-		$line = preg_replace("/\s*([!\}\{;,&=\|\-\+\*\/\)\(:])\s*/","\\1",$line);
160
-
161
-		$lines[$i] = $line;
162
-	}
163
-
164
-	//implode the lines
165
-	$sJS = implode("\n",$lines);
166
-
167
-	//make sure there is a max of 1 \n after each line
168
-	$sJS = preg_replace("/[\n]+/","\n",$sJS);
169
-
170
-	//strip out line breaks that immediately follow a semi-colon
171
-	$sJS = preg_replace("/;\n/",";",$sJS);
172
-
173
-	//curly brackets aren't on their own
174
-	$sJS = preg_replace("/[\n]*\{[\n]*/","{",$sJS);
175
-
176
-	//finally loop through and replace all the literal strings:
177
-	for($i=0;$i<count($literal_strings);$i++)
178
-		$sJS = str_replace("___".$i."___",$literal_strings[$i],$sJS);
179
-
180
-	return $sJS;
45
+    //remove windows cariage returns
46
+    $sJS = str_replace("\r","",$sJS);
47
+
48
+    //array to store replaced literal strings
49
+    $literal_strings = array();
50
+
51
+    //explode the string into lines
52
+    $lines = explode("\n",$sJS);
53
+    //loop through all the lines, building a new string at the same time as removing literal strings
54
+    $clean = "";
55
+    $inComment = false;
56
+    $literal = "";
57
+    $inQuote = false;
58
+    $escaped = false;
59
+    $quoteChar = "";
60
+
61
+    for($i=0;$i<count($lines);$i++)
62
+    {
63
+        $line = $lines[$i];
64
+        $inNormalComment = false;
65
+
66
+        //loop through line's characters and take out any literal strings, replace them with ___i___ where i is the index of this string
67
+        for($j=0;$j<strlen($line);$j++)
68
+        {
69
+            $c = substr($line,$j,1);
70
+            $d = substr($line,$j,2);
71
+
72
+            //look for start of quote
73
+            if(!$inQuote && !$inComment)
74
+            {
75
+                //is this character a quote or a comment
76
+                if(($c=="\"" || $c=="'") && !$inComment && !$inNormalComment)
77
+                {
78
+                    $inQuote = true;
79
+                    $inComment = false;
80
+                    $escaped = false;
81
+                    $quoteChar = $c;
82
+                    $literal = $c;
83
+                }
84
+                else if($d=="/*" && !$inNormalComment)
85
+                {
86
+                    $inQuote = false;
87
+                    $inComment = true;
88
+                    $escaped = false;
89
+                    $quoteChar = $d;
90
+                    $literal = $d;
91
+                    $j++;
92
+                }
93
+                else if($d=="//") //ignore string markers that are found inside comments
94
+                {
95
+                    $inNormalComment = true;
96
+                    $clean .= $c;
97
+                }
98
+                else
99
+                {
100
+                    $clean .= $c;
101
+                }
102
+            }
103
+            else //allready in a string so find end quote
104
+            {
105
+                if($c == $quoteChar && !$escaped && !$inComment)
106
+                {
107
+                    $inQuote = false;
108
+                    $literal .= $c;
109
+
110
+                    //subsitute in a marker for the string
111
+                    $clean .= "___" . count($literal_strings) . "___";
112
+
113
+                    //push the string onto our array
114
+                    array_push($literal_strings,$literal);
115
+
116
+                }
117
+                else if($inComment && $d=="*/")
118
+                {
119
+                    $inComment = false;
120
+                    $literal .= $d;
121
+
122
+                    //subsitute in a marker for the string
123
+                    $clean .= "___" . count($literal_strings) . "___";
124
+
125
+                    //push the string onto our array
126
+                    array_push($literal_strings,$literal);
127
+
128
+                    $j++;
129
+                }
130
+                else if($c == "\\" && !$escaped)
131
+                    $escaped = true;
132
+                else
133
+                    $escaped = false;
134
+
135
+                $literal .= $c;
136
+            }
137
+        }
138
+        if($inComment) $literal .= "\n";
139
+        $clean .= "\n";
140
+    }
141
+    //explode the clean string into lines again
142
+    $lines = explode("\n",$clean);
143
+
144
+    //now process each line at a time
145
+    for($i=0;$i<count($lines);$i++)
146
+    {
147
+        $line = $lines[$i];
148
+
149
+        //remove comments
150
+        $line = preg_replace("/\/\/(.*)/","",$line);
151
+
152
+        //strip leading and trailing whitespace
153
+        $line = trim($line);
154
+
155
+        //remove all whitespace with a single space
156
+        $line = preg_replace("/\s+/"," ",$line);
157
+
158
+        //remove any whitespace that occurs after/before an operator
159
+        $line = preg_replace("/\s*([!\}\{;,&=\|\-\+\*\/\)\(:])\s*/","\\1",$line);
160
+
161
+        $lines[$i] = $line;
162
+    }
163
+
164
+    //implode the lines
165
+    $sJS = implode("\n",$lines);
166
+
167
+    //make sure there is a max of 1 \n after each line
168
+    $sJS = preg_replace("/[\n]+/","\n",$sJS);
169
+
170
+    //strip out line breaks that immediately follow a semi-colon
171
+    $sJS = preg_replace("/;\n/",";",$sJS);
172
+
173
+    //curly brackets aren't on their own
174
+    $sJS = preg_replace("/[\n]*\{[\n]*/","{",$sJS);
175
+
176
+    //finally loop through and replace all the literal strings:
177
+    for($i=0;$i<count($literal_strings);$i++)
178
+        $sJS = str_replace("___".$i."___",$literal_strings[$i],$sJS);
179
+
180
+    return $sJS;
181 181
 }
182 182
 ?>
Please login to merge, or discard this patch.
main/inc/lib/userportal.lib.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -248,17 +248,17 @@  discard block
 block discarded – undo
248 248
                 }
249 249
             }
250 250
 
251
-			if (trim($home_top_temp) == '' && api_is_platform_admin()) {
252
-				$home_top_temp = '<div class="welcome-mascot">' . get_lang('PortalHomepageDefaultIntroduction') . '</div>';
253
-			} else {
254
-				$home_top_temp = '<div class="welcome-home-top-temp">' . $home_top_temp . '</div>';
255
-			}
256
-			$open = str_replace('{rel_path}', api_get_path(REL_PATH), $home_top_temp);
257
-			$html = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
258
-		}
259
-
260
-		return $html;
261
-	}
251
+            if (trim($home_top_temp) == '' && api_is_platform_admin()) {
252
+                $home_top_temp = '<div class="welcome-mascot">' . get_lang('PortalHomepageDefaultIntroduction') . '</div>';
253
+            } else {
254
+                $home_top_temp = '<div class="welcome-home-top-temp">' . $home_top_temp . '</div>';
255
+            }
256
+            $open = str_replace('{rel_path}', api_get_path(REL_PATH), $home_top_temp);
257
+            $html = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
258
+        }
259
+
260
+        return $html;
261
+    }
262 262
 
263 263
     function return_notice()
264 264
     {
@@ -509,7 +509,7 @@  discard block
 block discarded – undo
509 509
                     $thereIsSubCat = true;
510 510
                 } elseif (api_get_setting('show_empty_course_categories') == 'true') {
511 511
                     /* End changed code to eliminate the (0 courses) after empty categories. */
512
-                      $htmlListCat .= '<li>';
512
+                        $htmlListCat .= '<li>';
513 513
                     $htmlListCat .= $catLine['name'];
514 514
                     $htmlListCat .= "</li>";
515 515
                     $thereIsSubCat = true;
@@ -639,11 +639,11 @@  discard block
 block discarded – undo
639 639
     }
640 640
 
641 641
     /**
642
-    * retrieves all the courses that the user has already subscribed to
643
-    * @author Patrick Cool <[email protected]>, Ghent University, Belgium
644
-    * @param int $user_id: the id of the user
645
-    * @return array an array containing all the information of the courses of the given user
646
-    */
642
+     * retrieves all the courses that the user has already subscribed to
643
+     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
644
+     * @param int $user_id: the id of the user
645
+     * @return array an array containing all the information of the courses of the given user
646
+     */
647 647
     public function get_courses_of_user($user_id)
648 648
     {
649 649
         $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
Please login to merge, or discard this patch.
main/tracking/course_log_tools.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
 
79 79
 // getting all the students of the course
80 80
 if (empty($session_id)) {
81
-	// Registered students in a course outside session.
81
+    // Registered students in a course outside session.
82 82
     $a_students = CourseManager:: get_student_list_from_course_code(
83 83
         api_get_course_id(),
84 84
         false,
@@ -89,7 +89,7 @@  discard block
 block discarded – undo
89 89
         api_get_group_id()
90 90
     );
91 91
 } else {
92
-	// Registered students in session.
92
+    // Registered students in session.
93 93
     $a_students = CourseManager:: get_student_list_from_course_code(
94 94
         api_get_course_id(),
95 95
         true,
Please login to merge, or discard this patch.
main/tracking/courseLog.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -111,7 +111,7 @@
 block discarded – undo
111 111
                             get_lang('HideColumn'),
112 112
                             array('align' => 'absmiddle', 'hspace' => '3px'),
113 113
                             ICON_SIZE_SMALL
114
-                         ) . "</div>'
114
+                            ) . "</div>'
115 115
                     );
116 116
                 }
117 117
             );
Please login to merge, or discard this patch.