You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.6KB

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