Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/old/lib/internal/Customweb/Core/Http/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //home/corals/old/lib/internal/Customweb/Core/Http/AbstractMessage.php
<?php 
/**
  * You are allowed to use this API in your web application.
 *
 * Copyright (C) 2018 by customweb GmbH
 *
 * This program is licenced under the customweb software licence. With the
 * purchase or the installation of the software in your application you
 * accept the licence agreement. The allowed usage is outlined in the
 * customweb software licence which can be found under
 * http://www.sellxed.com/en/software-license-agreement
 *
 * Any modification or distribution is strictly forbidden. The license
 * grants you the installation in one application. For multiuse you will need
 * to purchase further licences at http://www.sellxed.com/shop.
 *
 * See the customweb software licence agreement for more details.
 *
 */



/**
 * Abstract impementation of a HTTP message. The class provides
 * basic facilities to handle HTTP message. 
 * 
 * Sub classes must implement a copy constructor.
 * 
 * @author hunziker
 *
 */
abstract class Customweb_Core_Http_AbstractMessage implements Customweb_Core_Http_IMessage{

	/**
	 * Header key for 'content-type' header.
	 * 
	 * @var string
	 */
	const HEADER_KEY_CONTENT_TYPE = 'content-type';
	
	/**
	 * Header key for 'content-encoding' header.
	 *
	 * @var string
	 */
	const HEADER_KEY_CONTENT_ENCODING = 'content-encoding';
	
	/**
	 * Header key for 'content-length' header.
	 *
	 * @var string
	 */
	const HEADER_KEY_CONTENT_LENGTH = 'content-length';

	/**
	 * @var string
	 */
	private $statusLine = null;
	
	/**
	 * @var array
	 */
	private $headers = array();
	
	/**
	 * @var array
	 */
	private $parsedHeaders = array();
	
	/**
	 * @var string
	 */
	private $protocolVersion = '1.1';

	/**
	 * @var string
	 */
	private $body = '';
	
	/**
	 * @var array
	 */
	private $parsedBody = null;
	
	/**
	 * @var int
	 */
	private $contentLength = 0;
	
	/**
	 * @var string
	 */
	private $contentType = null;
	
	/**
	 * @var string
	 */
	private $contentEncoding = null;
	
	public function __construct($message = null) {
		if ($message !== null) {
			if ($message instanceof Customweb_Core_Http_AbstractMessage) {
				$this->body = $message->body;
				$this->headers = $message->headers;
				$this->parsedBody = $message->parsedBody;
				$this->protocolVersion = $message->protocolVersion;
				$this->parsedHeaders = $message->parsedHeaders;
				$this->contentLength = $message->contentLength;
				$this->contentType = $message->contentType;
				$this->contentEncoding = $message->contentEncoding;
			}
			else {
				$message = (string)$message;
				$this->parseRawMessage($message);
			}
		}
		else {
			$this->setHeaders(
				array(
					'connection: close',
				)
			);
		}
	}
	
	/**
	 * Parses the status line.
	 * 
	 * @param string $line
	 * @return void
	 */
	protected abstract function parseStatusLine($line);

	/**
	 * Returns the body of the message.
	 * 
	 * @return string
	 */
	public function getBody(){
		return $this->body;
	}

	/**
	 * Tries to parse the body string as a query string into an array. In 
	 * case the body of the message is not a query string this method may
	 * lead to strange results.
	 * 
	 * @return array
	 */
	public function getParsedBody() {
		if ($this->parsedBody === null) {
			$this->parsedBody = self::parseBodyToArray($this->body);
		}
		return $this->parsedBody;
	}
	
