1: <?php
2:
3: namespace Guzzle\Http\Message;
4:
5: use Guzzle\Common\ToArrayInterface;
6:
7: /**
8: * Represents a header and all of the values stored by that header
9: */
10: class Header implements ToArrayInterface, \IteratorAggregate, \Countable
11: {
12: protected $values = array();
13: protected $header;
14: protected $glue;
15: protected $stringCache;
16: protected $arrayCache;
17:
18: /**
19: * Construct a new header object
20: *
21: * @param string $header Name of the header
22: * @param array $values Values of the header
23: * @param string $glue Glue used to combine multiple values into a string
24: */
25: public function __construct($header, $values = array(), $glue = ', ')
26: {
27: $this->header = $header;
28: $this->glue = $glue;
29:
30: if (null !== $values) {
31: foreach ((array) $values as $key => $value) {
32: if (is_numeric($key)) {
33: $key = $header;
34: }
35: if ($value === null) {
36: $this->add($value, $key);
37: } else {
38: foreach ((array) $value as $v) {
39: $this->add($v, $key);
40: }
41: }
42: }
43: }
44: }
45:
46: /**
47: * Convert the header to a string
48: *
49: * @return string
50: */
51: public function __toString()
52: {
53: if (!$this->stringCache) {
54: $this->stringCache = implode($this->glue, $this->toArray());
55: }
56:
57: return $this->stringCache;
58: }
59:
60: /**
61: * Add a value to the list of header values
62: *
63: * @param string $value Value to add
64: * @param string $header The exact header casing to add with. Defaults to the name of the header.
65: *
66: * @return Header
67: */
68: public function add($value, $header = null)
69: {
70: if (!$header) {
71: $header = $this->getName();
72: }
73:
74: if (!isset($this->values[$header])) {
75: $this->values[$header] = array($value);
76: } else {
77: $this->values[$header][] = $value;
78: }
79:
80: // Ensure that the array cache is cleared
81: $this->arrayCache = $this->stringCache = null;
82:
83: return $this;
84: }
85:
86: /**
87: * Get the name of the header
88: *
89: * @return string
90: */
91: public function getName()
92: {
93: return $this->header;
94: }
95:
96: /**
97: * Change the glue used to implode the values
98: *
99: * @param string $glue Glue used to implode multiple values
100: *
101: * @return Header
102: */
103: public function setGlue($glue)
104: {
105: $this->glue = $glue;
106: $this->stringCache = null;
107:
108: return $this;
109: }
110:
111: /**
112: * Get the glue used to implode multiple values into a string
113: *
114: * @return string
115: */
116: public function getGlue()
117: {
118: return $this->glue;
119: }
120:
121: /**
122: * Normalize the header to be a single header with an array of values
123: *
124: * @param bool $explodeOnGlue Set to true to explode each header value on the glue of the header
125: *
126: * @return Header
127: */
128: public function normalize($explodeOnGlue = false)
129: {
130: $values = $this->toArray();
131: $this->arrayCache = $this->stringCache = null;
132:
133: // Explode each value on glue if needed
134: if ($this->glue && $explodeOnGlue) {
135: foreach ($values as $i => $value) {
136: // Explode the value if the glue was found in the header
137: if (strpos($value, $this->glue)) {
138: foreach (explode($this->glue, $value) as $v) {
139: $values[] = $v;
140: }
141: unset($values[$i]);
142: }
143: }
144: }
145:
146: $this->values = array($this->getName() => $values);
147:
148: return $this;
149: }
150:
151: /**
152: * Check if a particular case variation is present in the header
153: * Example: A header exists on a message for 'Foo', and 'foo'. The Header object will contain all of the values of
154: * 'Foo' and all of the values of 'foo'. You can use this method to check to see if a header was set using
155: * 'foo' (true), 'Foo' (true), 'FOO' (false), etc.
156: *
157: * @param string $header Exact header to check for
158: *
159: * @return bool
160: */
161: public function hasExactHeader($header)
162: {
163: return isset($this->values[$header]);
164: }
165:
166: /**
167: * Check if the collection of headers has a particular value
168: *
169: * @param string $searchValue Value to search for
170: * @param bool $caseInsensitive Set to TRUE to use a case insensitive search
171: *
172: * @return bool
173: */
174: public function hasValue($searchValue, $caseInsensitive = false)
175: {
176: foreach ($this->toArray() as $value) {
177: if ($value == $searchValue) {
178: return true;
179: } elseif ($caseInsensitive && !strcasecmp($value, $searchValue)) {
180: return true;
181: }
182: }
183:
184: return false;
185: }
186:
187: /**
188: * Remove a specific value from the header
189: *
190: * @param string $searchValue Value to remove
191: *
192: * @return self
193: */
194: public function removeValue($searchValue)
195: {
196: foreach ($this->values as $key => $values) {
197: foreach ($values as $index => $value) {
198: if ($value == $searchValue) {
199: unset($this->values[$key][$index]);
200: $this->arrayCache = $this->stringCache = null;
201: break 2;
202: }
203: }
204: }
205:
206: return $this;
207: }
208:
209: /**
210: * Get all of the header values as a flat array
211: * {@inheritdoc}
212: */
213: public function toArray()
214: {
215: if ($this->arrayCache === null) {
216: $this->arrayCache = array();
217: foreach ($this->values as $values) {
218: $this->arrayCache = array_merge($this->arrayCache, $values);
219: }
220: }
221:
222: return $this->arrayCache;
223: }
224:
225: /**
226: * Get the raw data array of the headers. This array is represented as an associative array of the various cases
227: * that might be stored in the header and an array of values associated with each case variation.
228: *
229: * @return array
230: */
231: public function raw()
232: {
233: return $this->values;
234: }
235:
236: /**
237: * Returns the total number of header values
238: *
239: * @return int
240: */
241: public function count()
242: {
243: return count($this->toArray());
244: }
245:
246: /**
247: * Get an iterator that can be used to easily iterate over each header value
248: *
249: * @return \ArrayIterator
250: */
251: public function getIterator()
252: {
253: return new \ArrayIterator($this->toArray());
254: }
255: }
256: