Skip to content

Commit 8de1f9a

Browse files
committed
First commit for HTTP Response Header
0 parents  commit 8de1f9a

File tree

10 files changed

+477
-0
lines changed

10 files changed

+477
-0
lines changed

.github/worflows/ci-test.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Tests
2+
3+
on: [ push, pull_request ]
4+
5+
jobs:
6+
run:
7+
runs-on: ${{ matrix.operating-system }}
8+
strategy:
9+
matrix:
10+
operating-system: [ 'ubuntu-latest' ]
11+
php-versions: [ '8.0', '8.1', '8.2' ]
12+
name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }}
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v3
17+
18+
- name: Setup PHP
19+
uses: shivammathur/setup-php@v2
20+
with:
21+
php-version: ${{ matrix.php-versions }}
22+
coverage: none
23+
24+
- name: Check PHP Version
25+
run: php -v
26+
27+
- name: Check Composer Version
28+
run: composer -V
29+
30+
- name: Check PHP Extensions
31+
run: php -m
32+
33+
- name: Get Composer Cache Directory
34+
id: composer-cache
35+
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
36+
37+
- name: Cache Composer dependencies
38+
uses: actions/cache@v3
39+
with:
40+
path: ${{ steps.composer-cache.outputs.dir }}
41+
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
42+
restore-keys: ${{ runner.os }}-composer-
43+
44+
- name: Validate composer.json and composer.lock
45+
run: composer validate --strict
46+
47+
- name: Install dependencies for PHP
48+
run: composer update --no-interaction --no-progress --no-suggest
49+
50+
- name: Run test suite
51+
run: composer test

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Depedency folders
2+
/vendor/
3+
composer.lock
4+
5+
# IDE config folders
6+
.idea/
7+
8+
# Testing
9+
/.phpunit.cache/
10+
.phpunit.result.cache
11+
phpunit.xml

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# MIT License
2+
3+
*Copyright (c) 2023 Pierre-Henry Soria*
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# PHP HTTP Response
2+
3+
**Send easily HTTP status codes to the browser.**
4+
5+
6+
```php
7+
8+
9+
```
10+
11+
12+
13+
## 🧑‍🍳 Who made this...?
14+
15+
[![Pierre-Henry Soria](https://s.gravatar.com/avatar/a210fe61253c43c869d71eaed0e90149?s=200)](https://PH7.me 'Pierre-Henry Soria personal website')
16+
17+
**Pierre-Henry Soria**. A super passionate & enthusiastic software engineer! 🚀 True cheese 🧀 , mushrooms, and chocolate lover! 😋 Reach me at [PH7.me](https://PH7.me) 💫
18+
19+
☕️ Are you enjoying it? **[Offer me a coffee](https://ko-fi.com/phenry)** and boost the software development at the same time! 💪
20+
21+
[![@phenrysay][twitter-image]](https://twitter.com/phenrysay) [![pH-7][github-image]](https://github.com/pH-7)
22+
23+
24+
## ⚖️ License
25+
26+
**PHP HTTP Response** is generously distributed under the _[MIT](https://opensource.org/licenses/MIT)_ 🎉 Enjoy!
27+
28+
29+
<!-- GitHub's Markdown reference links -->
30+
[twitter-image]: https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white
31+
[github-image]: https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white

composer.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "ph-7/php-http-response-header",
3+
"description": "A simple package that sends HTTP header status codes",
4+
"keywords": [
5+
"HTTP code",
6+
"HTTP status code",
7+
"status code",
8+
"PHP status codes",
9+
"clean code",
10+
"constant",
11+
"constants",
12+
"http",
13+
"code",
14+
"magic number",
15+
"all status codes",
16+
"all HTTP status codes"
17+
],
18+
"homepage": "https://pierrehenry.be",
19+
20+
"type": "library",
21+
"require": {
22+
"php": ">=8.0",
23+
"ph-7/just-http-status-codes": "^1.1"
24+
},
25+
"require-dev": {
26+
"phpunit/phpunit": "^10.2"
27+
},
28+
"license": "MIT",
29+
"autoload": {
30+
"psr-4": {
31+
"PH7\\PhpHttpResponseHeader\\": "src/"
32+
}
33+
},
34+
"authors": [
35+
{
36+
"name": "Pierre-Henry Soria",
37+
"email": "hi@PH7.me"
38+
}
39+
]
40+
}

phpunit.xml.dist

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache">
3+
<coverage/>
4+
<testsuites>
5+
<testsuite name="Unit Tests">
6+
<directory>tests</directory>
7+
</testsuite>
8+
</testsuites>
9+
<source>
10+
<include>
11+
<directory suffix=".php">src</directory>
12+
</include>
13+
</source>
14+
</phpunit>

src/Exception.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace PH7\PhpHttpResponseHeader;
4+
5+
use RuntimeException;
6+
7+
class Exception extends RuntimeException
8+
{
9+
10+
}

src/Http.php

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
namespace PH7\PhpHttpResponseHeader;
4+
5+
use PH7\JustHttp\StatusCode;
6+
7+
class Http
8+
{
9+
protected const STATUS_CODE = [
10+
100 => '100 Continue',
11+
101 => '101 Switching Protocols',
12+
102 => '102 Processing',
13+
103 => 'Early Hints',
14+
200 => '200 OK',
15+
201 => '201 Created',
16+
202 => '202 Accepted',
17+
203 => '203 Non-Authoritative Information',
18+
204 => '204 No Content',
19+
205 => '205 Reset Content',
20+
206 => '206 Partial Content',
21+
207 => '207 Multi-Status',
22+
208 => '208 Already Reported',
23+
226 => '226 IM Used',
24+
300 => '300 Multiple Choices',
25+
301 => '301 Moved Permanently',
26+
302 => '302 Found',
27+
303 => '303 See Other',
28+
304 => '304 Not Modified',
29+
305 => '305 Use Proxy',
30+
307 => '307 Temporary Redirect',
31+
308 => '308 Permanent Redirect',
32+
400 => '400 Bad Request',
33+
401 => '401 Unauthorized',
34+
402 => '402 Payment Required',
35+
403 => '403 Forbidden',
36+
404 => '404 Not Found',
37+
405 => '405 Method Not Allowed',
38+
406 => '406 Not Acceptable',
39+
407 => '407 Proxy Authentication Required',
40+
408 => '408 Request Time-out',
41+
409 => '409 Conflict',
42+
410 => '410 Gone',
43+
411 => '411 Length Required',
44+
412 => '412 Precondition Failed',
45+
413 => '413 Request Entity Too Large',
46+
414 => '414 Request-URI Too Large',
47+
415 => '415 Unsupported Media Type',
48+
416 => '416 Requested range not satisfiable',
49+
417 => '417 Expectation Failed',
50+
422 => '422 Unprocessable Entity',
51+
423 => '423 Locked',
52+
424 => '424 Method Failure',
53+
425 => '425 Unordered Collection',
54+
426 => '426 Upgrade Required',
55+
428 => '428 Precondition Required',
56+
429 => '429 Too Many Requests',
57+
431 => '431 Request Header Fields Too Large',
58+
500 => '500 Internal Server Error',
59+
501 => '501 Not Implemented',
60+
502 => '502 Bad Gateway',
61+
503 => '503 Service Unavailable',
62+
504 => '504 Gateway Time-out',
63+
505 => '505 HTTP Version Unsupported',
64+
506 => '506 Variant Also Negotiates',
65+
507 => '507 Insufficient Storage',
66+
508 => '508 Loop Detected',
67+
509 => '509 Bandwidth Limit Exceede',
68+
510 => '510 Not Extended',
69+
511 => '511 Network Authentication Required',
70+
598 => '598 Network read timeout error',
71+
599 => '599 Network connect timeout error'
72+
];
73+
74+
75+
/**
76+
* Give the HTTP status code name (e.g. "204 No Content").
77+
*
78+
* @param int $iStatus The "code" for the HTTP status.
79+
*
80+
* @return string|bool $iStatus Returns the "HTTP status code" if found, FALSE otherwise.
81+
*/
82+
public static function getStatusCode(int $iStatus): string|bool
83+
{
84+
return !empty(static::STATUS_CODE[$iStatus]) ? static::STATUS_CODE[$iStatus] : false;
85+
}
86+
87+
/**
88+
* Retrieve the list with headers that are sent or to be sent.
89+
*/
90+
public static function getHeadersList(): array
91+
{
92+
return headers_list();
93+
}
94+
95+
/**
96+
* Set one or multiple headers.
97+
*
98+
* @param string|array $mHeaders Headers to send.
99+
*
100+
* @throws Exception
101+
*/
102+
public static function setHeaders(string|array $mHeaders): void
103+
{
104+
// Header already sent
105+
if (static::isSent()) {
106+
throw new Exception('Headers were already sent.');
107+
}
108+
109+
// Loop elements and set header
110+
foreach ((array)$mHeaders as $sHeader) {
111+
header((string)$sHeader);
112+
}
113+
}
114+
115+
/**
116+
* Parse headers for a given status code.
117+
*
118+
* @param int $iCode The code to use, possible values are: 200, 301, 302, 304, 307, 400, 401, 403, 404, 410, 500, 501, ...
119+
*
120+
* @throws Exception
121+
*/
122+
public static function setHeadersByCode(int $iCode = StatusCode::OK): void
123+
{
124+
if (!static::getStatusCode($iCode)) {
125+
$iCode = StatusCode::OK;
126+
}
127+
128+
static::setHeaders(static::getProtocol() . ' ' . static::getStatusCode($iCode));
129+
}
130+
131+
/**
132+
* Set a HTTP Content Type.
133+
*
134+
* @param string $sType Example: "text/xml".
135+
*
136+
* @throws Exception
137+
*/
138+
public static function setContentType(string $sType): void
139+
{
140+
static::setHeaders('Content-Type: ' . $sType);
141+
}
142+
143+
/**
144+
* Set the HTTP status code for the maintenance page.
145+
*
146+
* @param int $iMaintenanceTime Time site will be down for (in seconds).
147+
*/
148+
public static function setMaintenanceCode(int $iMaintenanceTime): void
149+
{
150+
header(static::getProtocol() . ' 503 Service Temporarily Unavailable');
151+
header('Retry-After: ' . $iMaintenanceTime);
152+
}
153+
154+
155+
/**
156+
* @return string|null The HTTP server protocol.
157+
*/
158+
public static function getProtocol(): ?string
159+
{
160+
return Server::getVariable(Server::SERVER_PROTOCOL);
161+
}
162+
163+
/**
164+
* Checks if any headers were already sent.
165+
*
166+
* @return bool TRUE if the headers were sent, FALSE if not.
167+
*/
168+
private static function isSent(): bool
169+
{
170+
return headers_sent();
171+
}
172+
}

src/Server.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace PH7\PhpHttpResponseHeader;
4+
5+
final class Server
6+
{
7+
const SERVER_PROTOCOL = 'SERVER_PROTOCOL';
8+
9+
/**
10+
* Retrieve a member of the $_SERVER super global.
11+
*
12+
* @param string|null $sKey If NULL, returns the entire $_SERVER variable.
13+
* @param string|null $sDefVal A default value to use if server key is not found.
14+
*/
15+
public static function getVariable(?string $sKey = null, ?string $sDefVal = null): string|array|null
16+
{
17+
if (null === $sKey) {
18+
return $_SERVER;
19+
}
20+
21+
return !empty($_SERVER[$sKey]) ? htmlspecialchars((string)$_SERVER[$sKey], ENT_QUOTES) : $sDefVal;
22+
}
23+
}

0 commit comments

Comments
 (0)