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