How to parse / validate / handle http headers in PHP

1.6k Views Asked by At

Currently i am building my own php framework and i am now creating an implementation of the PHP-FIG PSR-7 MessageInterface. In specific the withHeader method. It states that the method could trow an exeption: \InvalidArgumentException for invalid header names or values.

So i am wondering, when is a header valid or invalid? Same for the values. Or should i accept any header, and any header value? That could be dangerous right?

I now you can generaly say that if a header has multiple values, they are comma seperated. But that does not allways apply. If i look at a user-agent header for example, the value itself sometimes contains a comma. But you should treat it as a single value.

2

There are 2 best solutions below

0
On BEST ANSWER

Indeed, it's "dangerous" to pass a header name - as argument of withHeader(), which

  • is NULL
  • is not a string
  • is an empty string

The same applies to the header value argument. It must be an array or a string (representing only one value, not a comma-separated list of values!).

As for the implementation of the withHeader method:

/**
 * Return an instance with the provided value replacing the specified header.
 *
 * ...
 *
 * @param string $name Case-insensitive header field name.
 * @param string|string[] $value Header value(s).
 * @return static
 * @throws \InvalidArgumentException for invalid header names or values.
 */
public function withHeader($name, $value) {
    $this
            ->validateHeaderName($name)
            ->validateHeaderValue($value)
    ;

    $clone = clone $this;

    $clone->replaceHeader($name, $value);

    return $clone;
}

/**
 * =================
 * Not part of PSR-7
 * =================
 * 
 * Validate header name.
 * 
 * @param string $name Case-insensitive header field name.
 * @return $this
 * @throws \InvalidArgumentException
 */
protected function validateHeaderName($name) {
    if (!isset($name)) {
        throw new \InvalidArgumentException('No header name provided!');
    }

    if (!is_string($name)) {
        throw new \InvalidArgumentException('The header name must be a string!');
    }

    if (empty($name)) {
        throw new \InvalidArgumentException('Empty header name provided!');
    }

    return $this;
}

/**
 * =================
 * Not part of PSR-7
 * =================
 * 
 * Validate header value.
 * 
 * @param string|string[] $value Header value(s).
 * @return $this
 * @throws \InvalidArgumentException
 */
protected function validateHeaderValue($value) {
    if (isset($value) && !is_array($value) && !is_string($value)) {
        throw new \InvalidArgumentException('The header value must be a string or an array!');
    }

    return $this;
}

/**
 * =================
 * Not part of PSR-7
 * =================
 * 
 * Replace a header item with a new one.
 * 
 * @param string $name Case-insensitive header field name.
 * @param string|string[] $value Header value(s).
 * @return $this
 * @done
 */
protected function replaceHeader($name, $value) {
    $this
            ->removeHeader($name)
            ->addHeader($name, $value)
    ;

    return $this;
}
0
On

You can find that in RFC 7230. Check Zend Diactoro's HeaderSecurity class for an implementation.