See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 3 /** 4 * Defines allowed CSS attributes and what their values are. 5 * @see HTMLPurifier_HTMLDefinition 6 */ 7 class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 8 { 9 10 public $type = 'CSS'; 11 12 /** 13 * Assoc array of attribute name to definition object. 14 * @type HTMLPurifier_AttrDef[] 15 */ 16 public $info = array(); 17 18 /** 19 * Constructs the info array. The meat of this class. 20 * @param HTMLPurifier_Config $config 21 */ 22 protected function doSetup($config) 23 { 24 $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum( 25 array('left', 'right', 'center', 'justify'), 26 false 27 ); 28 29 $border_style = 30 $this->info['border-bottom-style'] = 31 $this->info['border-right-style'] = 32 $this->info['border-left-style'] = 33 $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( 34 array( 35 'none', 36 'hidden', 37 'dotted', 38 'dashed', 39 'solid', 40 'double', 41 'groove', 42 'ridge', 43 'inset', 44 'outset' 45 ), 46 false 47 ); 48 49 $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); 50 51 $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( 52 array('none', 'left', 'right', 'both'), 53 false 54 ); 55 $this->info['float'] = new HTMLPurifier_AttrDef_Enum( 56 array('none', 'left', 'right'), 57 false 58 ); 59 $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( 60 array('normal', 'italic', 'oblique'), 61 false 62 ); 63 $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( 64 array('normal', 'small-caps'), 65 false 66 ); 67 68 $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( 69 array( 70 new HTMLPurifier_AttrDef_Enum(array('none')), 71 new HTMLPurifier_AttrDef_CSS_URI() 72 ) 73 ); 74 75 $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( 76 array('inside', 'outside'), 77 false 78 ); 79 $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( 80 array( 81 'disc', 82 'circle', 83 'square', 84 'decimal', 85 'lower-roman', 86 'upper-roman', 87 'lower-alpha', 88 'upper-alpha', 89 'none' 90 ), 91 false 92 ); 93 $this->info['list-style-image'] = $uri_or_none; 94 95 $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); 96 97 $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( 98 array('capitalize', 'uppercase', 'lowercase', 'none'), 99 false 100 ); 101 $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); 102 103 $this->info['background-image'] = $uri_or_none; 104 $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( 105 array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') 106 ); 107 $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( 108 array('scroll', 'fixed') 109 ); 110 $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); 111 112 $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite( 113 array( 114 new HTMLPurifier_AttrDef_Enum( 115 array( 116 'auto', 117 'cover', 118 'contain', 119 'initial', 120 'inherit', 121 ) 122 ), 123 new HTMLPurifier_AttrDef_CSS_Percentage(), 124 new HTMLPurifier_AttrDef_CSS_Length() 125 ) 126 ); 127 128 $border_color = 129 $this->info['border-top-color'] = 130 $this->info['border-bottom-color'] = 131 $this->info['border-left-color'] = 132 $this->info['border-right-color'] = 133 $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( 134 array( 135 new HTMLPurifier_AttrDef_Enum(array('transparent')), 136 new HTMLPurifier_AttrDef_CSS_Color() 137 ) 138 ); 139 140 $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); 141 142 $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); 143 144 $border_width = 145 $this->info['border-top-width'] = 146 $this->info['border-bottom-width'] = 147 $this->info['border-left-width'] = 148 $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( 149 array( 150 new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), 151 new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative 152 ) 153 ); 154 155 $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); 156 157 $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( 158 array( 159 new HTMLPurifier_AttrDef_Enum(array('normal')), 160 new HTMLPurifier_AttrDef_CSS_Length() 161 ) 162 ); 163 164 $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( 165 array( 166 new HTMLPurifier_AttrDef_Enum(array('normal')), 167 new HTMLPurifier_AttrDef_CSS_Length() 168 ) 169 ); 170 171 $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( 172 array( 173 new HTMLPurifier_AttrDef_Enum( 174 array( 175 'xx-small', 176 'x-small', 177 'small', 178 'medium', 179 'large', 180 'x-large', 181 'xx-large', 182 'larger', 183 'smaller' 184 ) 185 ), 186 new HTMLPurifier_AttrDef_CSS_Percentage(), 187 new HTMLPurifier_AttrDef_CSS_Length() 188 ) 189 ); 190 191 $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( 192 array( 193 new HTMLPurifier_AttrDef_Enum(array('normal')), 194 new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives 195 new HTMLPurifier_AttrDef_CSS_Length('0'), 196 new HTMLPurifier_AttrDef_CSS_Percentage(true) 197 ) 198 ); 199 200 $margin = 201 $this->info['margin-top'] = 202 $this->info['margin-bottom'] = 203 $this->info['margin-left'] = 204 $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( 205 array( 206 new HTMLPurifier_AttrDef_CSS_Length(), 207 new HTMLPurifier_AttrDef_CSS_Percentage(), 208 new HTMLPurifier_AttrDef_Enum(array('auto')) 209 ) 210 ); 211 212 $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); 213 214 // non-negative 215 $padding = 216 $this->info['padding-top'] = 217 $this->info['padding-bottom'] = 218 $this->info['padding-left'] = 219 $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( 220 array( 221 new HTMLPurifier_AttrDef_CSS_Length('0'), 222 new HTMLPurifier_AttrDef_CSS_Percentage(true) 223 ) 224 ); 225 226 $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); 227 228 $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( 229 array( 230 new HTMLPurifier_AttrDef_CSS_Length(), 231 new HTMLPurifier_AttrDef_CSS_Percentage() 232 ) 233 ); 234 235 $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( 236 array( 237 new HTMLPurifier_AttrDef_CSS_Length('0'), 238 new HTMLPurifier_AttrDef_CSS_Percentage(true), 239 new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit')) 240 ) 241 ); 242 $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( 243 array( 244 new HTMLPurifier_AttrDef_CSS_Length('0'), 245 new HTMLPurifier_AttrDef_CSS_Percentage(true), 246 new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) 247 ) 248 ); 249 $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( 250 array( 251 new HTMLPurifier_AttrDef_CSS_Length('0'), 252 new HTMLPurifier_AttrDef_CSS_Percentage(true), 253 new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) 254 ) 255 ); 256 $max = $config->get('CSS.MaxImgLength'); 257 258 $this->info['width'] = 259 $this->info['height'] = 260 $max === null ? 261 $trusted_wh : 262 new HTMLPurifier_AttrDef_Switch( 263 'img', 264 // For img tags: 265 new HTMLPurifier_AttrDef_CSS_Composite( 266 array( 267 new HTMLPurifier_AttrDef_CSS_Length('0', $max), 268 new HTMLPurifier_AttrDef_Enum(array('auto')) 269 ) 270 ), 271 // For everyone else: 272 $trusted_wh 273 ); 274 $this->info['min-width'] = 275 $this->info['min-height'] = 276 $max === null ? 277 $trusted_min_wh : 278 new HTMLPurifier_AttrDef_Switch( 279 'img', 280 // For img tags: 281 new HTMLPurifier_AttrDef_CSS_Composite( 282 array( 283 new HTMLPurifier_AttrDef_CSS_Length('0', $max), 284 new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) 285 ) 286 ), 287 // For everyone else: 288 $trusted_min_wh 289 ); 290 $this->info['max-width'] = 291 $this->info['max-height'] = 292 $max === null ? 293 $trusted_max_wh : 294 new HTMLPurifier_AttrDef_Switch( 295 'img', 296 // For img tags: 297 new HTMLPurifier_AttrDef_CSS_Composite( 298 array( 299 new HTMLPurifier_AttrDef_CSS_Length('0', $max), 300 new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) 301 ) 302 ), 303 // For everyone else: 304 $trusted_max_wh 305 ); 306 307 $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); 308 309 $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); 310 311 // this could use specialized code 312 $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( 313 array( 314 'normal', 315 'bold', 316 'bolder', 317 'lighter', 318 '100', 319 '200', 320 '300', 321 '400', 322 '500', 323 '600', 324 '700', 325 '800', 326 '900' 327 ), 328 false 329 ); 330 331 // MUST be called after other font properties, as it references 332 // a CSSDefinition object 333 $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); 334 335 // same here 336 $this->info['border'] = 337 $this->info['border-bottom'] = 338 $this->info['border-top'] = 339 $this->info['border-left'] = 340 $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); 341 342 $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( 343 array('collapse', 'separate') 344 ); 345 346 $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( 347 array('top', 'bottom') 348 ); 349 350 $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( 351 array('auto', 'fixed') 352 ); 353 354 $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( 355 array( 356 new HTMLPurifier_AttrDef_Enum( 357 array( 358 'baseline', 359 'sub', 360 'super', 361 'top', 362 'text-top', 363 'middle', 364 'bottom', 365 'text-bottom' 366 ) 367 ), 368 new HTMLPurifier_AttrDef_CSS_Length(), 369 new HTMLPurifier_AttrDef_CSS_Percentage() 370 ) 371 ); 372 373 $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); 374 375 // These CSS properties don't work on many browsers, but we live 376 // in THE FUTURE! 377 $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( 378 array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line') 379 ); 380 381 if ($config->get('CSS.Proprietary')) { 382 $this->doSetupProprietary($config); 383 } 384 385 if ($config->get('CSS.AllowTricky')) { 386 $this->doSetupTricky($config); 387 } 388 389 if ($config->get('CSS.Trusted')) { 390 $this->doSetupTrusted($config); 391 } 392 393 $allow_important = $config->get('CSS.AllowImportant'); 394 // wrap all attr-defs with decorator that handles !important 395 foreach ($this->info as $k => $v) { 396 $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); 397 } 398 399 $this->setupConfigStuff($config); 400 } 401 402 /** 403 * @param HTMLPurifier_Config $config 404 */ 405 protected function doSetupProprietary($config) 406 { 407 // Internet Explorer only scrollbar colors 408 $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 409 $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 410 $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 411 $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 412 $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 413 $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); 414 415 // vendor specific prefixes of opacity 416 $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); 417 $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); 418 419 // only opacity, for now 420 $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); 421 422 // more CSS3 423 $this->info['page-break-after'] = 424 $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( 425 array( 426 'auto', 427 'always', 428 'avoid', 429 'left', 430 'right' 431 ) 432 ); 433 $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid')); 434 435 $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( 436 array( 437 new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative 438 new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative 439 )); 440 441 $this->info['border-top-left-radius'] = 442 $this->info['border-top-right-radius'] = 443 $this->info['border-bottom-right-radius'] = 444 $this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2); 445 // TODO: support SLASH syntax 446 $this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4); 447 448 } 449 450 /** 451 * @param HTMLPurifier_Config $config 452 */ 453 protected function doSetupTricky($config) 454 { 455 $this->info['display'] = new HTMLPurifier_AttrDef_Enum( 456 array( 457 'inline', 458 'block', 459 'list-item', 460 'run-in', 461 'compact', 462 'marker', 463 'table', 464 'inline-block', 465 'inline-table', 466 'table-row-group', 467 'table-header-group', 468 'table-footer-group', 469 'table-row', 470 'table-column-group', 471 'table-column', 472 'table-cell', 473 'table-caption', 474 'none' 475 ) 476 ); 477 $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( 478 array('visible', 'hidden', 'collapse') 479 ); 480 $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); 481 $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); 482 } 483 484 /** 485 * @param HTMLPurifier_Config $config 486 */ 487 protected function doSetupTrusted($config) 488 { 489 $this->info['position'] = new HTMLPurifier_AttrDef_Enum( 490 array('static', 'relative', 'absolute', 'fixed') 491 ); 492 $this->info['top'] = 493 $this->info['left'] = 494 $this->info['right'] = 495 $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( 496 array( 497 new HTMLPurifier_AttrDef_CSS_Length(), 498 new HTMLPurifier_AttrDef_CSS_Percentage(), 499 new HTMLPurifier_AttrDef_Enum(array('auto')), 500 ) 501 ); 502 $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( 503 array( 504 new HTMLPurifier_AttrDef_Integer(), 505 new HTMLPurifier_AttrDef_Enum(array('auto')), 506 ) 507 ); 508 } 509 510 /** 511 * Performs extra config-based processing. Based off of 512 * HTMLPurifier_HTMLDefinition. 513 * @param HTMLPurifier_Config $config 514 * @todo Refactor duplicate elements into common class (probably using 515 * composition, not inheritance). 516 */ 517 protected function setupConfigStuff($config) 518 { 519 // setup allowed elements 520 $support = "(for information on implementing this, see the " . 521 "support forums) "; 522 $allowed_properties = $config->get('CSS.AllowedProperties'); 523 if ($allowed_properties !== null) { 524 foreach ($this->info as $name => $d) { 525 if (!isset($allowed_properties[$name])) { 526 unset($this->info[$name]); 527 } 528 unset($allowed_properties[$name]); 529 } 530 // emit errors 531 foreach ($allowed_properties as $name => $d) { 532 // :TODO: Is this htmlspecialchars() call really necessary? 533 $name = htmlspecialchars($name); 534 trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); 535 } 536 } 537 538 $forbidden_properties = $config->get('CSS.ForbiddenProperties'); 539 if ($forbidden_properties !== null) { 540 foreach ($this->info as $name => $d) { 541 if (isset($forbidden_properties[$name])) { 542 unset($this->info[$name]); 543 } 544 } 545 } 546 } 547 } 548 549 // vim: et sw=4 sts=4
title
Description
Body
title
Description
Body
title
Description
Body
title
Body