	/**
	 * Sets the body of the message. Either a string or array can be 
	 * provided. In case it is an array the body is treated as a query
	 * string. 
	 *
	 * 
	 * @param string|array $body
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function setBody($body) {
		if (is_array($body)) {
			$this->body = Customweb_Core_Url::parseArrayToString($body);
			$this->parsedBody = $body;
		}
		else {
			$this->body = (string)$body;
		}
		$this->removeHeadersWithKey(self::HEADER_KEY_CONTENT_LENGTH);
		$length = strlen($this->body);
		if ($length > 0) {
			$this->appendHeader(self::HEADER_KEY_CONTENT_LENGTH . ': ' . $length);			
		}
		return $this;
	}
	
	/**
	 * This method appends the given string to the body of the message. 
	 * 
	 * @param string $string The string to append
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function appendBody($string) {
		$string = (string)$string;
		$body = $this->getBody();
		$this->setBody($body . $string);
		return $this;
	}
	
	/**
	 * This method prepends the given string to the body of the
	 * message.
	 * 
	 * @param string $string The string to prepend.
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function prependBody($string) {
		$string = (string)$string;
		$body = $this->getBody();
		$this->setBody($string . $body);
		return $this;
	}
		
	/**
	 * Returns all headers of the message as a list. The key is a numeric
	 * one.
	 * 
	 * @return array
	 */
	public function getHeaders(){
		return $this->headers;
	}

	/**
	 * Returns a key/value map of the headers which are key/value pairs. The 
	 * order of the items is not preserved. The key is always lower case.
	 * 
	 * Sample output:
	 * array(
	 *   'content-type' => array('text/html'),
	 *   'content-length' => array('345'),
	 * )
	 * 
	 * @return array
	 */
	public function getParsedHeaders() {
		return $this->parsedHeaders;
	}
	
	/**
	 * This method sets all headers of the message. The headers are parsed an
	 * the internal state of the message may be changed. If only a single header
	 * should be changed either the dedicated method for the operation should be 
	 * used or then the appendHeader method should be used.
	 * 
	 * @param array $headers
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function setHeaders(array $headers){
		$this->resetHeaders();
		foreach ($headers as $header) {
			$this->appendHeader($header);
		}
		return $this;
	}
	
	/**
	 * This method adds the given header at the end of the list.
	 * 
	 * @param string $header
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function appendHeader($header) {
		$this->parseHeader($header);
		$this->headers[] = $header;
		return $this;
	}
	
	/**
	 * Returns the protocol version of the message.
	 * 
	 * @return string
	 */
	public function getProtocolVersion(){
		return $this->protocolVersion;
	}
	
	/**
	 * This method sets the protocol version 
	 * 
	 * @param string $protocolVersion
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function setProtocolVersion($protocolVersion){
		if (!is_string($protocolVersion)) {
			$protocolVersion = (string)$protocolVersion;
		}
		$this->protocolVersion = $protocolVersion;
		return $this;
	}
	
	/**
	 * Returns the content type of the message. This may be null. If no content
	 * type was defined.
	 * 
	 * @return string
	 */
	public function getContentType(){
		return $this->contentType;
	}
	
	/**
	 * Sets the content type header.
	 * 
	 * @param string $contentType
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function setContentType($contentType){
		$this->removeHeadersWithKey(self::HEADER_KEY_CONTENT_TYPE);
		if ($contentType !== null) {
			$this->appendHeader(self::HEADER_KEY_CONTENT_TYPE . ': ' . $contentType);
		}
		return $this;
	}
	
	/**
	 * Returns the content encoding of the request. This may be null.
	 * 
	 * @return string
	 */
	public function getContentEncoding(){
		return $this->contentEncoding;
	}
	
	/**
	 * Sets the conent encoding (e.g. gzip, deflate etc.). If this is
	 * changed the body must be manually changed.
	 * 
	 * @param string $contentEncoding
	 * @return Customweb_Core_Http_AbstractMessage
	 */
	public function setContentEncoding($contentEncoding){
		$this->removeHeadersWithKey(self::HEADER_KEY_CONTENT_ENCODING);
		if ($contentEncoding !== null) {
			$this->appendHeader(self::HEADER_KEY_CONTENT_ENCODING . ': ' . $contentEncoding);
		}
		return $this;
	}
	
	/**
	 * Returns the content length header.
	 * 
	 * @return number
	 */
	public function getContentLength() {
		return $this->contentLength;
	}
	
