3v4l.org

run code in 300+ PHP versions simultaneously
<?php class ContentTypeBuilder { private $contentTypeFactory; private $CTLs = [ "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, "\x08" => 1, /* "\x09" */ /* "\x0A" */ "\x0B" => 1, "\x0C" => 1, /* "\x0D" */ "\x0E" => 1, "\x0F" => 1, "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, "\x18" => 1, "\x19" => 1, "\x1A" => 1, "\x1B" => 1, "\x1C" => 1, "\x1D" => 1, "\x1E" => 1, "\x1F" => 1, "\x7F" => 1, ]; private $LWS = [ "\x09" => 1, "\x0A" => 1, "\x0D" => 1, "\x20" => 1, ]; private $separators = [ "\x28" => '(', "\x29" => ')', "\x3C" => '<', "\x3E" => '>', "\x40" => '@', "\x2C" => ',', "\x3A" => ':', "\x5C" => '\\', "\x22" => '"', "\x5B" => '[', "\x5D" => ']', "\x3F" => '?', "\x7B" => '{', "\x7D" => '}', ]; public function __construct(ContentTypeFactory $contentTypeFactory) { $this->contentTypeFactory = $contentTypeFactory; } public function build($typeDef, &$qValue = null) { /* Note: * * This routine favours speed and efficiency over readability and DRY. Deal with it. * * All chars are written as hex literals, to avoid any breakage if some idiot changes the * encoding of this source file to something that doesn't use ASCII code points for the * lower 128. AFAIK the PHP interpreter doesn't yet support this, but this code is a * literal implementation of a concrete spec and doesn't need to be maintainable in the * traditional sense, so I don't want to have to come back here to maintain it. */ $typeDefBytes = (string) $typeDef; $totalLength = strlen($typeDefBytes); $bytePos = 0; // Skip leading LWS while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; $type = "\x00"; for (; $bytePos < $totalLength; $bytePos++) { if ( isset($this->CTLs[$typeDefBytes[$bytePos]]) // CTL || isset($this->LWS[$typeDefBytes[$bytePos]]) // LWS || isset($this->separators[$typeDefBytes[$bytePos]]) // separator || ($typeDefBytes[$bytePos] & "\x80") === "\x80" // >127 || $typeDefBytes[$bytePos] === "\x3B" // ; || $typeDefBytes[$bytePos] === "\x3D" // = ) { trigger_error( 'Syntax error in Accept header value:' . ' invalid token character ' . $typeDefBytes[$bytePos] . ' (0x' . sprintf('%02X', ord($typeDefBytes[$bytePos])) . ')' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } else if ($typeDefBytes[$bytePos] === "\x2F") { // / $bytePos++; break; } else { $type[$bytePos] = $typeDefBytes[$bytePos]; } } $subType = "\x00"; for ($valuePos = 0; $bytePos < $totalLength; $bytePos++) { if ( isset($this->CTLs[$typeDefBytes[$bytePos]]) // CTL || isset($this->separators[$typeDefBytes[$bytePos]]) // separator || ($typeDefBytes[$bytePos] & "\x80") === "\x80" // >127 || $typeDefBytes[$bytePos] === "\x2F" // / || $typeDefBytes[$bytePos] === "\x3D" // = ) { // invalid char for token trigger_error( 'Syntax error in Accept header value:' . ' invalid token character ' . $typeDefBytes[$bytePos] . ' (0x' . sprintf('%02X', ord($typeDefBytes[$bytePos])) . ')' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } else if (isset($this->LWS[$typeDefBytes[$bytePos]])) { // LWS $bytePos++; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; if ($typeDefBytes[$bytePos] === "\x3B") $bytePos++; // ; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; break; } else if ($typeDefBytes[$bytePos] === "\x3B") { // ; $bytePos++; while ($bytePos < $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; break; } else { $subType[$valuePos++] = $typeDefBytes[$bytePos]; } } // */something is not valid if ($type === "\x2A" && $subType !== "\x2A") { // * trigger_error( 'Semantic error in Accept header value:' . ' */' . $subType . ' is not a valid media-type' , E_USER_NOTICE); return null; } $params = []; $qValue = 1; while ($bytePos < $totalLength) { $name = "\x00"; for ($valuePos = 0; $bytePos < $totalLength; $bytePos++) { if ( isset($this->CTLs[$typeDefBytes[$bytePos]]) // CTL || isset($this->LWS[$typeDefBytes[$bytePos]]) // LWS || isset($this->separators[$typeDefBytes[$bytePos]]) // separator || ($typeDefBytes[$bytePos] & "\x80") === "\x80" // >127 || $typeDefBytes[$bytePos] === "\x3B" // ; || $typeDefBytes[$bytePos] === "\x2F" // / ) { // invalid char for token trigger_error( 'Syntax error in Accept header value:' . ' invalid token character ' . $typeDefBytes[$bytePos] . ' (0x' . sprintf('%02X', ord($typeDefBytes[$bytePos])) . ')' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } else if ($typeDefBytes[$bytePos] === "\x3D") { // = $bytePos++; break; } else { $name[$valuePos++] = $typeDefBytes[$bytePos]; } } if ($bytePos === $totalLength) { trigger_error( 'Syntax error in Accept header value:' . ' media-type parameter ' . $name . ' has no value' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } if (isset($this->LWS[$typeDefBytes[$bytePos]])) { trigger_error( 'Syntax error in Accept header value:' . ' LWS is not legal between a media-type parameter name and its value' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } if ($typeDefBytes[$bytePos] === "\x22") { // " quoted-string if ($typeDefBytes[++$bytePos] === "\x22") { // " empty string $value = ''; $bytePos++; } else { $value = "\x00"; for ($valuePos = 0; $bytePos < $totalLength; $bytePos++) { switch ($typeDefBytes[$bytePos]) { case "\x0D": case "\x0A": case "\x20": case "\x09": // LWS while (isset($this->LWS[$typeDefBytes[$bytePos + 1]])) $bytePos++; $value[$valuePos++] = ' '; // collapse LWS to a single SP break; case "\x22": // " $bytePos++; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; if ($typeDefBytes[$bytePos] === "\x3B") $bytePos++; // ; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; break 2; // end of value case "\x5C": // \ if (($typeDefBytes[++$bytePos] & "\x80") !== "\x00") { trigger_error( 'Syntax error in Accept header value:' . ' invalid quoted single character ' . $typeDefBytes[$bytePos] . ' (0x' . sprintf('%02X', ord($typeDefBytes[$bytePos])) . ')' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; // >127 not a valid escape sequence } // break; intentionally omitted default: $value[$valuePos++] = $typeDefBytes[$bytePos]; } } } } else { // token $value = "\x00"; for ($valuePos = 0; $bytePos < $totalLength; $bytePos++) { if ( isset($this->CTLs[$typeDefBytes[$bytePos]]) // CTL || isset($this->separators[$typeDefBytes[$bytePos]]) // separator || ($typeDefBytes[$bytePos] & "\x80") === "\x80" // >127 || $typeDefBytes[$bytePos] === "\x2F" // / || $typeDefBytes[$bytePos] === "\x3D" // = ) { trigger_error( 'Syntax error in Accept header value:' . ' invalid token character ' . $typeDefBytes[$bytePos] . ' (0x' . sprintf('%02X', ord($typeDefBytes[$bytePos])) . ')' . ' at offset ' . $bytePos , E_USER_NOTICE); return null; } else if (isset($this->LWS[$typeDefBytes[$bytePos]])) { // LWS $bytePos++; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; if ($typeDefBytes[$bytePos] === "\x3B") $bytePos++; // ; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; break; } else if ($typeDefBytes[$bytePos] === "\x3B") { // ; $bytePos++; while ($bytePos !== $totalLength && isset($this->LWS[$typeDefBytes[$bytePos]])) $bytePos++; break; } else { $value[$valuePos++] = $typeDefBytes[$bytePos]; } } } if (($name | "\x20") === "\x71") { // q $qValue = (float) $value; } else { $params[strtolower($name)] = $value; } } return $this->contentTypeFactory->create($type, $subType, $params); } } class ContentTypeFactory { public function create($type, $subType, array $params = []) { return new ContentType($type, $subType, $params); } } class ContentType { private $type; private $subType; private $params; public function __construct($type, $subType, array $params = []) { $this->type = strtolower($type); $this->subType = strtolower($subType); $this->params = $params; } public function __toString() { $params = []; foreach ($this->params as $key => $val) { $params[] = $key . '=' . $val; } return $this->getType() . ($params ? ';' . implode(';', $params) : ''); } public function getFullType() { return $this->type . '/' . $this->subType; } public function setType($type) { $this->type = strtolower($type); } public function getType() { return $this->type; } public function setSubType($subType) { $this->subType = strtolower($subType); } public function getSubType() { return $this->subType; } public function setParam($name, $value) { if ($value === null) { unset($this->params[strtolower($name)]); } else { $this->params[strtolower($name)] = $value; } } public function getParam($name) { return isset($this->params[$name = strtolower($name)]) ? $this->params[$name] : null; } public function hasParam($name) { return isset($this->params[$name = strtolower($name)]); } public function getParams() { return $this->params; } } $f = new ContentTypeBuilder(new ContentTypeFactory); var_dump($f->build('text/html; test= "a test"; things=stuff ; q=0.8'));
Output for 8.2.0 - 8.2.18, 8.3.0 - 8.3.6
Notice: Syntax error in Accept header value: LWS is not legal between a media-type parameter name and its value at offset 16 in /in/BOY6U on line 154 NULL
Output for 5.4.0 - 5.4.45, 5.5.0 - 5.5.38, 5.6.0 - 5.6.28, 7.0.0 - 7.0.20, 7.1.0 - 7.1.20, 7.2.6 - 7.2.33, 7.3.12 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.28
Notice: Syntax error in Accept header value: LWS is not legal between a media-type parameter name and its value at offset 16 in /in/BOY6U on line 158 NULL
Output for 5.3.0 - 5.3.29
Parse error: syntax error, unexpected '[' in /in/BOY6U on line 7
Process exited with code 255.

preferences:
204.2 ms | 401 KiB | 302 Q