Length.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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 3
  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. 'ch' => true, 'rem' => true, 'vw' => true, 'vh' => true,
  31. 'vmin' => true, 'vmax' => true
  32. );
  33. /**
  34. * @param string $n Magnitude
  35. * @param bool|string $u Unit
  36. */
  37. public function __construct($n = '0', $u = false)
  38. {
  39. $this->n = (string) $n;
  40. $this->unit = $u !== false ? (string) $u : false;
  41. }
  42. /**
  43. * @param string $s Unit string, like '2em' or '3.4in'
  44. * @return HTMLPurifier_Length
  45. * @warning Does not perform validation.
  46. */
  47. public static function make($s)
  48. {
  49. if ($s instanceof HTMLPurifier_Length) {
  50. return $s;
  51. }
  52. $n_length = strspn($s, '1234567890.+-');
  53. $n = substr($s, 0, $n_length);
  54. $unit = substr($s, $n_length);
  55. if ($unit === '') {
  56. $unit = false;
  57. }
  58. return new HTMLPurifier_Length($n, $unit);
  59. }
  60. /**
  61. * Validates the number and unit.
  62. * @return bool
  63. */
  64. protected function validate()
  65. {
  66. // Special case:
  67. if ($this->n === '+0' || $this->n === '-0') {
  68. $this->n = '0';
  69. }
  70. if ($this->n === '0' && $this->unit === false) {
  71. return true;
  72. }
  73. if (!ctype_lower($this->unit)) {
  74. $this->unit = strtolower($this->unit);
  75. }
  76. if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) {
  77. return false;
  78. }
  79. // Hack:
  80. $def = new HTMLPurifier_AttrDef_CSS_Number();
  81. $result = $def->validate($this->n, false, false);
  82. if ($result === false) {
  83. return false;
  84. }
  85. $this->n = $result;
  86. return true;
  87. }
  88. /**
  89. * Returns string representation of number.
  90. * @return string
  91. */
  92. public function toString()
  93. {
  94. if (!$this->isValid()) {
  95. return false;
  96. }
  97. return $this->n . $this->unit;
  98. }
  99. /**
  100. * Retrieves string numeric magnitude.
  101. * @return string
  102. */
  103. public function getN()
  104. {
  105. return $this->n;
  106. }
  107. /**
  108. * Retrieves string unit.
  109. * @return string
  110. */
  111. public function getUnit()
  112. {
  113. return $this->unit;
  114. }
  115. /**
  116. * Returns true if this length unit is valid.
  117. * @return bool
  118. */
  119. public function isValid()
  120. {
  121. if ($this->isValid === null) {
  122. $this->isValid = $this->validate();
  123. }
  124. return $this->isValid;
  125. }
  126. /**
  127. * Compares two lengths, and returns 1 if greater, -1 if less and 0 if equal.
  128. * @param HTMLPurifier_Length $l
  129. * @return int
  130. * @warning If both values are too large or small, this calculation will
  131. * not work properly
  132. */
  133. public function compareTo($l)
  134. {
  135. if ($l === false) {
  136. return false;
  137. }
  138. if ($l->unit !== $this->unit) {
  139. $converter = new HTMLPurifier_UnitConverter();
  140. $l = $converter->convert($l, $this->unit);
  141. if ($l === false) {
  142. return false;
  143. }
  144. }
  145. return $this->n - $l->n;
  146. }
  147. }
  148. // vim: et sw=4 sts=4