	/**
	 * Returns the message as a string.
	 *
	 * @return string
	 */
	public function toString() {
		$output = $this->getStatusLine() . "\r\n";
		foreach ($this->getHeaders() as $header) {
			$output .= $header . "\r\n";
		}
		$output .= "\r\n";
		$output .= $this->getBody();
		return $output;
	}
	
	/**
	 * Returns the message as a string.
	 * 
	 * @return string
	 */
	public function __toString() {
		return $this->toString();
	}
	
	############ Methods for sup types ###############
	
	/**
	 * This method parses the given header. In case the header is a key / value 
	 * pair the header is written to the list of parsed headers.
	 * 
	 * @param string $header
	 * @throws Exception
	 */
	protected final function parseHeader($header) {
		if (!is_string($header)) {
			throw new Exception("The given header is not a string.");
		}
		
		if (preg_match('/([^:]+):(.*)/', $header, $rs)) {
			$key = strtolower($rs[1]);
			$value = trim($rs[2]);
			$key = strtolower($key);
			if (!isset($this->parsedHeaders[$key])) {
				$this->parsedHeaders[$key] = array();
			}
			$this->parsedHeaders[$key][] = $value;
			$this->processKeyedHeader($key, $value);
		}
		else {
			throw new Exception(Customweb_Core_String::_("Invalid format of the header '@header'. It must contain a ':' char.")->format(array('@header' => $header)));
		}
	}
	
	/**
	 * This method is called when a keyed header is parsed. This method 
	 * should be overriden by sup classes to update the internal state.
	 * The key is always in lowercase.
	 * 
	 * @param string $headerKey
	 * @param string $headerValue
	 */
	protected function processKeyedHeader($headerKey, $headerValue) {
		if ($headerKey == self::HEADER_KEY_CONTENT_LENGTH) {
			$this->contentLength = (int)$headerValue;
		}
		else if ($headerKey == self::HEADER_KEY_CONTENT_TYPE) {
			$this->contentType = $headerValue;
		}
		else if ($headerKey == self::HEADER_KEY_CONTENT_ENCODING) {
			$this->contentEncoding = $headerValue;
		}
	}

	/**
	 * Resets the whole state regarding header. Sub classes should override 
	 * this method to make sure their state is also reseted.
	 * 
	 * @return void
	 */
	protected function resetHeaders() {
		$this->headers = array();
		$this->parsedHeaders = array();
		$this->protocolVersion = '1.1';
	}
	
	/**
	 * This method removes all headers with the given key.
	 * 
	 * @param string $key The key of the header
	 */
	public function removeHeadersWithKey($key) {
		$prefix = $key . ':';
		foreach ($this->headers as $k => $value) {
			if (strpos(strtolower($value), strtolower($prefix)) === 0) {
				unset($this->headers[$k]);
				unset($this->parsedHeaders[$key]);
			}
		}
	}

	/**
	 * Parse the given HTTP message.
	 *
	 * @param string $message
	 * @return void
	 */
	protected function parseRawMessage($message) {
		$positionStartBody = strpos($message, "\r\n\r\n");
		
		$startPositionOffset = 4;
		if ($positionStartBody === false) {
			$positionStartBody = strpos($message, "\n\n");
			$startPositionOffset = 2;
			if ($positionStartBody === false) {
				throw new Exception("Invalid HTTP message provided. It does not contain a header part.");
			}
		}
		
		$headerString = str_replace("\r\n", "\n", trim(substr($message, 0, $positionStartBody), "\r\n"));
		$content = substr($message, $positionStartBody + $startPositionOffset);
	
		$headers = explode("\n", $headerString);
		$statusLine = current($headers);
		array_shift($headers);
		$this->setHeaders($headers);
		$this->parseStatusLine($statusLine);
		$this->setBody($content);
	}
	

	################# Utils methods ##################
	
	protected static function parseBodyToArray($input) {
		$output = array();
		// We expect that that at least a '=' char must be present, otherwise
		// it is not a valid input.
		if (strstr($input, '=')) {
			parse_str($input, $output);
		}
		return $output;
	}
	
}

Spamworldpro Mini