Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Http / Header / AbstractAccept.php
blob23be958e452dbb51112ffde328288427ec7b4299
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Http\Header;
12 use stdClass;
14 /**
15 * Abstract Accept Header
17 * Naming conventions:
19 * Accept: audio/mp3; q=0.2; version=0.5, audio/basic+mp3
20 * |------------------------------------------------------| header line
21 * |------| field name
22 * |-----------------------------------------------| field value
23 * |-------------------------------| field value part
24 * |------| type
25 * |--| subtype
26 * |--| format
27 * |----| subtype
28 * |---| format
29 * |-------------------| parameter set
30 * |-----------| parameter
31 * |-----| parameter key
32 * |--| parameter value
33 * |---| priority
36 * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
37 * @author Dolf Schimmel - Freeaqingme
39 abstract class AbstractAccept implements HeaderInterface
42 /**
44 * @var array
46 protected $fieldValueParts = array();
48 protected $regexAddType;
50 /**
51 * Determines if since last mutation the stack was sorted
53 * @var bool
55 protected $sorted = false;
58 /**
60 * @param string $headerLine
62 public function parseHeaderLine($headerLine)
64 $fieldName = $this->getFieldName();
65 $pos = strlen($fieldName) + 2;
66 if (strtolower(substr($headerLine, 0, $pos)) == strtolower($fieldName) . ': ') {
67 $headerLine = substr($headerLine, $pos);
70 foreach ($this->getFieldValuePartsFromHeaderLine($headerLine) as $value) {
71 $this->addFieldValuePartToQueue($value);
75 /**
76 * Factory method: parse Accept header string
78 * @param string $headerLine
79 * @return Accept
81 public static function fromString($headerLine)
83 $obj = new static();
84 $obj->parseHeaderLine($headerLine);
85 return $obj;
88 /**
89 * Parse the Field Value Parts represented by a header line
91 * @param string $headerLine
92 * @throws Exception\InvalidArgumentException If header is invalid
93 * @return array
95 public function getFieldValuePartsFromHeaderLine($headerLine)
97 // process multiple accept values, they may be between quotes
98 if (!preg_match_all('/(?:[^,"]|"(?:[^\\\"]|\\\.)*")+/', $headerLine, $values)
99 || !isset($values[0])
101 throw new Exception\InvalidArgumentException(
102 'Invalid header line for ' . $this->getFieldName() . ' header string'
106 $out = array();
107 foreach ($values[0] as $value) {
108 $value = trim($value);
110 $out[] = $this->parseFieldValuePart($value);
113 return $out;
117 * Parse the accept params belonging to a media range
119 * @param string $fieldValuePart
120 * @return stdClass
122 protected function parseFieldValuePart($fieldValuePart)
124 $raw = $subtypeWhole = $type = $fieldValuePart;
125 if ($pos = strpos($fieldValuePart, ';')) {
126 $type = substr($fieldValuePart, 0, $pos);
129 $params = $this->getParametersFromFieldValuePart($fieldValuePart);
131 if ($pos = strpos($fieldValuePart, ';')) {
132 $fieldValuePart = trim(substr($fieldValuePart, 0, $pos));
135 $format = '*';
136 $subtype = '*';
138 return (object) array(
139 'typeString' => trim($fieldValuePart),
140 'type' => $type,
141 'subtype' => $subtype,
142 'subtypeRaw' => $subtypeWhole,
143 'format' => $format,
144 'priority' => isset($params['q']) ? $params['q'] : 1,
145 'params' => $params,
146 'raw' => trim($raw)
151 * Parse the keys contained in the header line
153 * @param string $fieldValuePart
154 * @return array
156 protected function getParametersFromFieldValuePart($fieldValuePart)
158 $params = array();
159 if ((($pos = strpos($fieldValuePart, ';')) !== false)) {
160 preg_match_all('/(?:[^;"]|"(?:[^\\\"]|\\\.)*")+/', $fieldValuePart, $paramsStrings);
162 if (isset($paramsStrings[0])) {
163 array_shift($paramsStrings[0]);
164 $paramsStrings = $paramsStrings[0];
167 foreach ($paramsStrings as $param) {
168 $explode = explode('=', $param, 2);
170 $value = trim($explode[1]);
171 if (isset($value[0]) && $value[0] == '"' && substr($value, -1) == '"') {
172 $value = substr(substr($value, 1), 0, -1);
175 $params[trim($explode[0])] = stripslashes($value);
179 return $params;
184 * Get field value
186 * @param array|null $values
187 * @return string
189 public function getFieldValue($values = null)
191 if (!$values) {
192 return $this->getFieldValue($this->fieldValueParts);
195 $strings = array();
196 foreach ($values as $value) {
197 $params = $value->params;
198 array_walk($params, array($this, 'assembleAcceptParam'));
199 $strings[] = implode(';', array($value->typeString) + $params);
202 return implode(', ', $strings);
207 * Assemble and escape the field value parameters based on RFC 2616 section 2.1
209 * @todo someone should review this thoroughly
210 * @param string $value
211 * @param string $key
212 * @return string
214 protected function assembleAcceptParam(&$value, $key)
216 $separators = array('(', ')', '<', '>', '@', ',', ';', ':',
217 '/', '[', ']', '?', '=', '{', '}', ' ', "\t");
219 $escaped = preg_replace_callback('/[[:cntrl:]"\\\\]/', // escape cntrl, ", \
220 function ($v) {
221 return '\\' . $v[0];
223 $value
226 if ($escaped == $value && !array_intersect(str_split($value), $separators)) {
227 $value = $key . '=' . $value;
228 } else {
229 $value = $key . '="' . $escaped . '"';
232 return $value;
236 * Add a type, with the given priority
238 * @param string $type
239 * @param int|float $priority
240 * @param array (optional) $params
241 * @throws Exception\InvalidArgumentException
242 * @return Accept
244 protected function addType($type, $priority = 1, array $params = array())
246 if (!preg_match($this->regexAddType, $type)) {
247 throw new Exception\InvalidArgumentException(sprintf(
248 '%s expects a valid type; received "%s"',
249 __METHOD__,
250 (string) $type
254 if (!is_int($priority) && !is_float($priority) && !is_numeric($priority)
255 || $priority > 1 || $priority < 0
257 throw new Exception\InvalidArgumentException(sprintf(
258 '%s expects a numeric priority; received %s',
259 __METHOD__,
260 (string) $priority
264 if ($priority != 1) {
265 $params = array('q' => sprintf('%01.1f', $priority)) + $params;
268 $assembledString = $this->getFieldValue(
269 array((object) array('typeString' => $type, 'params' => $params))
272 $value = $this->parseFieldValuePart($assembledString);
273 $this->addFieldValuePartToQueue($value);
274 return $this;
279 * Does the header have the requested type?
281 * @param array|string $matchAgainst
282 * @return bool
284 protected function hasType($matchAgainst)
286 return (bool) $this->match($matchAgainst);
290 * Match a media string against this header
292 * @param array|string $matchAgainst
293 * @return AcceptFieldValuePart|bool The matched value or false
295 public function match($matchAgainst)
297 if (is_string($matchAgainst)) {
298 $matchAgainst = $this->getFieldValuePartsFromHeaderLine($matchAgainst);
301 foreach ($this->getPrioritized() as $left) {
302 foreach ($matchAgainst as $right) {
303 if ($right->type == '*' || $left->type == '*') {
304 if ($this->matchAcceptParams($left, $right)) {
305 $left->setMatchedAgainst($right);
307 return $left;
311 if ($left->type == $right->type) {
312 if ((($left->subtype == $right->subtype ||
313 ($right->subtype == '*' || $left->subtype == '*')) &&
314 ($left->format == $right->format ||
315 $right->format == '*' || $left->format == '*')))
317 if ($this->matchAcceptParams($left, $right)) {
318 $left->setMatchedAgainst($right);
320 return $left;
329 return false;
333 * Return a match where all parameters in argument #1 match those in argument #2
335 * @param array $match1
336 * @param array $match2
337 * @return bool|array
339 protected function matchAcceptParams($match1, $match2)
341 foreach ($match2->params as $key => $value) {
342 if (isset($match1->params[$key])) {
343 if (strpos($value, '-')) {
344 preg_match(
345 '/^(?|([^"-]*)|"([^"]*)")-(?|([^"-]*)|"([^"]*)")\z/',
346 $value,
347 $pieces
350 if (count($pieces) == 3 &&
351 (version_compare($pieces[1], $match1->params[$key], '<=') xor
352 version_compare($pieces[2], $match1->params[$key], '>=')
355 return false;
357 } elseif (strpos($value, '|')) {
358 $options = explode('|', $value);
359 $good = false;
360 foreach ($options as $option) {
361 if ($option == $match1->params[$key]) {
362 $good = true;
363 break;
367 if (!$good) {
368 return false;
370 } elseif ($match1->params[$key] != $value) {
371 return false;
377 return $match1;
382 * Add a key/value combination to the internal queue
384 * @param stdClass $value
385 * @return number
387 protected function addFieldValuePartToQueue($value)
389 $this->fieldValueParts[] = $value;
390 $this->sorted = false;
394 * Sort the internal Field Value Parts
396 * @See rfc2616 sect 14.1
397 * Media ranges can be overridden by more specific media ranges or
398 * specific media types. If more than one media range applies to a given
399 * type, the most specific reference has precedence. For example,
401 * Accept: text/*, text/html, text/html;level=1, * /*
403 * have the following precedence:
405 * 1) text/html;level=1
406 * 2) text/html
407 * 3) text/*
408 * 4) * /*
410 * @return number
412 protected function sortFieldValueParts()
414 $sort = function ($a, $b) { // If A has higher prio than B, return -1.
415 if ($a->priority > $b->priority) {
416 return -1;
417 } elseif ($a->priority < $b->priority) {
418 return 1;
421 // Asterisks
422 $values = array('type', 'subtype', 'format');
423 foreach ($values as $value) {
424 if ($a->$value == '*' && $b->$value != '*') {
425 return 1;
426 } elseif ($b->$value == '*' && $a->$value != '*') {
427 return -1;
431 if ($a->type == 'application' && $b->type != 'application') {
432 return -1;
433 } elseif ($b->type == 'application' && $a->type != 'application') {
434 return 1;
437 //@todo count number of dots in case of type==application in subtype
439 // So far they're still the same. Longest stringlength may be more specific
440 if (strlen($a->raw) == strlen($b->raw)) return 0;
441 return (strlen($a->raw) > strlen($b->raw)) ? -1 : 1;
444 usort($this->fieldValueParts, $sort);
445 $this->sorted = true;
449 * @return array with all the keys, values and parameters this header represents:
451 public function getPrioritized()
453 if (!$this->sorted) {
454 $this->sortFieldValueParts();
457 return $this->fieldValueParts;