@ 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 git.master , git.master_jit , rfc.property-hooks 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
This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.
Active branches Archived branches Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page
preferences:dark mode live preview
56.06 ms | 401 KiB | 8 Q