setDisposition($parts[0]); if (isset($parts[1])) { $values = ListParser::parse(trim($parts[1]), [';', '=']); $length = count($values); $continuedValues = []; for ($i = 0; $i < $length; $i += 2) { $value = $values[$i + 1]; $value = trim($value, "'\" \t\n\r\0\x0B"); $name = trim($values[$i], "'\" \t\n\r\0\x0B"); if (strpos($name, '*')) { [$name, $count] = explode('*', $name); // allow optional count: // Content-Disposition: attachment; filename*=UTF-8''%64%61%61%6D%69%2D%6D%C3%B5%72%76%2E%6A%70%67 if ($count === "") { $count = 0; } if (! is_numeric($count)) { $type = gettype($count); $value = var_export($count, true); throw new Exception\InvalidArgumentException(sprintf( "Invalid header line for Content-Disposition string" . " - count expected to be numeric, got %s with value %s", $type, $value )); } if (! isset($continuedValues[$name])) { $continuedValues[$name] = []; } $continuedValues[$name][$count] = $value; } else { $header->setParameter($name, $value); } } foreach ($continuedValues as $name => $values) { $value = ''; for ($i = 0, $iMax = count($values); $i < $iMax; $i++) { if (! isset($values[$i])) { throw new Exception\InvalidArgumentException( 'Invalid header line for Content-Disposition string - incomplete continuation' . '; HeaderLine: ' . $headerLine ); } $value .= $values[$i]; } $header->setParameter($name, $value); } } return $header; } /** * @inheritDoc */ public function getFieldName() { return 'Content-Disposition'; } /** * @inheritDoc */ public function getFieldValue($format = HeaderInterface::FORMAT_RAW) { $result = $this->disposition; if (empty($this->parameters)) { return $result; } foreach ($this->parameters as $attribute => $value) { $valueIsEncoded = false; if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) { $value = $this->getEncodedValue($value); $valueIsEncoded = true; } $line = sprintf('%s="%s"', $attribute, $value); if (strlen($line) < self::MAX_PARAMETER_LENGTH) { $lines = explode(Headers::FOLDING, $result); if (count($lines) === 1) { $existingLineLength = strlen('Content-Disposition: ' . $result); } else { $existingLineLength = 1 + strlen($lines[count($lines) - 1]); } if ((2 + $existingLineLength + strlen($line)) <= self::MAX_PARAMETER_LENGTH) { $result .= '; ' . $line; } else { $result .= ';' . Headers::FOLDING . $line; } } else { // Use 'continuation' per RFC 2231 if ($valueIsEncoded) { $value = HeaderWrap::mimeDecodeValue($value); } $i = 0; $fullLength = mb_strlen($value, 'UTF-8'); while ($fullLength > 0) { $attributePart = $attribute . '*' . $i++ . '="'; $attLen = mb_strlen($attributePart, 'UTF-8'); $subPos = 1; $valuePart = ''; while ($subPos <= $fullLength) { $sub = mb_substr($value, 0, $subPos, 'UTF-8'); if ($valueIsEncoded) { $sub = $this->getEncodedValue($sub); } if ($attLen + mb_strlen($sub, 'UTF-8') >= self::MAX_PARAMETER_LENGTH) { $subPos--; break; } $subPos++; $valuePart = $sub; } $value = mb_substr($value, $subPos, null, 'UTF-8'); $fullLength = mb_strlen($value, 'UTF-8'); $result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"'; } } } return $result; } /** * @param string $value * @return string */ protected function getEncodedValue($value) { $configuredEncoding = $this->encoding; $this->encoding = 'UTF-8'; $value = HeaderWrap::wrap($value, $this); $this->encoding = $configuredEncoding; return $value; } /** * @inheritDoc */ public function setEncoding($encoding) { $this->encoding = $encoding; return $this; } /** * @inheritDoc */ public function getEncoding() { return $this->encoding; } /** * @inheritDoc */ public function toString() { return 'Content-Disposition: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED); } /** * Set the content disposition * Expected values include 'inline', 'attachment' * * @param string $disposition * @return ContentDisposition */ public function setDisposition($disposition) { $this->disposition = strtolower($disposition); return $this; } /** * Retrieve the content disposition * * @return string */ public function getDisposition() { return $this->disposition; } /** * Add a parameter pair * * @param string $name * @param string $value * @return ContentDisposition */ public function setParameter($name, $value) { $name = strtolower($name); if (! HeaderValue::isValid($name)) { throw new Exception\InvalidArgumentException( 'Invalid content-disposition parameter name detected' ); } // '5' here is for the quotes & equal sign in `name="value"`, // and the space & semicolon for line folding if ((strlen($name) + 5) >= self::MAX_PARAMETER_LENGTH) { throw new Exception\InvalidArgumentException( 'Invalid content-disposition parameter name detected (too long)' ); } $this->parameters[$name] = $value; return $this; } /** * Get all parameters * * @return array */ public function getParameters() { return $this->parameters; } /** * Get a parameter by name * * @param string $name * @return null|string */ public function getParameter($name) { $name = strtolower($name); if (isset($this->parameters[$name])) { return $this->parameters[$name]; } return null; } /** * Remove a named parameter * * @param string $name * @return bool */ public function removeParameter($name) { $name = strtolower($name); if (isset($this->parameters[$name])) { unset($this->parameters[$name]); return true; } return false; } }