Skip to content

Commit

Permalink
Add supports for Restful.
Browse files Browse the repository at this point in the history
  • Loading branch information
terrylinooo committed Jul 15, 2020
1 parent 0994fce commit 8978cbd
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 7 deletions.
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ echo $uploadFileArr['foo']->getClientFilename();
- [withQueryParams](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-withQueryParams-Example)
- [getUploadedFiles](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-getUploadedFiles-Example)
- [withUploadedFiles](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-withUploadedFiles-Example)
- [getParsedBody](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-getParsedBody-Example)
- [getParsedBody](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-getParsedBody-Example) (See explanation below)
- [withParsedBody](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-withParsedBody-Example)
- [getAttributes](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-getAttributes-Example)
- [getAttribute](https://github.com/terrylinooo/psr-http/wiki/ServerRequest:-getAttribute-Example)
Expand Down Expand Up @@ -225,6 +225,37 @@ echo $uploadFileArr['foo']->getClientFilename();

If you are looking for combined examples, see [unit testing](https://github.com/terrylinooo/psr-http/tree/master/tests).

### The Behavior of Handling Request Body

Shieldon PSR-HTTP is ready for RESTful, the following content explains how PRS-HTTP deals with the request body.

- **A.** The `getParsedBody` method returns an array of the superglobal *$_POST* if the request request method is `POST` and the Content-Type is one of the following type:
- `multipart/form-data`
- `application/x-www-form-urlencode`


- **B.** The `getParsedBody` method returns a JSON object if the request fit to the following conditions.
- The request Content-Type is `application/json`
- The request body is a valid *JSON-formatted* string.
- The request method is not `GET`.

- **C.** The `getParsedBody` method returns a array parsed from HTTP build query:
- The condition is neither A or B.
- The request method is not `GET`.

- **D.** The `getParsedBody` method returns `null` if the condition is not one of above.

#### Summary

| Condition| Method | Content-type | Parsed-body |
| --- | --- | --- | --- |
| A | POST | multipart/form-data<br />application/x-www-form-urlencode | array |
| B | ALL excepts GET | application/json | object |
| C | ALL excepts GET | Not A or B | array |
| D | - | - | null |

Hope this helps.

---

## Author
Expand Down
12 changes: 12 additions & 0 deletions src/Psr17/Utils/SuperGlobal.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ public static function extract(): array
self::mockCliEnvironment();
}

// Here we add the HTTP prefix by ourselves...
$headerParamsWithoutHttpPrefix = [
'CONTENT_TYPE',
'CONTENT_LENGTH',
];

foreach ($headerParamsWithoutHttpPrefix as $value) {
if (isset($_SERVER[$value])) {
$_SERVER['HTTP_' . $value] = $_SERVER[$value];
}
}

$headerParams = [];
$serverParams = $_SERVER ?? [];
$cookieParams = $_COOKIE ?? [];
Expand Down
78 changes: 73 additions & 5 deletions src/Psr7/ServerRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,19 @@
use Shieldon\Psr7\Request;
use Shieldon\Psr7\Utils\UploadedFileHelper;
use InvalidArgumentException;

use function file_get_contents;
use function gettype;
use function is_array;
use function is_null;
use function is_object;
use function json_decode;
use function json_last_error;
use function parse_str;
use function preg_split;
use function sprintf;
use function gettype;
use function strtolower;
use function strtoupper;
use const JSON_ERROR_NONE;

/*
* Representation of an incoming, server-side HTTP request.
Expand Down Expand Up @@ -111,9 +118,7 @@ public function __construct(
$this->queryParams = $getParams;
$this->attributes = [];

if (!empty($postParams)) {
$this->parsedBody = $postParams;
}
$this->determineParsedBody($postParams);

// This property will be assigned to a parsed array that contains
// the UploadedFile instance(s) as the $filesParams is given.
Expand Down Expand Up @@ -308,4 +313,67 @@ protected function assertParsedBody($data): void
);
}
}

/**
* Confirm the content type and post values whether fit the requirement.
*
* @param array $postParams
* @return void
*/
protected function determineParsedBody(array $postParams)
{
$headerContentType = $this->getHeaderLine('Content-Type');
$contentTypeArr = preg_split('/\s*[;,]\s*/', $headerContentType);
$contentType = strtolower($contentTypeArr[0]);
$httpMethod = strtoupper($this->getMethod());

// Is it a form submit or not.
$isForm = false;

if ($httpMethod === 'POST' && !empty($postParams)) {

// If the request Content-Type is either application/x-www-form-urlencoded
// or multipart/form-data, and the request method is POST, this method MUST
// return the contents of $_POST.
$postRequiredContentTypes = [
'', // For unit testing purpose.
'application/x-www-form-urlencoded',
'multipart/form-data',
];

if (in_array($contentType, $postRequiredContentTypes)) {
$this->parsedBody = $postParams ?: null;
$isForm = true;
}
}

// Maybe other http methods such as PUT, DELETE, etc...
if ($httpMethod !== 'GET' && !$isForm) {

// If it a JSON formatted string?
$isJson = false;

// Receive content from PHP stdin input, if exists.
$rawText = file_get_contents('php://input');

if (!empty($rawText)) {

if ($contentType === 'application/json') {
$jsonParsedBody = json_decode($rawText);
$isJson = (json_last_error() === JSON_ERROR_NONE);
}

// Condition 1 - It's a JSON, now the body is a JSON object.
if ($isJson) {
$this->parsedBody = $jsonParsedBody ?: null;
}

// Condition 2 - It's not a JSON, might be a http build query.
if (!$isJson) {
parse_str($rawText, $parsedStr);
$this->parsedBody = $parsedStr ?: null;
}
}
}
}
}
1 change: 0 additions & 1 deletion tests/Psr7/ServerRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ public function test_GetPrefixMethods()
$this->assertSame($serverRequest->getAttributes(), []);;

// Test 2

$serverRequest = self::getServerRequest(
'POST',
['foo' => 'bar'],
Expand Down

0 comments on commit 8978cbd

Please sign in to comment.