2005-02-06 06:44:48 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
2006-01-07 08:50:07 +00:00
|
|
|
|
* XHTML sanitizer for MediaWiki
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*
|
|
|
|
|
|
* Copyright (C) 2002-2005 Brion Vibber <brion@pobox.com> et al
|
|
|
|
|
|
* http://www.mediawiki.org/
|
|
|
|
|
|
*
|
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2006-01-07 13:09:30 +00:00
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
2005-02-06 06:44:48 +00:00
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
*
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
2006-04-05 07:43:17 +00:00
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-02-06 06:44:48 +00:00
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
|
|
*
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
* @file
|
|
|
|
|
|
* @ingroup Parser
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Regular expression to match various types of character references in
|
|
|
|
|
|
* Sanitizer::normalizeCharReferences and Sanitizer::decodeCharReferences
|
|
|
|
|
|
*/
|
|
|
|
|
|
define( 'MW_CHAR_REFS_REGEX',
|
2007-04-29 08:28:34 +00:00
|
|
|
|
'/&([A-Za-z0-9\x80-\xff]+);
|
2005-05-31 11:54:36 +00:00
|
|
|
|
|&\#([0-9]+);
|
|
|
|
|
|
|&\#x([0-9A-Za-z]+);
|
|
|
|
|
|
|&\#X([0-9A-Za-z]+);
|
|
|
|
|
|
|(&)/x' );
|
|
|
|
|
|
|
2005-06-03 08:12:48 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Regular expression to match HTML/XML attribute pairs within a tag.
|
|
|
|
|
|
* Allows some... latitude.
|
|
|
|
|
|
* Used in Sanitizer::fixTagAttributes and Sanitizer::decodeTagAttributes
|
|
|
|
|
|
*/
|
2006-01-07 13:09:30 +00:00
|
|
|
|
$attrib = '[A-Za-z0-9]';
|
2005-06-03 08:12:48 +00:00
|
|
|
|
$space = '[\x09\x0a\x0d\x20]';
|
|
|
|
|
|
define( 'MW_ATTRIBS_REGEX',
|
|
|
|
|
|
"/(?:^|$space)($attrib+)
|
|
|
|
|
|
($space*=$space*
|
|
|
|
|
|
(?:
|
|
|
|
|
|
# The attribute value: quoted or alone
|
|
|
|
|
|
\"([^<\"]*)\"
|
|
|
|
|
|
| '([^<']*)'
|
|
|
|
|
|
| ([a-zA-Z0-9!#$%&()*,\\-.\\/:;<>?@[\\]^_`{|}~]+)
|
|
|
|
|
|
| (\#[0-9a-fA-F]+) # Technically wrong, but lots of
|
|
|
|
|
|
# colors are specified like this.
|
|
|
|
|
|
# We'll be normalizing it.
|
|
|
|
|
|
)
|
|
|
|
|
|
)?(?=$space|\$)/sx" );
|
|
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* List of all named character entities defined in HTML 4.01
|
|
|
|
|
|
* http://www.w3.org/TR/html4/sgml/entities.html
|
2006-04-24 19:22:18 +00:00
|
|
|
|
* @private
|
2005-05-31 11:54:36 +00:00
|
|
|
|
*/
|
|
|
|
|
|
global $wgHtmlEntities;
|
|
|
|
|
|
$wgHtmlEntities = array(
|
|
|
|
|
|
'Aacute' => 193,
|
|
|
|
|
|
'aacute' => 225,
|
|
|
|
|
|
'Acirc' => 194,
|
|
|
|
|
|
'acirc' => 226,
|
|
|
|
|
|
'acute' => 180,
|
|
|
|
|
|
'AElig' => 198,
|
|
|
|
|
|
'aelig' => 230,
|
|
|
|
|
|
'Agrave' => 192,
|
|
|
|
|
|
'agrave' => 224,
|
|
|
|
|
|
'alefsym' => 8501,
|
|
|
|
|
|
'Alpha' => 913,
|
|
|
|
|
|
'alpha' => 945,
|
|
|
|
|
|
'amp' => 38,
|
|
|
|
|
|
'and' => 8743,
|
|
|
|
|
|
'ang' => 8736,
|
|
|
|
|
|
'Aring' => 197,
|
|
|
|
|
|
'aring' => 229,
|
|
|
|
|
|
'asymp' => 8776,
|
|
|
|
|
|
'Atilde' => 195,
|
|
|
|
|
|
'atilde' => 227,
|
|
|
|
|
|
'Auml' => 196,
|
|
|
|
|
|
'auml' => 228,
|
|
|
|
|
|
'bdquo' => 8222,
|
|
|
|
|
|
'Beta' => 914,
|
|
|
|
|
|
'beta' => 946,
|
|
|
|
|
|
'brvbar' => 166,
|
|
|
|
|
|
'bull' => 8226,
|
|
|
|
|
|
'cap' => 8745,
|
|
|
|
|
|
'Ccedil' => 199,
|
|
|
|
|
|
'ccedil' => 231,
|
|
|
|
|
|
'cedil' => 184,
|
|
|
|
|
|
'cent' => 162,
|
|
|
|
|
|
'Chi' => 935,
|
|
|
|
|
|
'chi' => 967,
|
|
|
|
|
|
'circ' => 710,
|
|
|
|
|
|
'clubs' => 9827,
|
|
|
|
|
|
'cong' => 8773,
|
|
|
|
|
|
'copy' => 169,
|
|
|
|
|
|
'crarr' => 8629,
|
|
|
|
|
|
'cup' => 8746,
|
|
|
|
|
|
'curren' => 164,
|
|
|
|
|
|
'dagger' => 8224,
|
|
|
|
|
|
'Dagger' => 8225,
|
|
|
|
|
|
'darr' => 8595,
|
|
|
|
|
|
'dArr' => 8659,
|
|
|
|
|
|
'deg' => 176,
|
|
|
|
|
|
'Delta' => 916,
|
|
|
|
|
|
'delta' => 948,
|
|
|
|
|
|
'diams' => 9830,
|
|
|
|
|
|
'divide' => 247,
|
|
|
|
|
|
'Eacute' => 201,
|
|
|
|
|
|
'eacute' => 233,
|
|
|
|
|
|
'Ecirc' => 202,
|
|
|
|
|
|
'ecirc' => 234,
|
|
|
|
|
|
'Egrave' => 200,
|
|
|
|
|
|
'egrave' => 232,
|
|
|
|
|
|
'empty' => 8709,
|
|
|
|
|
|
'emsp' => 8195,
|
|
|
|
|
|
'ensp' => 8194,
|
|
|
|
|
|
'Epsilon' => 917,
|
|
|
|
|
|
'epsilon' => 949,
|
|
|
|
|
|
'equiv' => 8801,
|
|
|
|
|
|
'Eta' => 919,
|
|
|
|
|
|
'eta' => 951,
|
|
|
|
|
|
'ETH' => 208,
|
|
|
|
|
|
'eth' => 240,
|
|
|
|
|
|
'Euml' => 203,
|
|
|
|
|
|
'euml' => 235,
|
|
|
|
|
|
'euro' => 8364,
|
|
|
|
|
|
'exist' => 8707,
|
|
|
|
|
|
'fnof' => 402,
|
|
|
|
|
|
'forall' => 8704,
|
|
|
|
|
|
'frac12' => 189,
|
|
|
|
|
|
'frac14' => 188,
|
|
|
|
|
|
'frac34' => 190,
|
|
|
|
|
|
'frasl' => 8260,
|
|
|
|
|
|
'Gamma' => 915,
|
|
|
|
|
|
'gamma' => 947,
|
|
|
|
|
|
'ge' => 8805,
|
|
|
|
|
|
'gt' => 62,
|
|
|
|
|
|
'harr' => 8596,
|
|
|
|
|
|
'hArr' => 8660,
|
|
|
|
|
|
'hearts' => 9829,
|
|
|
|
|
|
'hellip' => 8230,
|
|
|
|
|
|
'Iacute' => 205,
|
|
|
|
|
|
'iacute' => 237,
|
|
|
|
|
|
'Icirc' => 206,
|
|
|
|
|
|
'icirc' => 238,
|
|
|
|
|
|
'iexcl' => 161,
|
|
|
|
|
|
'Igrave' => 204,
|
|
|
|
|
|
'igrave' => 236,
|
|
|
|
|
|
'image' => 8465,
|
|
|
|
|
|
'infin' => 8734,
|
|
|
|
|
|
'int' => 8747,
|
|
|
|
|
|
'Iota' => 921,
|
|
|
|
|
|
'iota' => 953,
|
|
|
|
|
|
'iquest' => 191,
|
|
|
|
|
|
'isin' => 8712,
|
|
|
|
|
|
'Iuml' => 207,
|
|
|
|
|
|
'iuml' => 239,
|
|
|
|
|
|
'Kappa' => 922,
|
|
|
|
|
|
'kappa' => 954,
|
|
|
|
|
|
'Lambda' => 923,
|
|
|
|
|
|
'lambda' => 955,
|
|
|
|
|
|
'lang' => 9001,
|
|
|
|
|
|
'laquo' => 171,
|
|
|
|
|
|
'larr' => 8592,
|
|
|
|
|
|
'lArr' => 8656,
|
|
|
|
|
|
'lceil' => 8968,
|
|
|
|
|
|
'ldquo' => 8220,
|
|
|
|
|
|
'le' => 8804,
|
|
|
|
|
|
'lfloor' => 8970,
|
|
|
|
|
|
'lowast' => 8727,
|
|
|
|
|
|
'loz' => 9674,
|
|
|
|
|
|
'lrm' => 8206,
|
|
|
|
|
|
'lsaquo' => 8249,
|
|
|
|
|
|
'lsquo' => 8216,
|
|
|
|
|
|
'lt' => 60,
|
|
|
|
|
|
'macr' => 175,
|
|
|
|
|
|
'mdash' => 8212,
|
|
|
|
|
|
'micro' => 181,
|
|
|
|
|
|
'middot' => 183,
|
|
|
|
|
|
'minus' => 8722,
|
|
|
|
|
|
'Mu' => 924,
|
|
|
|
|
|
'mu' => 956,
|
|
|
|
|
|
'nabla' => 8711,
|
|
|
|
|
|
'nbsp' => 160,
|
|
|
|
|
|
'ndash' => 8211,
|
|
|
|
|
|
'ne' => 8800,
|
|
|
|
|
|
'ni' => 8715,
|
|
|
|
|
|
'not' => 172,
|
|
|
|
|
|
'notin' => 8713,
|
|
|
|
|
|
'nsub' => 8836,
|
|
|
|
|
|
'Ntilde' => 209,
|
|
|
|
|
|
'ntilde' => 241,
|
|
|
|
|
|
'Nu' => 925,
|
|
|
|
|
|
'nu' => 957,
|
|
|
|
|
|
'Oacute' => 211,
|
|
|
|
|
|
'oacute' => 243,
|
|
|
|
|
|
'Ocirc' => 212,
|
|
|
|
|
|
'ocirc' => 244,
|
|
|
|
|
|
'OElig' => 338,
|
|
|
|
|
|
'oelig' => 339,
|
|
|
|
|
|
'Ograve' => 210,
|
|
|
|
|
|
'ograve' => 242,
|
|
|
|
|
|
'oline' => 8254,
|
|
|
|
|
|
'Omega' => 937,
|
|
|
|
|
|
'omega' => 969,
|
|
|
|
|
|
'Omicron' => 927,
|
|
|
|
|
|
'omicron' => 959,
|
|
|
|
|
|
'oplus' => 8853,
|
|
|
|
|
|
'or' => 8744,
|
|
|
|
|
|
'ordf' => 170,
|
|
|
|
|
|
'ordm' => 186,
|
|
|
|
|
|
'Oslash' => 216,
|
|
|
|
|
|
'oslash' => 248,
|
|
|
|
|
|
'Otilde' => 213,
|
|
|
|
|
|
'otilde' => 245,
|
|
|
|
|
|
'otimes' => 8855,
|
|
|
|
|
|
'Ouml' => 214,
|
|
|
|
|
|
'ouml' => 246,
|
|
|
|
|
|
'para' => 182,
|
|
|
|
|
|
'part' => 8706,
|
|
|
|
|
|
'permil' => 8240,
|
|
|
|
|
|
'perp' => 8869,
|
|
|
|
|
|
'Phi' => 934,
|
|
|
|
|
|
'phi' => 966,
|
|
|
|
|
|
'Pi' => 928,
|
|
|
|
|
|
'pi' => 960,
|
|
|
|
|
|
'piv' => 982,
|
|
|
|
|
|
'plusmn' => 177,
|
|
|
|
|
|
'pound' => 163,
|
|
|
|
|
|
'prime' => 8242,
|
|
|
|
|
|
'Prime' => 8243,
|
|
|
|
|
|
'prod' => 8719,
|
|
|
|
|
|
'prop' => 8733,
|
|
|
|
|
|
'Psi' => 936,
|
|
|
|
|
|
'psi' => 968,
|
|
|
|
|
|
'quot' => 34,
|
|
|
|
|
|
'radic' => 8730,
|
|
|
|
|
|
'rang' => 9002,
|
|
|
|
|
|
'raquo' => 187,
|
|
|
|
|
|
'rarr' => 8594,
|
|
|
|
|
|
'rArr' => 8658,
|
|
|
|
|
|
'rceil' => 8969,
|
|
|
|
|
|
'rdquo' => 8221,
|
|
|
|
|
|
'real' => 8476,
|
|
|
|
|
|
'reg' => 174,
|
|
|
|
|
|
'rfloor' => 8971,
|
|
|
|
|
|
'Rho' => 929,
|
|
|
|
|
|
'rho' => 961,
|
|
|
|
|
|
'rlm' => 8207,
|
|
|
|
|
|
'rsaquo' => 8250,
|
|
|
|
|
|
'rsquo' => 8217,
|
|
|
|
|
|
'sbquo' => 8218,
|
|
|
|
|
|
'Scaron' => 352,
|
|
|
|
|
|
'scaron' => 353,
|
|
|
|
|
|
'sdot' => 8901,
|
|
|
|
|
|
'sect' => 167,
|
|
|
|
|
|
'shy' => 173,
|
|
|
|
|
|
'Sigma' => 931,
|
|
|
|
|
|
'sigma' => 963,
|
|
|
|
|
|
'sigmaf' => 962,
|
|
|
|
|
|
'sim' => 8764,
|
|
|
|
|
|
'spades' => 9824,
|
|
|
|
|
|
'sub' => 8834,
|
|
|
|
|
|
'sube' => 8838,
|
|
|
|
|
|
'sum' => 8721,
|
|
|
|
|
|
'sup' => 8835,
|
|
|
|
|
|
'sup1' => 185,
|
|
|
|
|
|
'sup2' => 178,
|
|
|
|
|
|
'sup3' => 179,
|
|
|
|
|
|
'supe' => 8839,
|
|
|
|
|
|
'szlig' => 223,
|
|
|
|
|
|
'Tau' => 932,
|
|
|
|
|
|
'tau' => 964,
|
|
|
|
|
|
'there4' => 8756,
|
|
|
|
|
|
'Theta' => 920,
|
|
|
|
|
|
'theta' => 952,
|
|
|
|
|
|
'thetasym' => 977,
|
|
|
|
|
|
'thinsp' => 8201,
|
|
|
|
|
|
'THORN' => 222,
|
|
|
|
|
|
'thorn' => 254,
|
|
|
|
|
|
'tilde' => 732,
|
|
|
|
|
|
'times' => 215,
|
|
|
|
|
|
'trade' => 8482,
|
|
|
|
|
|
'Uacute' => 218,
|
|
|
|
|
|
'uacute' => 250,
|
|
|
|
|
|
'uarr' => 8593,
|
|
|
|
|
|
'uArr' => 8657,
|
|
|
|
|
|
'Ucirc' => 219,
|
|
|
|
|
|
'ucirc' => 251,
|
|
|
|
|
|
'Ugrave' => 217,
|
|
|
|
|
|
'ugrave' => 249,
|
|
|
|
|
|
'uml' => 168,
|
|
|
|
|
|
'upsih' => 978,
|
|
|
|
|
|
'Upsilon' => 933,
|
|
|
|
|
|
'upsilon' => 965,
|
|
|
|
|
|
'Uuml' => 220,
|
|
|
|
|
|
'uuml' => 252,
|
|
|
|
|
|
'weierp' => 8472,
|
|
|
|
|
|
'Xi' => 926,
|
|
|
|
|
|
'xi' => 958,
|
|
|
|
|
|
'Yacute' => 221,
|
|
|
|
|
|
'yacute' => 253,
|
|
|
|
|
|
'yen' => 165,
|
|
|
|
|
|
'Yuml' => 376,
|
|
|
|
|
|
'yuml' => 255,
|
|
|
|
|
|
'Zeta' => 918,
|
|
|
|
|
|
'zeta' => 950,
|
|
|
|
|
|
'zwj' => 8205,
|
|
|
|
|
|
'zwnj' => 8204 );
|
|
|
|
|
|
|
2007-04-29 08:28:34 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Character entity aliases accepted by MediaWiki
|
|
|
|
|
|
*/
|
|
|
|
|
|
global $wgHtmlEntityAliases;
|
|
|
|
|
|
$wgHtmlEntityAliases = array(
|
|
|
|
|
|
'רלמ' => 'rlm',
|
|
|
|
|
|
'رلم' => 'rlm',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-04-20 08:55:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* XHTML sanitizer for MediaWiki
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
* @ingroup Parser
|
2007-04-20 08:55:14 +00:00
|
|
|
|
*/
|
2005-02-06 06:44:48 +00:00
|
|
|
|
class Sanitizer {
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Cleans up HTML, removes dangerous tags and attributes, and
|
|
|
|
|
|
* removes HTML comments
|
2006-04-24 19:22:18 +00:00
|
|
|
|
* @private
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $processCallback Callback to do any variable or parameter replacements in HTML attribute values
|
|
|
|
|
|
* @param $args Array for the processing callback
|
|
|
|
|
|
* @param $extratags Array for any extra tags to include
|
|
|
|
|
|
* @param $removetags Array for any tags (default or extra) to exclude
|
2005-04-01 23:24:26 +00:00
|
|
|
|
* @return string
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*/
|
2009-04-19 23:48:50 +00:00
|
|
|
|
static function removeHTMLtags( $text, $processCallback = null, $args = array(), $extratags = array(), $removetags = array() ) {
|
2007-04-16 13:50:38 +00:00
|
|
|
|
global $wgUseTidy;
|
2005-02-06 06:44:48 +00:00
|
|
|
|
|
2009-04-21 21:54:47 +00:00
|
|
|
|
static $htmlpairsStatic, $htmlsingle, $htmlsingleonly, $htmlnest, $tabletags,
|
|
|
|
|
|
$htmllist, $listtags, $htmlsingleallowed, $htmlelementsStatic, $staticInitialised;
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if ( !$staticInitialised ) {
|
2006-05-02 18:34:28 +00:00
|
|
|
|
|
2009-04-21 21:54:47 +00:00
|
|
|
|
$htmlpairsStatic = array( # Tags that must be closed
|
2009-11-07 15:03:04 +00:00
|
|
|
|
'b', 'del', 'i', 'ins', 'u', 'font', 'big', 'small', 'sub', 'sup', 'h1',
|
2007-04-16 13:50:38 +00:00
|
|
|
|
'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's',
|
|
|
|
|
|
'strike', 'strong', 'tt', 'var', 'div', 'center',
|
|
|
|
|
|
'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre',
|
2009-08-02 22:15:28 +00:00
|
|
|
|
'ruby', 'rt' , 'rb' , 'rp', 'p', 'span', 'u', 'abbr'
|
2009-04-21 21:54:47 +00:00
|
|
|
|
);
|
2007-04-16 13:50:38 +00:00
|
|
|
|
$htmlsingle = array(
|
|
|
|
|
|
'br', 'hr', 'li', 'dt', 'dd'
|
|
|
|
|
|
);
|
|
|
|
|
|
$htmlsingleonly = array( # Elements that cannot have close tags
|
|
|
|
|
|
'br', 'hr'
|
|
|
|
|
|
);
|
|
|
|
|
|
$htmlnest = array( # Tags that can be nested--??
|
|
|
|
|
|
'table', 'tr', 'td', 'th', 'div', 'blockquote', 'ol', 'ul',
|
|
|
|
|
|
'dl', 'font', 'big', 'small', 'sub', 'sup', 'span'
|
|
|
|
|
|
);
|
|
|
|
|
|
$tabletags = array( # Can only appear inside table, we will close them
|
|
|
|
|
|
'td', 'th', 'tr',
|
|
|
|
|
|
);
|
|
|
|
|
|
$htmllist = array( # Tags used by list
|
|
|
|
|
|
'ul','ol',
|
|
|
|
|
|
);
|
|
|
|
|
|
$listtags = array( # Tags that can appear in a list
|
|
|
|
|
|
'li',
|
|
|
|
|
|
);
|
2006-08-06 14:01:47 +00:00
|
|
|
|
|
2009-04-19 23:48:50 +00:00
|
|
|
|
$htmlsingleallowed = array_unique( array_merge( $htmlsingle, $tabletags ) );
|
2009-04-21 21:54:47 +00:00
|
|
|
|
$htmlelementsStatic = array_unique( array_merge( $htmlsingle, $htmlpairsStatic, $htmlnest ) );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
|
2006-08-06 14:01:47 +00:00
|
|
|
|
# Convert them all to hashtables for faster lookup
|
2009-04-21 21:54:47 +00:00
|
|
|
|
$vars = array( 'htmlpairsStatic', 'htmlsingle', 'htmlsingleonly', 'htmlnest', 'tabletags',
|
|
|
|
|
|
'htmllist', 'listtags', 'htmlsingleallowed', 'htmlelementsStatic' );
|
2006-08-06 14:01:47 +00:00
|
|
|
|
foreach ( $vars as $var ) {
|
|
|
|
|
|
$$var = array_flip( $$var );
|
|
|
|
|
|
}
|
|
|
|
|
|
$staticInitialised = true;
|
|
|
|
|
|
}
|
2009-04-21 21:54:47 +00:00
|
|
|
|
# Populate $htmlpairs and $htmlelements with the $extratags and $removetags arrays
|
|
|
|
|
|
$extratags = array_flip( $extratags );
|
|
|
|
|
|
$removetags = array_flip( $removetags );
|
|
|
|
|
|
$htmlpairs = array_merge( $extratags, $htmlpairsStatic );
|
2009-05-23 02:24:54 +00:00
|
|
|
|
$htmlelements = array_diff_key( array_merge( $extratags, $htmlelementsStatic ) , $removetags );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
|
|
|
|
|
|
# Remove HTML comments
|
|
|
|
|
|
$text = Sanitizer::removeHTMLcomments( $text );
|
|
|
|
|
|
$bits = explode( '<', $text );
|
2007-01-17 21:52:37 +00:00
|
|
|
|
$text = str_replace( '>', '>', array_shift( $bits ) );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
if(!$wgUseTidy) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
$tagstack = $tablestack = array();
|
2005-02-06 06:44:48 +00:00
|
|
|
|
foreach ( $bits as $x ) {
|
2006-11-23 08:25:56 +00:00
|
|
|
|
$regs = array();
|
2006-11-29 05:45:03 +00:00
|
|
|
|
if( preg_match( '!^(/?)(\\w+)([^>]*?)(/{0,1}>)([^<]*)$!', $x, $regs ) ) {
|
|
|
|
|
|
list( /* $qbar */, $slash, $t, $params, $brace, $rest ) = $regs;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$slash = $t = $params = $brace = $rest = null;
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2005-02-06 06:44:48 +00:00
|
|
|
|
$badtag = 0 ;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if ( isset( $htmlelements[$t = strtolower( $t )] ) ) {
|
2005-02-06 06:44:48 +00:00
|
|
|
|
# Check our stack
|
|
|
|
|
|
if ( $slash ) {
|
|
|
|
|
|
# Closing a tag...
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if( isset( $htmlsingleonly[$t] ) ) {
|
2005-06-06 03:04:12 +00:00
|
|
|
|
$badtag = 1;
|
2006-01-07 04:57:38 +00:00
|
|
|
|
} elseif ( ( $ot = @array_pop( $tagstack ) ) != $t ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if ( isset( $htmlsingleallowed[$ot] ) ) {
|
2006-06-03 00:01:01 +00:00
|
|
|
|
# Pop all elements with an optional close tag
|
|
|
|
|
|
# and see if we find a match below them
|
|
|
|
|
|
$optstack = array();
|
|
|
|
|
|
array_push ($optstack, $ot);
|
|
|
|
|
|
while ( ( ( $ot = @array_pop( $tagstack ) ) != $t ) &&
|
2008-04-14 07:45:50 +00:00
|
|
|
|
isset( $htmlsingleallowed[$ot] ) )
|
2006-08-06 14:01:47 +00:00
|
|
|
|
{
|
2006-06-03 00:01:01 +00:00
|
|
|
|
array_push ($optstack, $ot);
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $t != $ot ) {
|
|
|
|
|
|
# No match. Push the optinal elements back again
|
|
|
|
|
|
$badtag = 1;
|
|
|
|
|
|
while ( $ot = @array_pop( $optstack ) ) {
|
|
|
|
|
|
array_push( $tagstack, $ot );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
@array_push( $tagstack, $ot );
|
|
|
|
|
|
# <li> can be nested in <ul> or <ol>, skip those cases:
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if(!(isset( $htmllist[$ot] ) && isset( $listtags[$t] ) )) {
|
2006-06-03 00:01:01 +00:00
|
|
|
|
$badtag = 1;
|
|
|
|
|
|
}
|
2006-05-02 18:34:28 +00:00
|
|
|
|
}
|
2005-02-06 06:44:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
if ( $t == 'table' ) {
|
|
|
|
|
|
$tagstack = array_pop( $tablestack );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-06-01 04:35:19 +00:00
|
|
|
|
$newparams = '';
|
2005-02-06 06:44:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# Keep track for later
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if ( isset( $tabletags[$t] ) &&
|
2005-02-06 06:44:48 +00:00
|
|
|
|
! in_array( 'table', $tagstack ) ) {
|
|
|
|
|
|
$badtag = 1;
|
|
|
|
|
|
} else if ( in_array( $t, $tagstack ) &&
|
2006-08-06 14:01:47 +00:00
|
|
|
|
! isset( $htmlnest [$t ] ) ) {
|
2005-02-06 06:44:48 +00:00
|
|
|
|
$badtag = 1 ;
|
2006-04-30 11:50:36 +00:00
|
|
|
|
# Is it a self closed htmlpair ? (bug 5487)
|
|
|
|
|
|
} else if( $brace == '/>' &&
|
2006-08-06 14:01:47 +00:00
|
|
|
|
isset( $htmlpairs[$t] ) ) {
|
2006-04-30 11:50:36 +00:00
|
|
|
|
$badtag = 1;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
} elseif( isset( $htmlsingleonly[$t] ) ) {
|
2005-06-06 03:04:12 +00:00
|
|
|
|
# Hack to force empty tag for uncloseable elements
|
|
|
|
|
|
$brace = '/>';
|
2006-08-06 14:01:47 +00:00
|
|
|
|
} else if( isset( $htmlsingle[$t] ) ) {
|
2006-04-24 19:25:14 +00:00
|
|
|
|
# Hack to not close $htmlsingle tags
|
|
|
|
|
|
$brace = NULL;
|
2007-01-17 20:55:26 +00:00
|
|
|
|
} else if( isset( $tabletags[$t] )
|
|
|
|
|
|
&& in_array($t ,$tagstack) ) {
|
|
|
|
|
|
// New table tag but forgot to close the previous one
|
|
|
|
|
|
$text .= "</$t>";
|
2006-01-07 04:57:38 +00:00
|
|
|
|
} else {
|
2005-02-06 06:44:48 +00:00
|
|
|
|
if ( $t == 'table' ) {
|
|
|
|
|
|
array_push( $tablestack, $tagstack );
|
|
|
|
|
|
$tagstack = array();
|
|
|
|
|
|
}
|
|
|
|
|
|
array_push( $tagstack, $t );
|
|
|
|
|
|
}
|
2005-06-06 01:46:03 +00:00
|
|
|
|
|
|
|
|
|
|
# Replace any variables or template parameters with
|
|
|
|
|
|
# plaintext results.
|
|
|
|
|
|
if( is_callable( $processCallback ) ) {
|
|
|
|
|
|
call_user_func_array( $processCallback, array( &$params, $args ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-02-06 06:44:48 +00:00
|
|
|
|
# Strip non-approved attributes from the tag
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$newparams = Sanitizer::fixTagAttributes( $params, $t );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( ! $badtag ) {
|
|
|
|
|
|
$rest = str_replace( '>', '>', $rest );
|
2007-01-17 22:06:32 +00:00
|
|
|
|
$close = ( $brace == '/>' && !$slash ) ? ' /' : '';
|
2005-06-06 03:04:12 +00:00
|
|
|
|
$text .= "<$slash$t$newparams$close>$rest";
|
2005-02-06 06:44:48 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$text .= '<' . str_replace( '>', '>', $x);
|
|
|
|
|
|
}
|
|
|
|
|
|
# Close off any remaining tags
|
|
|
|
|
|
while ( is_array( $tagstack ) && ($t = array_pop( $tagstack )) ) {
|
|
|
|
|
|
$text .= "</$t>\n";
|
|
|
|
|
|
if ( $t == 'table' ) { $tagstack = array_pop( $tablestack ); }
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# this might be possible using tidy itself
|
|
|
|
|
|
foreach ( $bits as $x ) {
|
2005-06-06 03:04:12 +00:00
|
|
|
|
preg_match( '/^(\\/?)(\\w+)([^>]*?)(\\/{0,1}>)([^<]*)$/',
|
2005-02-06 06:44:48 +00:00
|
|
|
|
$x, $regs );
|
2006-11-23 08:25:56 +00:00
|
|
|
|
@list( /* $qbar */, $slash, $t, $params, $brace, $rest ) = $regs;
|
2006-08-06 14:01:47 +00:00
|
|
|
|
if ( isset( $htmlelements[$t = strtolower( $t )] ) ) {
|
2005-06-06 01:46:03 +00:00
|
|
|
|
if( is_callable( $processCallback ) ) {
|
|
|
|
|
|
call_user_func_array( $processCallback, array( &$params, $args ) );
|
|
|
|
|
|
}
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$newparams = Sanitizer::fixTagAttributes( $params, $t );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
$rest = str_replace( '>', '>', $rest );
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$text .= "<$slash$t$newparams$brace$rest";
|
2005-02-06 06:44:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$text .= '<' . str_replace( '>', '>', $x);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Remove '<!--', '-->', and everything between.
|
|
|
|
|
|
* To avoid leaving blank lines, when a comment is both preceded
|
|
|
|
|
|
* and followed by a newline (ignoring spaces), trim leading and
|
|
|
|
|
|
* trailing spaces and one of the newlines.
|
2006-01-07 13:09:30 +00:00
|
|
|
|
*
|
2006-04-24 19:22:18 +00:00
|
|
|
|
* @private
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
2005-04-01 23:24:26 +00:00
|
|
|
|
* @return string
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function removeHTMLcomments( $text ) {
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileIn( __METHOD__ );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
while (($start = strpos($text, '<!--')) !== false) {
|
|
|
|
|
|
$end = strpos($text, '-->', $start + 4);
|
|
|
|
|
|
if ($end === false) {
|
|
|
|
|
|
# Unterminated comment; bail out
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$end += 3;
|
|
|
|
|
|
|
|
|
|
|
|
# Trim space and newline if the comment is both
|
|
|
|
|
|
# preceded and followed by a newline
|
|
|
|
|
|
$spaceStart = max($start - 1, 0);
|
|
|
|
|
|
$spaceLen = $end - $spaceStart;
|
|
|
|
|
|
while (substr($text, $spaceStart, 1) === ' ' && $spaceStart > 0) {
|
|
|
|
|
|
$spaceStart--;
|
|
|
|
|
|
$spaceLen++;
|
|
|
|
|
|
}
|
|
|
|
|
|
while (substr($text, $spaceStart + $spaceLen, 1) === ' ')
|
|
|
|
|
|
$spaceLen++;
|
|
|
|
|
|
if (substr($text, $spaceStart, 1) === "\n" and substr($text, $spaceStart + $spaceLen, 1) === "\n") {
|
|
|
|
|
|
# Remove the comment, leading and trailing
|
|
|
|
|
|
# spaces, and leave only one newline.
|
|
|
|
|
|
$text = substr_replace($text, "\n", $spaceStart, $spaceLen + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
# Remove just the comment.
|
|
|
|
|
|
$text = substr_replace($text, '', $start, $end - $start);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-08-06 14:01:47 +00:00
|
|
|
|
wfProfileOut( __METHOD__ );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2006-06-06 22:56:38 +00:00
|
|
|
|
* Take an array of attribute names and values and normalize or discard
|
|
|
|
|
|
* illegal values for the given element type.
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*
|
|
|
|
|
|
* - Discards attributes not on a whitelist for the given element
|
|
|
|
|
|
* - Unsafe style attributes are discarded
|
2007-07-13 17:25:06 +00:00
|
|
|
|
* - Invalid id attributes are reencoded
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $attribs Array
|
|
|
|
|
|
* @param $element String
|
|
|
|
|
|
* @return Array
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @todo Check for legal values where the DTD limits things.
|
|
|
|
|
|
* @todo Check for unique id attribute :P
|
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function validateTagAttributes( $attribs, $element ) {
|
2007-07-13 17:25:06 +00:00
|
|
|
|
return Sanitizer::validateAttributes( $attribs,
|
|
|
|
|
|
Sanitizer::attributeWhitelist( $element ) );
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-07-13 17:25:06 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Take an array of attribute names and values and normalize or discard
|
|
|
|
|
|
* illegal values for the given whitelist.
|
|
|
|
|
|
*
|
|
|
|
|
|
* - Discards attributes not the given whitelist
|
|
|
|
|
|
* - Unsafe style attributes are discarded
|
|
|
|
|
|
* - Invalid id attributes are reencoded
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $attribs Array
|
|
|
|
|
|
* @param $whitelist Array: list of allowed attribute names
|
|
|
|
|
|
* @return Array
|
2007-07-13 17:25:06 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @todo Check for legal values where the DTD limits things.
|
|
|
|
|
|
* @todo Check for unique id attribute :P
|
|
|
|
|
|
*/
|
|
|
|
|
|
static function validateAttributes( $attribs, $whitelist ) {
|
|
|
|
|
|
$whitelist = array_flip( $whitelist );
|
2006-06-06 22:56:38 +00:00
|
|
|
|
$out = array();
|
|
|
|
|
|
foreach( $attribs as $attribute => $value ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
if( !isset( $whitelist[$attribute] ) ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
# Strip javascript "expression" from stylesheets.
|
|
|
|
|
|
# http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
|
2005-10-06 02:38:26 +00:00
|
|
|
|
if( $attribute == 'style' ) {
|
2006-07-02 22:45:16 +00:00
|
|
|
|
$value = Sanitizer::checkCss( $value );
|
|
|
|
|
|
if( $value === false ) {
|
2005-10-06 02:38:26 +00:00
|
|
|
|
# haxx0r
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2005-02-06 12:46:31 +00:00
|
|
|
|
}
|
2006-01-07 08:50:07 +00:00
|
|
|
|
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
if ( $attribute === 'id' ) {
|
|
|
|
|
|
global $wgEnforceHtmlIds;
|
|
|
|
|
|
$value = Sanitizer::escapeId( $value,
|
2009-01-05 15:59:35 +00:00
|
|
|
|
$wgEnforceHtmlIds ? 'noninitial' : 'xml' );
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2009-11-07 15:13:38 +00:00
|
|
|
|
//RDFa properties allow URIs. check them
|
|
|
|
|
|
if ( $attribute === 'rel' || $attribute === 'rev' ||
|
|
|
|
|
|
$attribute === 'about' || $attribute === 'property' || $attribute === 'resource' ||
|
|
|
|
|
|
$attribute === 'datatype' || $attribute === 'typeof' ) {
|
|
|
|
|
|
//Paranoia. Allow "simple" values but suppress javascript
|
|
|
|
|
|
if ( preg_match( '/(^|\s)javascript\s*:/i', $value ) ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-06-06 22:56:38 +00:00
|
|
|
|
// If this attribute was previously set, override it.
|
|
|
|
|
|
// Output should only have one attribute of each name.
|
|
|
|
|
|
$out[$attribute] = $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
return $out;
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-07-13 17:25:06 +00:00
|
|
|
|
/**
|
2008-07-30 22:02:23 +00:00
|
|
|
|
* Merge two sets of HTML attributes. Conflicting items in the second set
|
|
|
|
|
|
* will override those in the first, except for 'class' attributes which
|
|
|
|
|
|
* will be combined (if they're both strings).
|
2007-07-13 17:25:06 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @todo implement merging for other attributes such as style
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $a Array
|
|
|
|
|
|
* @param $b Array
|
2007-07-13 17:25:06 +00:00
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
|
|
|
|
|
static function mergeAttributes( $a, $b ) {
|
|
|
|
|
|
$out = array_merge( $a, $b );
|
2008-07-30 22:02:23 +00:00
|
|
|
|
if( isset( $a['class'] ) && isset( $b['class'] )
|
|
|
|
|
|
&& is_string( $a['class'] ) && is_string( $b['class'] )
|
|
|
|
|
|
&& $a['class'] !== $b['class'] ) {
|
|
|
|
|
|
$classes = preg_split( '/\s+/', "{$a['class']} {$b['class']}",
|
|
|
|
|
|
-1, PREG_SPLIT_NO_EMPTY );
|
|
|
|
|
|
$out['class'] = implode( ' ', array_unique( $classes ) );
|
2007-07-13 17:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $out;
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-07-02 22:45:16 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Pick apart some CSS and check it for forbidden or unsafe structures.
|
|
|
|
|
|
* Returns a sanitized string, or false if it was just too evil.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Currently URL references, 'expression', 'tps' are forbidden.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $value String
|
|
|
|
|
|
* @return Mixed
|
2006-07-02 22:45:16 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function checkCss( $value ) {
|
|
|
|
|
|
$stripped = Sanitizer::decodeCharReferences( $value );
|
|
|
|
|
|
|
|
|
|
|
|
// Remove any comments; IE gets token splitting wrong
|
2006-11-22 07:08:50 +00:00
|
|
|
|
$stripped = StringUtils::delimiterReplace( '/*', '*/', ' ', $stripped );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-07-02 22:45:16 +00:00
|
|
|
|
$value = $stripped;
|
|
|
|
|
|
|
|
|
|
|
|
// ... and continue checks
|
|
|
|
|
|
$stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e',
|
|
|
|
|
|
'codepointToUtf8(hexdec("$1"))', $stripped );
|
|
|
|
|
|
$stripped = str_replace( '\\', '', $stripped );
|
2007-04-13 00:23:49 +00:00
|
|
|
|
if( preg_match( '/(?:expression|tps*:\/\/|url\\s*\().*/is',
|
2006-07-02 22:45:16 +00:00
|
|
|
|
$stripped ) ) {
|
|
|
|
|
|
# haxx0r
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2006-07-02 22:45:16 +00:00
|
|
|
|
return $value;
|
|
|
|
|
|
}
|
2006-06-06 22:56:38 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Take a tag soup fragment listing an HTML element's attributes
|
|
|
|
|
|
* and normalize it to well-formed XML, discarding unwanted attributes.
|
|
|
|
|
|
* Output is safe for further wikitext processing, with escaping of
|
|
|
|
|
|
* values that could trigger problems.
|
|
|
|
|
|
*
|
|
|
|
|
|
* - Normalizes attribute names to lowercase
|
|
|
|
|
|
* - Discards attributes not on a whitelist for the given element
|
|
|
|
|
|
* - Turns broken or invalid entities into plaintext
|
|
|
|
|
|
* - Double-quotes all attribute values
|
|
|
|
|
|
* - Attributes without values are given the name as attribute
|
|
|
|
|
|
* - Double attributes are discarded
|
|
|
|
|
|
* - Unsafe style attributes are discarded
|
|
|
|
|
|
* - Prepends space if there are attributes.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @param $element String
|
|
|
|
|
|
* @return String
|
2006-06-06 22:56:38 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function fixTagAttributes( $text, $element ) {
|
2006-06-06 22:56:38 +00:00
|
|
|
|
if( trim( $text ) == '' ) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-06 22:56:38 +00:00
|
|
|
|
$stripped = Sanitizer::validateTagAttributes(
|
|
|
|
|
|
Sanitizer::decodeTagAttributes( $text ), $element );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-06 22:56:38 +00:00
|
|
|
|
$attribs = array();
|
|
|
|
|
|
foreach( $stripped as $attribute => $value ) {
|
|
|
|
|
|
$encAttribute = htmlspecialchars( $attribute );
|
2006-06-09 21:21:00 +00:00
|
|
|
|
$encValue = Sanitizer::safeEncodeAttribute( $value );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-06 22:56:38 +00:00
|
|
|
|
$attribs[] = "$encAttribute=\"$encValue\"";
|
2005-02-06 12:46:31 +00:00
|
|
|
|
}
|
2006-01-07 08:50:07 +00:00
|
|
|
|
return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Encode an attribute value for HTML output.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
2006-06-09 21:21:00 +00:00
|
|
|
|
* @return HTML-encoded text fragment
|
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function encodeAttribute( $text ) {
|
2007-09-24 12:54:00 +00:00
|
|
|
|
$encValue = htmlspecialchars( $text, ENT_QUOTES );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
// Whitespace is normalized during attribute decoding,
|
|
|
|
|
|
// so if we've been passed non-spaces we must encode them
|
|
|
|
|
|
// ahead of time or they won't be preserved.
|
|
|
|
|
|
$encValue = strtr( $encValue, array(
|
|
|
|
|
|
"\n" => ' ',
|
|
|
|
|
|
"\r" => ' ',
|
|
|
|
|
|
"\t" => '	',
|
|
|
|
|
|
) );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
return $encValue;
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Encode an attribute value for HTML tags, with extra armoring
|
|
|
|
|
|
* against further wiki processing.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
2006-06-09 21:21:00 +00:00
|
|
|
|
* @return HTML-encoded text fragment
|
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function safeEncodeAttribute( $text ) {
|
2006-06-09 21:21:00 +00:00
|
|
|
|
$encValue = Sanitizer::encodeAttribute( $text );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
# Templates and links may be expanded in later parsing,
|
|
|
|
|
|
# creating invalid or dangerous output. Suppress this.
|
|
|
|
|
|
$encValue = strtr( $encValue, array(
|
|
|
|
|
|
'<' => '<', // This should never happen,
|
|
|
|
|
|
'>' => '>', // we've received invalid input
|
|
|
|
|
|
'"' => '"', // which should have been escaped.
|
|
|
|
|
|
'{' => '{',
|
|
|
|
|
|
'[' => '[',
|
|
|
|
|
|
"''" => '''',
|
|
|
|
|
|
'ISBN' => 'ISBN',
|
|
|
|
|
|
'RFC' => 'RFC',
|
|
|
|
|
|
'PMID' => 'PMID',
|
|
|
|
|
|
'|' => '|',
|
|
|
|
|
|
'__' => '__',
|
|
|
|
|
|
) );
|
|
|
|
|
|
|
|
|
|
|
|
# Stupid hack
|
|
|
|
|
|
$encValue = preg_replace_callback(
|
|
|
|
|
|
'/(' . wfUrlProtocols() . ')/',
|
|
|
|
|
|
array( 'Sanitizer', 'armorLinksCallback' ),
|
|
|
|
|
|
$encValue );
|
|
|
|
|
|
return $encValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-01-07 08:50:07 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Given a value escape it so that it can be used in an id attribute and
|
|
|
|
|
|
* return it, this does not validate the value however (see first link)
|
|
|
|
|
|
*
|
Some small doc tweaks to reduce Doxygen warnings, namely:
* @link. You might think @link would surely mean "here comes a web URL" ... but @link is a valid command
in Doxygen, which means an entirely different kind of link (an internal link to somewhere, so that you can separate
documentation and implementation). The result is a mess, and the best solution I can see is to use "@see" instead of "@link".
* Warning: argument `nourl' of command @param is not found in the argument list of Linker::makeMediaLinkObj($title,$text='')
* Moving few class descriptions to right above classes, and/or formatting into Javadoc style.
* "@addtogroup Special Pages" --> "@addtogroup SpecialPage" so that all special pages have the same @addtogroup tag.
* @fixme --> @todo (must have missed these before)
* "@param $specialPage @see" remove the "@" in the "@see" to stop warning.
* @throws wants type, then a brief description, to stop warning.
This last one is for PHPdocumentor only, but it fixes something for PHPDocumentor, and should be neutral for Doxygen:
* WARNING in includes/api/ApiFormatYaml_spyc.php on line 860: docblock template never terminated with /**#@-*/
2007-04-18 09:50:10 +00:00
|
|
|
|
* @see http://www.w3.org/TR/html401/types.html#type-name Valid characters
|
2006-01-07 08:50:07 +00:00
|
|
|
|
* in the id and
|
|
|
|
|
|
* name attributes
|
Some small doc tweaks to reduce Doxygen warnings, namely:
* @link. You might think @link would surely mean "here comes a web URL" ... but @link is a valid command
in Doxygen, which means an entirely different kind of link (an internal link to somewhere, so that you can separate
documentation and implementation). The result is a mess, and the best solution I can see is to use "@see" instead of "@link".
* Warning: argument `nourl' of command @param is not found in the argument list of Linker::makeMediaLinkObj($title,$text='')
* Moving few class descriptions to right above classes, and/or formatting into Javadoc style.
* "@addtogroup Special Pages" --> "@addtogroup SpecialPage" so that all special pages have the same @addtogroup tag.
* @fixme --> @todo (must have missed these before)
* "@param $specialPage @see" remove the "@" in the "@see" to stop warning.
* @throws wants type, then a brief description, to stop warning.
This last one is for PHPdocumentor only, but it fixes something for PHPDocumentor, and should be neutral for Doxygen:
* WARNING in includes/api/ApiFormatYaml_spyc.php on line 860: docblock template never terminated with /**#@-*/
2007-04-18 09:50:10 +00:00
|
|
|
|
* @see http://www.w3.org/TR/html401/struct/links.html#h-12.2.3 Anchors with the id attribute
|
2006-01-07 08:50:07 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $id String: id to validate
|
|
|
|
|
|
* @param $options Mixed: string or array of strings (default is array()):
|
2008-12-30 00:22:14 +00:00
|
|
|
|
* 'noninitial': This is a non-initial fragment of an id, not a full id,
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
* so don't pay attention if the first character isn't valid at the
|
2008-12-30 00:22:14 +00:00
|
|
|
|
* beginning of an id.
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
* 'xml': Don't restrict the id to be HTML4-compatible. This option
|
|
|
|
|
|
* allows any alphabetic character to be used, per the XML standard.
|
|
|
|
|
|
* Therefore, it also completely changes the type of escaping: instead
|
|
|
|
|
|
* of weird dot-encoding, runs of invalid characters (mostly
|
|
|
|
|
|
* whitespace) are just compressed into a single underscore.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @return String
|
2006-01-07 08:50:07 +00:00
|
|
|
|
*/
|
2008-12-30 00:22:14 +00:00
|
|
|
|
static function escapeId( $id, $options = array() ) {
|
|
|
|
|
|
$options = (array)$options;
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
|
|
|
|
|
|
if ( !in_array( 'xml', $options ) ) {
|
|
|
|
|
|
# HTML4-style escaping
|
|
|
|
|
|
static $replace = array(
|
|
|
|
|
|
'%3A' => ':',
|
|
|
|
|
|
'%' => '.'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$id = urlencode( Sanitizer::decodeCharReferences( strtr( $id, ' ', '_' ) ) );
|
|
|
|
|
|
$id = str_replace( array_keys( $replace ), array_values( $replace ), $id );
|
|
|
|
|
|
|
2008-12-30 20:34:19 +00:00
|
|
|
|
if ( !preg_match( '/^[a-zA-Z]/', $id )
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
&& !in_array( 'noninitial', $options ) ) {
|
|
|
|
|
|
// Initial character must be a letter!
|
|
|
|
|
|
$id = "x$id";
|
|
|
|
|
|
}
|
|
|
|
|
|
return $id;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# XML-style escaping. For the patterns used, see the XML 1.0 standard,
|
|
|
|
|
|
# 5th edition, NameStartChar and NameChar: <http://www.w3.org/TR/REC-xml/>
|
|
|
|
|
|
$nameStartChar = ':a-zA-Z_\xC0-\xD6\xD8-\xF6\xF8-\x{2FF}\x{370}-\x{37D}'
|
|
|
|
|
|
. '\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}'
|
|
|
|
|
|
. '\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}';
|
|
|
|
|
|
$nameChar = $nameStartChar . '.\-0-9\xB7\x{0300}-\x{036F}'
|
|
|
|
|
|
. '\x{203F}-\x{2040}';
|
|
|
|
|
|
# Replace _ as well so we don't get multiple consecutive underscores
|
|
|
|
|
|
$id = preg_replace( "/([^$nameChar]|_)+/u", '_', $id );
|
|
|
|
|
|
$id = trim( $id, '_' );
|
|
|
|
|
|
|
|
|
|
|
|
if ( !preg_match( "/^[$nameStartChar]/u", $id )
|
|
|
|
|
|
&& !in_array( 'noninitial', $options ) ) {
|
|
|
|
|
|
$id = "_$id";
|
2007-08-31 04:43:56 +00:00
|
|
|
|
}
|
Optionally allow non-HTML4-compatible ids
This adds a config option, $wgEnforceHtmlIds, true by default. If this
is set to false, all characters that are allowed in XML ids are let
through in header ids and manually-specified ids. In particular, this
should include all alphabetic and numeric characters.
Some remaining issues to work out:
* This will cause backward-compatibility issues for some types of links
and references: links from non-MediaWiki sources, links from MediaWiki
sources running a different version, external links, and references from
stylesheets/scripts. These could be partially alleviated by having a
second <a name="" id=""> for headers where the two versions differ, but
it would remain an issue for manually-specified id's.
* Any invalid characters are now, effectively, stripped (replaced with
underscores). This might cause problems if some writing systems are
invalid in id's for some reason: we'll want to double-check the list of
prohibited characters carefully.
* Some user agents might not support these links. IE5 appears to, and
so do recent versions of Opera and Firefox, but I didn't do extensive
testing.
* Not tested extensively, there are probably some bugs.
I think this would be good to enable on testwiki for the moment to see
how it goes.
No parser test regressions. No change to RELEASE-NOTES, we can add that
when the option is enabled by default (ideally, removed entirely).
2008-12-30 00:22:34 +00:00
|
|
|
|
|
2007-08-31 04:43:56 +00:00
|
|
|
|
return $id;
|
2005-02-06 12:46:31 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2006-10-20 03:28:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Given a value, escape it so that it can be used as a CSS class and
|
|
|
|
|
|
* return it.
|
|
|
|
|
|
*
|
2007-01-15 16:29:41 +00:00
|
|
|
|
* @todo For extra validity, input should be validated UTF-8.
|
2006-10-20 03:28:05 +00:00
|
|
|
|
*
|
Some small doc tweaks to reduce Doxygen warnings, namely:
* @link. You might think @link would surely mean "here comes a web URL" ... but @link is a valid command
in Doxygen, which means an entirely different kind of link (an internal link to somewhere, so that you can separate
documentation and implementation). The result is a mess, and the best solution I can see is to use "@see" instead of "@link".
* Warning: argument `nourl' of command @param is not found in the argument list of Linker::makeMediaLinkObj($title,$text='')
* Moving few class descriptions to right above classes, and/or formatting into Javadoc style.
* "@addtogroup Special Pages" --> "@addtogroup SpecialPage" so that all special pages have the same @addtogroup tag.
* @fixme --> @todo (must have missed these before)
* "@param $specialPage @see" remove the "@" in the "@see" to stop warning.
* @throws wants type, then a brief description, to stop warning.
This last one is for PHPdocumentor only, but it fixes something for PHPDocumentor, and should be neutral for Doxygen:
* WARNING in includes/api/ApiFormatYaml_spyc.php on line 860: docblock template never terminated with /**#@-*/
2007-04-18 09:50:10 +00:00
|
|
|
|
* @see http://www.w3.org/TR/CSS21/syndata.html Valid characters/format
|
2006-10-20 03:28:05 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $class String
|
|
|
|
|
|
* @return String
|
2006-10-20 03:28:05 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function escapeClass( $class ) {
|
|
|
|
|
|
// Convert ugly stuff to underscores and kill underscores in ugly places
|
|
|
|
|
|
return rtrim(preg_replace(
|
|
|
|
|
|
array('/(^[0-9\\-])|[\\x00-\\x20!"#$%&\'()*+,.\\/:;<=>?@[\\]^`{|}~]|\\xC2\\xA0/','/_+/'),
|
|
|
|
|
|
'_',
|
|
|
|
|
|
$class ), '_');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-08-18 18:15:47 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Given HTML input, escape with htmlspecialchars but un-escape entites.
|
|
|
|
|
|
* This allows (generally harmless) entities like to survive.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $html String to escape
|
|
|
|
|
|
* @return String: escaped input
|
2008-08-18 18:15:47 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function escapeHtmlAllowEntities( $html ) {
|
|
|
|
|
|
# It seems wise to escape ' as well as ", as a matter of course. Can't
|
|
|
|
|
|
# hurt.
|
|
|
|
|
|
$html = htmlspecialchars( $html, ENT_QUOTES );
|
|
|
|
|
|
$html = str_replace( '&', '&', $html );
|
|
|
|
|
|
$html = Sanitizer::normalizeCharReferences( $html );
|
|
|
|
|
|
return $html;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-08-23 21:49:48 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Regex replace callback for armoring links against further processing.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $matches Array
|
2005-08-23 21:49:48 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
private static function armorLinksCallback( $matches ) {
|
2005-08-23 21:49:48 +00:00
|
|
|
|
return str_replace( ':', ':', $matches[1] );
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-06-03 08:12:48 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return an associative array of attribute names and values from
|
|
|
|
|
|
* a partial tag string. Attribute names are forces to lowercase,
|
|
|
|
|
|
* character references are decoded to UTF-8 text.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return Array
|
2005-06-03 08:12:48 +00:00
|
|
|
|
*/
|
2008-08-05 17:05:59 +00:00
|
|
|
|
public static function decodeTagAttributes( $text ) {
|
2005-06-03 08:12:48 +00:00
|
|
|
|
$attribs = array();
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-06-03 08:12:48 +00:00
|
|
|
|
if( trim( $text ) == '' ) {
|
|
|
|
|
|
return $attribs;
|
|
|
|
|
|
}
|
2005-12-04 20:43:42 +00:00
|
|
|
|
|
2006-01-07 13:31:29 +00:00
|
|
|
|
$pairs = array();
|
2005-06-03 08:12:48 +00:00
|
|
|
|
if( !preg_match_all(
|
|
|
|
|
|
MW_ATTRIBS_REGEX,
|
|
|
|
|
|
$text,
|
|
|
|
|
|
$pairs,
|
|
|
|
|
|
PREG_SET_ORDER ) ) {
|
|
|
|
|
|
return $attribs;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach( $pairs as $set ) {
|
|
|
|
|
|
$attribute = strtolower( $set[1] );
|
|
|
|
|
|
$value = Sanitizer::getTagAttributeCallback( $set );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
// Normalize whitespace
|
|
|
|
|
|
$value = preg_replace( '/[\t\r\n ]+/', ' ', $value );
|
|
|
|
|
|
$value = trim( $value );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-06-09 21:21:00 +00:00
|
|
|
|
// Decode character references
|
2005-06-03 08:12:48 +00:00
|
|
|
|
$attribs[$attribute] = Sanitizer::decodeCharReferences( $value );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $attribs;
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-06-03 08:12:48 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Pick the appropriate attribute value from a match set from the
|
|
|
|
|
|
* MW_ATTRIBS_REGEX matches.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $set Array
|
|
|
|
|
|
* @return String
|
2005-06-03 08:12:48 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
private static function getTagAttributeCallback( $set ) {
|
2005-06-03 08:12:48 +00:00
|
|
|
|
if( isset( $set[6] ) ) {
|
|
|
|
|
|
# Illegal #XXXXXX color with no quotes.
|
|
|
|
|
|
return $set[6];
|
|
|
|
|
|
} elseif( isset( $set[5] ) ) {
|
|
|
|
|
|
# No quotes.
|
|
|
|
|
|
return $set[5];
|
|
|
|
|
|
} elseif( isset( $set[4] ) ) {
|
|
|
|
|
|
# Single-quoted
|
|
|
|
|
|
return $set[4];
|
|
|
|
|
|
} elseif( isset( $set[3] ) ) {
|
|
|
|
|
|
# Double-quoted
|
|
|
|
|
|
return $set[3];
|
|
|
|
|
|
} elseif( !isset( $set[2] ) ) {
|
|
|
|
|
|
# In XHTML, attributes must have a value.
|
|
|
|
|
|
# For 'reduced' form, return explicitly the attribute name here.
|
|
|
|
|
|
return $set[1];
|
|
|
|
|
|
} else {
|
2006-06-07 06:40:24 +00:00
|
|
|
|
throw new MWException( "Tag conditions not met. This should never happen and is a bug." );
|
2005-06-03 08:12:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Normalize whitespace and character references in an XML source-
|
|
|
|
|
|
* encoded text for an attribute value.
|
|
|
|
|
|
*
|
|
|
|
|
|
* See http://www.w3.org/TR/REC-xml/#AVNormalize for background,
|
2009-01-07 02:31:30 +00:00
|
|
|
|
* but note that we're not returning the value, but are returning
|
2005-02-06 12:46:31 +00:00
|
|
|
|
* XML source fragments that will be slapped into output.
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return String
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
private static function normalizeAttributeValue( $text ) {
|
2005-06-03 08:12:48 +00:00
|
|
|
|
return str_replace( '"', '"',
|
2007-04-20 20:26:15 +00:00
|
|
|
|
self::normalizeWhitespace(
|
2005-06-03 08:12:48 +00:00
|
|
|
|
Sanitizer::normalizeCharReferences( $text ) ) );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-04-20 20:26:15 +00:00
|
|
|
|
private static function normalizeWhitespace( $text ) {
|
|
|
|
|
|
return preg_replace(
|
|
|
|
|
|
'/\r\n|[\x20\x0d\x0a\x09]/',
|
|
|
|
|
|
' ',
|
|
|
|
|
|
$text );
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 06:44:48 +00:00
|
|
|
|
/**
|
2005-02-06 12:46:31 +00:00
|
|
|
|
* Ensure that any entities and character references are legal
|
|
|
|
|
|
* for XML and XHTML specifically. Any stray bits will be
|
|
|
|
|
|
* &-escaped to result in a valid text fragment.
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*
|
2005-02-06 12:46:31 +00:00
|
|
|
|
* a. any named char refs must be known in XHTML
|
|
|
|
|
|
* b. any numeric char refs must be legal chars, not invalid or forbidden
|
|
|
|
|
|
* c. use &#x, not &#X
|
|
|
|
|
|
* d. fix or reject non-valid attributes
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return String
|
2006-04-24 19:22:18 +00:00
|
|
|
|
* @private
|
2005-02-06 06:44:48 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function normalizeCharReferences( $text ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
return preg_replace_callback(
|
2005-05-31 11:54:36 +00:00
|
|
|
|
MW_CHAR_REFS_REGEX,
|
2005-02-06 12:46:31 +00:00
|
|
|
|
array( 'Sanitizer', 'normalizeCharReferencesCallback' ),
|
|
|
|
|
|
$text );
|
|
|
|
|
|
}
|
2005-04-01 23:24:26 +00:00
|
|
|
|
/**
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $matches String
|
|
|
|
|
|
* @return String
|
2005-04-01 23:24:26 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function normalizeCharReferencesCallback( $matches ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$ret = null;
|
|
|
|
|
|
if( $matches[1] != '' ) {
|
|
|
|
|
|
$ret = Sanitizer::normalizeEntity( $matches[1] );
|
|
|
|
|
|
} elseif( $matches[2] != '' ) {
|
|
|
|
|
|
$ret = Sanitizer::decCharReference( $matches[2] );
|
|
|
|
|
|
} elseif( $matches[3] != '' ) {
|
|
|
|
|
|
$ret = Sanitizer::hexCharReference( $matches[3] );
|
|
|
|
|
|
} elseif( $matches[4] != '' ) {
|
|
|
|
|
|
$ret = Sanitizer::hexCharReference( $matches[4] );
|
2005-02-06 06:44:48 +00:00
|
|
|
|
}
|
2005-02-06 12:46:31 +00:00
|
|
|
|
if( is_null( $ret ) ) {
|
|
|
|
|
|
return htmlspecialchars( $matches[0] );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* If the named entity is defined in the HTML 4.0/XHTML 1.0 DTD,
|
2008-04-14 07:45:50 +00:00
|
|
|
|
* return the named entity reference as is. If the entity is a
|
|
|
|
|
|
* MediaWiki-specific alias, returns the HTML equivalent. Otherwise,
|
2007-04-29 08:28:34 +00:00
|
|
|
|
* returns HTML-escaped text of pseudo-entity source (eg &foo;)
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $name String
|
|
|
|
|
|
* @return String
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function normalizeEntity( $name ) {
|
2007-04-29 08:28:34 +00:00
|
|
|
|
global $wgHtmlEntities, $wgHtmlEntityAliases;
|
|
|
|
|
|
if ( isset( $wgHtmlEntityAliases[$name] ) ) {
|
|
|
|
|
|
return "&{$wgHtmlEntityAliases[$name]};";
|
|
|
|
|
|
} elseif( isset( $wgHtmlEntities[$name] ) ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
return "&$name;";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return "&$name;";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function decCharReference( $codepoint ) {
|
2005-08-16 23:36:16 +00:00
|
|
|
|
$point = intval( $codepoint );
|
2005-02-06 12:46:31 +00:00
|
|
|
|
if( Sanitizer::validateCodepoint( $point ) ) {
|
|
|
|
|
|
return sprintf( '&#%d;', $point );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function hexCharReference( $codepoint ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$point = hexdec( $codepoint );
|
|
|
|
|
|
if( Sanitizer::validateCodepoint( $point ) ) {
|
|
|
|
|
|
return sprintf( '&#x%x;', $point );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Returns true if a given Unicode codepoint is a valid character in XML.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $codepoint Integer
|
|
|
|
|
|
* @return Boolean
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
private static function validateCodepoint( $codepoint ) {
|
2005-02-06 12:46:31 +00:00
|
|
|
|
return ($codepoint == 0x09)
|
|
|
|
|
|
|| ($codepoint == 0x0a)
|
|
|
|
|
|
|| ($codepoint == 0x0d)
|
|
|
|
|
|
|| ($codepoint >= 0x20 && $codepoint <= 0xd7ff)
|
|
|
|
|
|
|| ($codepoint >= 0xe000 && $codepoint <= 0xfffd)
|
|
|
|
|
|
|| ($codepoint >= 0x10000 && $codepoint <= 0x10ffff);
|
|
|
|
|
|
}
|
2005-02-06 06:44:48 +00:00
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Decode any character references, numeric or named entities,
|
|
|
|
|
|
* in the text and return a UTF-8 string.
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String
|
|
|
|
|
|
* @return String
|
2005-05-31 11:54:36 +00:00
|
|
|
|
*/
|
2006-07-10 15:08:51 +00:00
|
|
|
|
public static function decodeCharReferences( $text ) {
|
2005-05-31 11:54:36 +00:00
|
|
|
|
return preg_replace_callback(
|
|
|
|
|
|
MW_CHAR_REFS_REGEX,
|
|
|
|
|
|
array( 'Sanitizer', 'decodeCharReferencesCallback' ),
|
|
|
|
|
|
$text );
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $matches String
|
|
|
|
|
|
* @return String
|
2005-05-31 11:54:36 +00:00
|
|
|
|
*/
|
2006-07-10 15:08:51 +00:00
|
|
|
|
static function decodeCharReferencesCallback( $matches ) {
|
2005-05-31 11:54:36 +00:00
|
|
|
|
if( $matches[1] != '' ) {
|
|
|
|
|
|
return Sanitizer::decodeEntity( $matches[1] );
|
|
|
|
|
|
} elseif( $matches[2] != '' ) {
|
|
|
|
|
|
return Sanitizer::decodeChar( intval( $matches[2] ) );
|
|
|
|
|
|
} elseif( $matches[3] != '' ) {
|
|
|
|
|
|
return Sanitizer::decodeChar( hexdec( $matches[3] ) );
|
|
|
|
|
|
} elseif( $matches[4] != '' ) {
|
|
|
|
|
|
return Sanitizer::decodeChar( hexdec( $matches[4] ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
# Last case should be an ampersand by itself
|
|
|
|
|
|
return $matches[0];
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return UTF-8 string for a codepoint if that is a valid
|
|
|
|
|
|
* character reference, otherwise U+FFFD REPLACEMENT CHARACTER.
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $codepoint Integer
|
|
|
|
|
|
* @return String
|
2006-04-24 19:22:18 +00:00
|
|
|
|
* @private
|
2005-05-31 11:54:36 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function decodeChar( $codepoint ) {
|
2005-05-31 11:54:36 +00:00
|
|
|
|
if( Sanitizer::validateCodepoint( $codepoint ) ) {
|
|
|
|
|
|
return codepointToUtf8( $codepoint );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return UTF8_REPLACEMENT;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-05-31 11:54:36 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* If the named entity is defined in the HTML 4.0/XHTML 1.0 DTD,
|
|
|
|
|
|
* return the UTF-8 encoding of that character. Otherwise, returns
|
|
|
|
|
|
* pseudo-entity source (eg &foo;)
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $name Strings
|
|
|
|
|
|
* @return String
|
2005-05-31 11:54:36 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function decodeEntity( $name ) {
|
2007-04-29 08:28:34 +00:00
|
|
|
|
global $wgHtmlEntities, $wgHtmlEntityAliases;
|
|
|
|
|
|
if ( isset( $wgHtmlEntityAliases[$name] ) ) {
|
|
|
|
|
|
$name = $wgHtmlEntityAliases[$name];
|
|
|
|
|
|
}
|
2005-05-31 11:54:36 +00:00
|
|
|
|
if( isset( $wgHtmlEntities[$name] ) ) {
|
|
|
|
|
|
return codepointToUtf8( $wgHtmlEntities[$name] );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return "&$name;";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
/**
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* Fetch the whitelist of acceptable attributes for a given element name.
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $element String
|
|
|
|
|
|
* @return Array
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function attributeWhitelist( $element ) {
|
2005-05-31 10:21:14 +00:00
|
|
|
|
static $list;
|
|
|
|
|
|
if( !isset( $list ) ) {
|
|
|
|
|
|
$list = Sanitizer::setupAttributeWhitelist();
|
|
|
|
|
|
}
|
2005-02-06 12:46:31 +00:00
|
|
|
|
return isset( $list[$element] )
|
|
|
|
|
|
? $list[$element]
|
|
|
|
|
|
: array();
|
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
/**
|
2008-10-06 15:31:03 +00:00
|
|
|
|
* Foreach array key (an allowed HTML element), return an array
|
|
|
|
|
|
* of allowed attributes
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @return Array
|
2005-02-06 12:46:31 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function setupAttributeWhitelist() {
|
2009-11-07 15:13:38 +00:00
|
|
|
|
$common = array( 'id', 'class', 'lang', 'dir', 'title', 'style',
|
|
|
|
|
|
#RDFa attributes as specified in section 9 of http://www.w3.org/TR/2008/REC-rdfa-syntax-20081014
|
|
|
|
|
|
'about', 'property', 'resource', 'datatype', 'typeof',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
$block = array_merge( $common, array( 'align' ) );
|
|
|
|
|
|
$tablealign = array( 'align', 'char', 'charoff', 'valign' );
|
|
|
|
|
|
$tablecell = array( 'abbr',
|
|
|
|
|
|
'axis',
|
|
|
|
|
|
'headers',
|
|
|
|
|
|
'scope',
|
|
|
|
|
|
'rowspan',
|
|
|
|
|
|
'colspan',
|
|
|
|
|
|
'nowrap', # deprecated
|
2005-05-12 08:54:23 +00:00
|
|
|
|
'width', # deprecated
|
|
|
|
|
|
'height', # deprecated
|
|
|
|
|
|
'bgcolor' # deprecated
|
2005-02-06 12:46:31 +00:00
|
|
|
|
);
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# Numbers refer to sections in HTML 4.01 standard describing the element.
|
|
|
|
|
|
# See: http://www.w3.org/TR/html4/
|
|
|
|
|
|
$whitelist = array (
|
|
|
|
|
|
# 7.5.4
|
|
|
|
|
|
'div' => $block,
|
|
|
|
|
|
'center' => $common, # deprecated
|
|
|
|
|
|
'span' => $block, # ??
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 7.5.5
|
|
|
|
|
|
'h1' => $block,
|
|
|
|
|
|
'h2' => $block,
|
|
|
|
|
|
'h3' => $block,
|
|
|
|
|
|
'h4' => $block,
|
|
|
|
|
|
'h5' => $block,
|
|
|
|
|
|
'h6' => $block,
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 7.5.6
|
|
|
|
|
|
# address
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 8.2.4
|
|
|
|
|
|
# bdo
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.2.1
|
|
|
|
|
|
'em' => $common,
|
|
|
|
|
|
'strong' => $common,
|
|
|
|
|
|
'cite' => $common,
|
|
|
|
|
|
# dfn
|
|
|
|
|
|
'code' => $common,
|
|
|
|
|
|
# samp
|
|
|
|
|
|
# kbd
|
|
|
|
|
|
'var' => $common,
|
2009-08-02 22:15:28 +00:00
|
|
|
|
'abbr' => $common,
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# acronym
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.2.2
|
|
|
|
|
|
'blockquote' => array_merge( $common, array( 'cite' ) ),
|
|
|
|
|
|
# q
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.2.3
|
|
|
|
|
|
'sub' => $common,
|
|
|
|
|
|
'sup' => $common,
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.3.1
|
|
|
|
|
|
'p' => $block,
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.3.2
|
|
|
|
|
|
'br' => array( 'id', 'class', 'title', 'style', 'clear' ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.3.4
|
|
|
|
|
|
'pre' => array_merge( $common, array( 'width' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 9.4
|
|
|
|
|
|
'ins' => array_merge( $common, array( 'cite', 'datetime' ) ),
|
|
|
|
|
|
'del' => array_merge( $common, array( 'cite', 'datetime' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 10.2
|
|
|
|
|
|
'ul' => array_merge( $common, array( 'type' ) ),
|
|
|
|
|
|
'ol' => array_merge( $common, array( 'type', 'start' ) ),
|
|
|
|
|
|
'li' => array_merge( $common, array( 'type', 'value' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 10.3
|
|
|
|
|
|
'dl' => $common,
|
|
|
|
|
|
'dd' => $common,
|
|
|
|
|
|
'dt' => $common,
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.1
|
|
|
|
|
|
'table' => array_merge( $common,
|
|
|
|
|
|
array( 'summary', 'width', 'border', 'frame',
|
2006-07-10 09:13:50 +00:00
|
|
|
|
'rules', 'cellspacing', 'cellpadding',
|
2006-07-11 16:39:51 +00:00
|
|
|
|
'align', 'bgcolor',
|
2006-07-10 09:13:50 +00:00
|
|
|
|
) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.2
|
|
|
|
|
|
'caption' => array_merge( $common, array( 'align' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.3
|
|
|
|
|
|
'thead' => array_merge( $common, $tablealign ),
|
|
|
|
|
|
'tfoot' => array_merge( $common, $tablealign ),
|
|
|
|
|
|
'tbody' => array_merge( $common, $tablealign ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.4
|
|
|
|
|
|
'colgroup' => array_merge( $common, array( 'span', 'width' ), $tablealign ),
|
|
|
|
|
|
'col' => array_merge( $common, array( 'span', 'width' ), $tablealign ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.5
|
|
|
|
|
|
'tr' => array_merge( $common, array( 'bgcolor' ), $tablealign ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 11.2.6
|
|
|
|
|
|
'td' => array_merge( $common, $tablecell, $tablealign ),
|
|
|
|
|
|
'th' => array_merge( $common, $tablecell, $tablealign ),
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-07-13 17:25:06 +00:00
|
|
|
|
# 13.2
|
|
|
|
|
|
# Not usually allowed, but may be used for extension-style hooks
|
|
|
|
|
|
# such as <math> when it is rasterized
|
|
|
|
|
|
'img' => array_merge( $common, array( 'alt' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 15.2.1
|
|
|
|
|
|
'tt' => $common,
|
|
|
|
|
|
'b' => $common,
|
|
|
|
|
|
'i' => $common,
|
|
|
|
|
|
'big' => $common,
|
|
|
|
|
|
'small' => $common,
|
|
|
|
|
|
'strike' => $common,
|
|
|
|
|
|
's' => $common,
|
|
|
|
|
|
'u' => $common,
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 15.2.2
|
|
|
|
|
|
'font' => array_merge( $common, array( 'size', 'color', 'face' ) ),
|
|
|
|
|
|
# basefont
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 12:46:31 +00:00
|
|
|
|
# 15.3
|
|
|
|
|
|
'hr' => array_merge( $common, array( 'noshade', 'size', 'width' ) ),
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-06 16:13:06 +00:00
|
|
|
|
# XHTML Ruby annotation text module, simple ruby only.
|
|
|
|
|
|
# http://www.w3c.org/TR/ruby/
|
|
|
|
|
|
'ruby' => $common,
|
|
|
|
|
|
# rbc
|
|
|
|
|
|
# rtc
|
2005-02-06 12:46:31 +00:00
|
|
|
|
'rb' => $common,
|
2005-02-06 16:13:06 +00:00
|
|
|
|
'rt' => $common, #array_merge( $common, array( 'rbspan' ) ),
|
2005-02-06 12:46:31 +00:00
|
|
|
|
'rp' => $common,
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
2007-07-13 17:25:06 +00:00
|
|
|
|
# MathML root element, where used for extensions
|
|
|
|
|
|
# 'title' may not be 100% valid here; it's XHTML
|
|
|
|
|
|
# http://www.w3.org/TR/REC-MathML/
|
|
|
|
|
|
'math' => array( 'class', 'style', 'id', 'title' ),
|
2005-02-06 12:46:31 +00:00
|
|
|
|
);
|
|
|
|
|
|
return $whitelist;
|
2005-02-06 06:44:48 +00:00
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-07 03:56:22 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Take a fragment of (potentially invalid) HTML and return
|
2007-04-20 20:26:15 +00:00
|
|
|
|
* a version with any tags removed, encoded as plain text.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Warning: this return value must be further escaped for literal
|
|
|
|
|
|
* inclusion in HTML output as of 1.10!
|
2005-02-07 03:56:22 +00:00
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @param $text String: HTML fragment
|
|
|
|
|
|
* @return String
|
2005-02-07 03:56:22 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function stripAllTags( $text ) {
|
2005-02-07 03:56:22 +00:00
|
|
|
|
# Actual <tags>
|
2006-11-21 09:53:45 +00:00
|
|
|
|
$text = StringUtils::delimiterReplace( '<', '>', '', $text );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-07 03:56:22 +00:00
|
|
|
|
# Normalize &entities and whitespace
|
2007-04-20 20:26:15 +00:00
|
|
|
|
$text = self::decodeCharReferences( $text );
|
|
|
|
|
|
$text = self::normalizeWhitespace( $text );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
|
2005-02-07 03:56:22 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2005-02-06 06:44:48 +00:00
|
|
|
|
|
2006-01-14 17:42:08 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Hack up a private DOCTYPE with HTML's standard entity declarations.
|
|
|
|
|
|
* PHP 4 seemed to know these if you gave it an HTML doctype, but
|
|
|
|
|
|
* PHP 5.1 doesn't.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Use for passing XHTML fragments to PHP's XML parsing functions
|
|
|
|
|
|
*
|
2009-04-22 20:56:41 +00:00
|
|
|
|
* @return String
|
2006-01-14 17:42:08 +00:00
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
|
static function hackDocType() {
|
2006-01-14 17:42:08 +00:00
|
|
|
|
global $wgHtmlEntities;
|
|
|
|
|
|
$out = "<!DOCTYPE html [\n";
|
|
|
|
|
|
foreach( $wgHtmlEntities as $entity => $codepoint ) {
|
|
|
|
|
|
$out .= "<!ENTITY $entity \"&#$codepoint;\">";
|
|
|
|
|
|
}
|
|
|
|
|
|
$out .= "]>\n";
|
|
|
|
|
|
return $out;
|
|
|
|
|
|
}
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2008-07-30 21:02:28 +00:00
|
|
|
|
static function cleanUrl( $url ) {
|
2006-07-11 19:54:20 +00:00
|
|
|
|
# Normalize any HTML entities in input. They will be
|
|
|
|
|
|
# re-escaped by makeExternalLink().
|
|
|
|
|
|
$url = Sanitizer::decodeCharReferences( $url );
|
|
|
|
|
|
|
|
|
|
|
|
# Escape any control characters introduced by the above step
|
|
|
|
|
|
$url = preg_replace( '/[\][<>"\\x00-\\x20\\x7F]/e', "urlencode('\\0')", $url );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
# Validate hostname portion
|
2006-11-23 08:25:56 +00:00
|
|
|
|
$matches = array();
|
2006-07-11 19:54:20 +00:00
|
|
|
|
if( preg_match( '!^([^:]+:)(//[^/]+)?(.*)$!iD', $url, $matches ) ) {
|
2006-11-23 08:25:56 +00:00
|
|
|
|
list( /* $whole */, $protocol, $host, $rest ) = $matches;
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
// Characters that will be ignored in IDNs.
|
|
|
|
|
|
// http://tools.ietf.org/html/3454#section-3.1
|
|
|
|
|
|
// Strip them before further processing so blacklists and such work.
|
|
|
|
|
|
$strip = "/
|
|
|
|
|
|
\\s| # general whitespace
|
|
|
|
|
|
\xc2\xad| # 00ad SOFT HYPHEN
|
|
|
|
|
|
\xe1\xa0\x86| # 1806 MONGOLIAN TODO SOFT HYPHEN
|
|
|
|
|
|
\xe2\x80\x8b| # 200b ZERO WIDTH SPACE
|
|
|
|
|
|
\xe2\x81\xa0| # 2060 WORD JOINER
|
|
|
|
|
|
\xef\xbb\xbf| # feff ZERO WIDTH NO-BREAK SPACE
|
|
|
|
|
|
\xcd\x8f| # 034f COMBINING GRAPHEME JOINER
|
|
|
|
|
|
\xe1\xa0\x8b| # 180b MONGOLIAN FREE VARIATION SELECTOR ONE
|
|
|
|
|
|
\xe1\xa0\x8c| # 180c MONGOLIAN FREE VARIATION SELECTOR TWO
|
|
|
|
|
|
\xe1\xa0\x8d| # 180d MONGOLIAN FREE VARIATION SELECTOR THREE
|
|
|
|
|
|
\xe2\x80\x8c| # 200c ZERO WIDTH NON-JOINER
|
|
|
|
|
|
\xe2\x80\x8d| # 200d ZERO WIDTH JOINER
|
|
|
|
|
|
[\xef\xb8\x80-\xef\xb8\x8f] # fe00-fe00f VARIATION SELECTOR-1-16
|
|
|
|
|
|
/xuD";
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
$host = preg_replace( $strip, '', $host );
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
// @fixme: validate hostnames here
|
2007-01-17 19:48:48 +00:00
|
|
|
|
|
2006-07-11 19:54:20 +00:00
|
|
|
|
return $protocol . $host . $rest;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2006-01-14 17:42:08 +00:00
|
|
|
|
|
2005-02-06 06:44:48 +00:00
|
|
|
|
}
|