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.

161 lines
3.7KB

  1. <?php
  2. /**
  3. * Represents a measurable length, with a string numeric magnitude
  4. * and a unit. This object is immutable.
  5. */
  6. class HTMLPurifier_Length
  7. {
  8. /**
  9. * String numeric magnitude.
  10. * @type string
  11. */
  12. protected $n;
  13. /**
  14. * String unit. False is permitted if $n = 0.
  15. * @type string|bool
  16. */
  17. protected $unit;
  18. /**
  19. * Whether or not this length is valid. Null if not calculated yet.
  20. * @type bool
  21. */
  22. protected $isValid;
  23. /**
  24. * Array Lookup array of units recognized by CSS 2.1
  25. * @type array
  26. */
  27. protected static $allowedUnits = array(
  28. 'em' => true, 'ex' => true, 'px' => true, 'in' => true,
  29. 'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true
  30. );
  31. /**
  32. * @param string $n Magnitude
  33. * @param bool|string $u Unit
  34. */
  35. public function __construct($n = '0', $u = false)
  36. {
  37. $this->n = (string) $n;
  38. $this->unit = $u !== false ? (string) $u : false;
  39. }
  40. /**
  41. * @param string $s Unit string, like '2em' or '3.4in'
  42. * @return HTMLPurifier_Length
  43. * @warning Does not perform validation.
  44. */
  45. public static function make($s)
  46. {
  47. if ($s instanceof HTMLPurifier_Length) {
  48. return $s;
  49. }
  50. $n_length = strspn($s, '1234567890.+-');
  51. $n = substr($s, 0, $n_length);
  52. $unit = substr($s, $n_length);
  53. if ($unit === '') {
  54. $unit = false;
  55. }
  56. return new HTMLPurifier_Length($n, $unit);
  57. }
  58. /**
  59. * Validates the number and unit.
  60. * @return bool
  61. */
  62. protected function validate()
  63. {
  64. // Special case:
  65. if ($this->n === '+0' || $this->n === '-0') {
  66. $this->n = '0';
  67. }
  68. if ($this->n === '0' && $this->unit === false) {
  69. return true;
  70. }
  71. if (!ctype_lower($this->unit)) {
  72. $this->unit = strtolower($this->unit);
  73. }
  74. if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) {
  75. return false;
  76. }
  77. // Hack:
  78. $def = new HTMLPurifier_AttrDef_CSS_Number();
  79. $result = $def->validate($this->n, false, false);
  80. if ($result === false) {
  81. return false;
  82. }
  83. $this->n = $result;
  84. return true;
  85. }
  86. /**
  87. * Returns string representation of number.
  88. * @return string
  89. */
  90. public function toString()
  91. {
  92. if (!$this->isValid()) {
  93. return false;
  94. }
  95. return $this->n . $this->unit;
  96. }
  97. /**
  98. * Retrieves string numeric magnitude.
  99. * @return string
  100. */
  101. public function getN()
  102. {
  103. return $this->n;
  104. }
  105. /**
  106. * Retrieves string unit.
  107. * @return string
  108. */
  109. public function getUnit()
  110. {
  111. return $this->unit;
  112. }
  113. /**
  114. * Returns true if this length unit is valid.
  115. * @return bool
  116. */
  117. public function isValid()
  118. {
  119. if ($this->isValid === null) {
  120. $this->isValid = $this->validate();
  121. }
  122. return $this->isValid;
  123. }
  124. /**
  125. * Compares two lengths, and returns 1 if greater, -1 if less and 0 if equal.
  126. * @param HTMLPurifier_Length $l
  127. * @return int
  128. * @warning If both values are too large or small, this calculation will
  129. * not work properly
  130. */
  131. public function compareTo($l)
  132. {
  133. if ($l === false) {
  134. return false;
  135. }
  136. if ($l->unit !== $this->unit) {
  137. $converter = new HTMLPurifier_UnitConverter();
  138. $l = $converter->convert($l, $this->unit);
  139. if ($l === false) {
  140. return false;
  141. }
  142. }
  143. return $this->n - $l->n;
  144. }
  145. }
  146. // vim: et sw=4 sts=4