238 lines
6.6 KiB
PHP
238 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace http\core;
|
|
|
|
|
|
class HttpRequest{
|
|
|
|
/* [0] Constants
|
|
=========================================================*/
|
|
/* (1) Content-Type */
|
|
const CT_BINARY = 0; // unknown
|
|
const CT_TEXT = 1;
|
|
const CT_JSON = 2;
|
|
const CT_YAML = 3;
|
|
const CT_MULTIPART_FORM_DATA = 4;
|
|
const CT_X_WWW_FORM_URLENCODED = 5;
|
|
|
|
|
|
/* [1] Attributes
|
|
=========================================================*/
|
|
private $uri;
|
|
private $headers;
|
|
private $method;
|
|
private $postdata;
|
|
private $getdata;
|
|
|
|
private $type;
|
|
private $body;
|
|
|
|
|
|
/* [2] Constructs an HTTP Request based on environment
|
|
*
|
|
* @return instance<HttpRequest> auto-filled HTTP Request
|
|
*
|
|
=========================================================*/
|
|
public function __construct(){
|
|
/* [1] Define URI & Status Code & method
|
|
=========================================================*/
|
|
$this->uri = $_SERVER['REQUEST_URI'];
|
|
$this->method = $_SERVER['REQUEST_METHOD'];
|
|
|
|
|
|
/* [2] Define headers
|
|
=========================================================*/
|
|
$this->headers = self::getallheaders_adapter();
|
|
|
|
|
|
/* [3] Define default datasets (GET, POST)
|
|
=========================================================*/
|
|
/* (1) Add to $_GET legacy GET parameters */
|
|
parse_str(parse_url($this->uri)['query'], $legacy_get);
|
|
$_GET = array_merge($_GET, $legacy_get);
|
|
|
|
/* (2) Store GET parameters */
|
|
$this->getdata = $_GET;
|
|
|
|
/* (3) Store POST parameters */
|
|
$this->postdata = $_POST;
|
|
|
|
|
|
/* [4] Define BODY & its type
|
|
=========================================================*/
|
|
/* (1) Default: set plain/text body */
|
|
$this->body = \file_get_contents('php://input');
|
|
|
|
/* (2) Fetch content type */
|
|
if( isset($this->headers['Content-Type']) )
|
|
$this->type = self::getContentType($this->headers['Content-Type']);
|
|
else
|
|
$this->type = self::getContentType();
|
|
|
|
|
|
/* [5] Parse BODY data -> POST
|
|
=========================================================*/
|
|
$this->parseBody();
|
|
}
|
|
|
|
|
|
|
|
/* GET CONSTANT CT_* FROM `Content-Type` HEADER
|
|
*
|
|
* @pContentType<String> `Content-Type` header value
|
|
*
|
|
* @return type<int> Constant value
|
|
*
|
|
*/
|
|
private static function getContentType($pContentType=null){
|
|
/* [1] Checks argv
|
|
=========================================================*/
|
|
if( is_null($pContentType) )
|
|
if( isset($_SERVER['CONTENT_TYPE']) )
|
|
$pContentType = $_SERVER['CONTENT_TYPE'];
|
|
else
|
|
$pContentType = 'text/plain';
|
|
|
|
|
|
/* [2] Checks types
|
|
=========================================================*/
|
|
/* (1) Form Data Types
|
|
---------------------------------------------------------*/
|
|
/* (1) multipart/form-data */
|
|
if( preg_match('/^multipart\/form\-data; boundary=(.+)$/i', $pContentType) )
|
|
return self::CT_MULTIPART_FORM_DATA;
|
|
|
|
/* (2) application/x-www-form-urlencoded */
|
|
if( preg_match('/^application\/x\-www\-form\-urlencoded/i', $pContentType) )
|
|
return self::CT_X_WWW_FORM_URLENCODED;
|
|
|
|
|
|
/* (2) Data types
|
|
---------------------------------------------------------*/
|
|
/* (1) Basic JSON content type */
|
|
if( preg_match('/^application\/json/i', $pContentType) )
|
|
return self::CT_JSON;
|
|
|
|
/* (2) Basic YAML content type */
|
|
if( preg_match('/^application\/yaml/i', $pContentType) )
|
|
return self::CT_YAML;
|
|
|
|
/* (3) Basic TEXT content type */
|
|
if( preg_match('/text\/[a-z]+/', $pContentType) )
|
|
return self::CT_TEXT;
|
|
|
|
|
|
/* (3) Default Type
|
|
---------------------------------------------------------*/
|
|
return self::CT_BINARY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PARSES BODY DATA
|
|
*
|
|
*/
|
|
private function parseBody(){
|
|
/* [1] If empty body -> do nothing
|
|
=========================================================*/
|
|
if( strlen($this->body) === 0 )
|
|
return true;
|
|
|
|
|
|
/* [2] Management for each ContentType
|
|
=========================================================*/
|
|
switch($this->type){
|
|
|
|
/* (1) multipart/form-data -> parse for not-POST methods
|
|
---------------------------------------------------------*/
|
|
case self::CT_MULTIPART_FORM_DATA:
|
|
/* (1) Fetch the boundary */
|
|
if( !preg_match('/boundary=(.+)$/i', $this->headers['Content-Type'], $match) )
|
|
return false;
|
|
|
|
$boundary = $match[1];
|
|
|
|
/* (2) Break body into parts */
|
|
$splitter = "/(?:\n|\r\n|--)*$boundary(?:\n|\r\n|--)?/im";
|
|
$parts = preg_split($splitter, $this->body);
|
|
|
|
/* (3) Process parts */
|
|
foreach($parts as $part)
|
|
if( preg_match('/^Content\-Disposition: form\-data; name=\"([^"]+)\"(?:\n|\r\n){2}(.+)$/mi', $part, $match) )
|
|
$this->postdata[$match[1]] = $match[2];
|
|
|
|
/* (4) Erases body */
|
|
$this->body = '';
|
|
break;
|
|
|
|
|
|
/* (2) application/x-www-form-urlencoded -> parse for not-POST methods
|
|
---------------------------------------------------------*/
|
|
case self::CT_X_WWW_FORM_URLENCODED:
|
|
/* Auto parse builtin-php function */
|
|
parse_str($this->body, $this->postdata);
|
|
|
|
/* Erases body */
|
|
$this->body = '';
|
|
break;
|
|
|
|
|
|
/* (3) application/json -> parse if no error
|
|
---------------------------------------------------------*/
|
|
case self::CT_JSON:
|
|
/* (1) Decode body content */
|
|
$decoded = json_decode($this->body, true);
|
|
|
|
/* (2) If error -> do nothing */
|
|
if( is_null($decoded) )
|
|
return;
|
|
|
|
/* (3) Parse body into body */
|
|
$this->body = $decoded;
|
|
break;
|
|
|
|
|
|
/* (4) application/yaml -> parse if no error
|
|
---------------------------------------------------------*/
|
|
case self::CT_YAML:
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
public function BODY(){ return $this->body; }
|
|
public function POST(){ return $this->postdata; }
|
|
public function GET(){ return $this->getdata; }
|
|
public function HEADERS(){ return $this->headers; }
|
|
public function METHOD(){ return $this->method; }
|
|
public function URI(){ return $this->uri; }
|
|
|
|
|
|
private static function getallheaders_adapter(){
|
|
/* (1) If exists -> use it
|
|
---------------------------------------------------------*/
|
|
if( function_exists('getallheaders') )
|
|
return getallheaders();
|
|
|
|
/* (2) If does not (php-fpm)
|
|
---------------------------------------------------------*/
|
|
/* (1) init. variables */
|
|
$fetched_headers = [];
|
|
|
|
/* (2) Get all headers from $_SERVER */
|
|
foreach($_SERVER as $hname=>$hvalue ){
|
|
|
|
// {1} Store only if begins with 'HTTP_' //
|
|
if( substr($hname,0,5) == 'HTTP_' )
|
|
$fetched_headers[ str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($hname,5)))))] = $hvalue;
|
|
|
|
}
|
|
|
|
/* (3) Return created headers */
|
|
return $fetched_headers;
|
|
|
|
}
|
|
}
|