AttrCollections.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <?php
  2. /**
  3. * Defines common attribute collections that modules reference
  4. */
  5. class HTMLPurifier_AttrCollections
  6. {
  7. /**
  8. * Associative array of attribute collections, indexed by name
  9. */
  10. public $info = array();
  11. /**
  12. * Performs all expansions on internal data for use by other inclusions
  13. * It also collects all attribute collection extensions from
  14. * modules
  15. * @param $attr_types HTMLPurifier_AttrTypes instance
  16. * @param $modules Hash array of HTMLPurifier_HTMLModule members
  17. */
  18. public function __construct($attr_types, $modules) {
  19. // load extensions from the modules
  20. foreach ($modules as $module) {
  21. foreach ($module->attr_collections as $coll_i => $coll) {
  22. if (!isset($this->info[$coll_i])) {
  23. $this->info[$coll_i] = array();
  24. }
  25. foreach ($coll as $attr_i => $attr) {
  26. if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
  27. // merge in includes
  28. $this->info[$coll_i][$attr_i] = array_merge(
  29. $this->info[$coll_i][$attr_i], $attr);
  30. continue;
  31. }
  32. $this->info[$coll_i][$attr_i] = $attr;
  33. }
  34. }
  35. }
  36. // perform internal expansions and inclusions
  37. foreach ($this->info as $name => $attr) {
  38. // merge attribute collections that include others
  39. $this->performInclusions($this->info[$name]);
  40. // replace string identifiers with actual attribute objects
  41. $this->expandIdentifiers($this->info[$name], $attr_types);
  42. }
  43. }
  44. /**
  45. * Takes a reference to an attribute associative array and performs
  46. * all inclusions specified by the zero index.
  47. * @param &$attr Reference to attribute array
  48. */
  49. public function performInclusions(&$attr) {
  50. if (!isset($attr[0])) return;
  51. $merge = $attr[0];
  52. $seen = array(); // recursion guard
  53. // loop through all the inclusions
  54. for ($i = 0; isset($merge[$i]); $i++) {
  55. if (isset($seen[$merge[$i]])) continue;
  56. $seen[$merge[$i]] = true;
  57. // foreach attribute of the inclusion, copy it over
  58. if (!isset($this->info[$merge[$i]])) continue;
  59. foreach ($this->info[$merge[$i]] as $key => $value) {
  60. if (isset($attr[$key])) continue; // also catches more inclusions
  61. $attr[$key] = $value;
  62. }
  63. if (isset($this->info[$merge[$i]][0])) {
  64. // recursion
  65. $merge = array_merge($merge, $this->info[$merge[$i]][0]);
  66. }
  67. }
  68. unset($attr[0]);
  69. }
  70. /**
  71. * Expands all string identifiers in an attribute array by replacing
  72. * them with the appropriate values inside HTMLPurifier_AttrTypes
  73. * @param &$attr Reference to attribute array
  74. * @param $attr_types HTMLPurifier_AttrTypes instance
  75. */
  76. public function expandIdentifiers(&$attr, $attr_types) {
  77. // because foreach will process new elements we add, make sure we
  78. // skip duplicates
  79. $processed = array();
  80. foreach ($attr as $def_i => $def) {
  81. // skip inclusions
  82. if ($def_i === 0) continue;
  83. if (isset($processed[$def_i])) continue;
  84. // determine whether or not attribute is required
  85. if ($required = (strpos($def_i, '*') !== false)) {
  86. // rename the definition
  87. unset($attr[$def_i]);
  88. $def_i = trim($def_i, '*');
  89. $attr[$def_i] = $def;
  90. }
  91. $processed[$def_i] = true;
  92. // if we've already got a literal object, move on
  93. if (is_object($def)) {
  94. // preserve previous required
  95. $attr[$def_i]->required = ($required || $attr[$def_i]->required);
  96. continue;
  97. }
  98. if ($def === false) {
  99. unset($attr[$def_i]);
  100. continue;
  101. }
  102. if ($t = $attr_types->get($def)) {
  103. $attr[$def_i] = $t;
  104. $attr[$def_i]->required = $required;
  105. } else {
  106. unset($attr[$def_i]);
  107. }
  108. }
  109. }
  110. }
  111. // vim: et sw=4 sts=4