@ 2013-07-31T17:55:55Z <?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'));
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
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:dark mode live preview
204.2 ms | 401 KiB | 302 Q