Skip to content

Commit 49c942c

Browse files
committed
0 parents  commit 49c942c

18 files changed

+1937
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.build/*
2+
.docs/*
3+
.idea/*
4+
vendor/*
5+
composer.lock
6+
*cacert.pem
7+
phpunit.xml

.phan/config.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
/**
3+
* This configuration will be read and overlaid on top of the
4+
* default configuration. Command-line arguments will be applied
5+
* after this file is read.
6+
*/
7+
return [
8+
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`,
9+
// `'7.4'`, `null`.
10+
// If this is set to `null`,
11+
// then Phan assumes the PHP version which is closest to the minor version
12+
// of the php executable used to execute Phan.
13+
//
14+
// Note that the **only** effect of choosing `'5.6'` is to infer
15+
// that functions removed in php 7.0 exist.
16+
// (See `backward_compatibility_checks` for additional options)
17+
'target_php_version' => '7.4',
18+
19+
// A list of directories that should be parsed for class and
20+
// method information. After excluding the directories
21+
// defined in exclude_analysis_directory_list, the remaining
22+
// files will be statically analyzed for errors.
23+
//
24+
// Thus, both first-party and third-party code being used by
25+
// your application should be included in this list.
26+
'directory_list' => [
27+
'src',
28+
'tests',
29+
'vendor',
30+
],
31+
32+
// A regex used to match every file name that you want to
33+
// exclude from parsing. Actual value will exclude every
34+
// "test", "tests", "Test" and "Tests" folders found in
35+
// "vendor/" directory.
36+
'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
37+
38+
// A directory list that defines files that will be excluded
39+
// from static analysis, but whose class and method
40+
// information should be included.
41+
//
42+
// Generally, you'll want to include the directories for
43+
// third-party code (such as "vendor/") in this list.
44+
//
45+
// n.b.: If you'd like to parse but not analyze 3rd
46+
// party code, directories containing that code
47+
// should be added to both the `directory_list`
48+
// and `exclude_analysis_directory_list` arrays.
49+
'exclude_analysis_directory_list' => [
50+
'tests',
51+
'vendor',
52+
],
53+
];

.scrutinizer.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
build:
2+
nodes:
3+
analysis:
4+
tests:
5+
override:
6+
- php-scrutinizer-run
7+
environment:
8+
php: 8.0.0
9+
10+
filter:
11+
excluded_paths:
12+
- examples/*
13+
- tests/*
14+
- vendor/*
15+
- .github/*
16+
- .phan/*

.travis.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
language: php
2+
3+
env:
4+
global:
5+
- PHAN_ALLOW_XDEBUG=0 PHAN_DISABLE_XDEBUG_WARN=1
6+
7+
matrix:
8+
include:
9+
- php: 7.4
10+
- php: 8.0
11+
- php: nightly
12+
allow_failures:
13+
- php: nightly
14+
15+
before_install:
16+
- curl -o tests/cacert.pem https://curl.haxx.se/ca/cacert.pem
17+
- composer install --no-interaction --prefer-source --ignore-platform-reqs
18+
19+
script: vendor/bin/phpunit --configuration phpunit.xml.dist
20+
21+
after_success: bash <(curl -s https://codecov.io/bash)

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) 2021 smiley
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.

composer.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "chillerlan/php-http-message-utils",
3+
"description": "PSR-7/17/18 utils. PHP7.4+",
4+
"license": "MIT",
5+
"type": "library",
6+
"keywords": [
7+
"http", "message", "psr-7", "psr-17", "psr-18"
8+
],
9+
"minimum-stability": "stable",
10+
"authors": [
11+
{
12+
"name": "smiley",
13+
"email": "smiley@chillerlan.net",
14+
"homepage": "https://github.com/codemasher"
15+
}
16+
],
17+
"support": {
18+
"issues": "https://github.com/chillerlan/php-http-message-utils/issues",
19+
"source": "https://github.com/chillerlan/php-http-message-utils"
20+
},
21+
"require": {
22+
"php": "^7.4 || ^8.0",
23+
"psr/http-factory":"^1.0",
24+
"ext-json": "*",
25+
"ext-simplexml": "*",
26+
"ext-zlib": "*"
27+
},
28+
"require-dev": {
29+
"guzzlehttp/psr7": "2.0.0-beta1",
30+
"phan/phan": "^4.0",
31+
"phpunit/phpunit": "^9.5"
32+
},
33+
"autoload": {
34+
"files": [
35+
"src/includes.php"
36+
],
37+
"psr-4": {
38+
"chillerlan\\HTTP\\Utils\\": "src/"
39+
}
40+
},
41+
"autoload-dev": {
42+
"psr-4": {
43+
"chillerlan\\HTTPTest\\Utils\\": "tests/"
44+
}
45+
}
46+
}

phpunit.xml.dist

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
cacheResultFile=".build/phpunit.result.cache"
6+
colors="true"
7+
verbose="true"
8+
>
9+
<coverage>
10+
<include>
11+
<directory suffix=".php">./src</directory>
12+
</include>
13+
<report>
14+
<clover outputFile=".build/coverage/clover.xml"/>
15+
<xml outputDirectory=".build/coverage/coverage-xml"/>
16+
</report>
17+
</coverage>
18+
<testsuites>
19+
<testsuite name="php-http-message-utils test suite">
20+
<directory>./tests</directory>
21+
</testsuite>
22+
</testsuites>
23+
<logging>
24+
<junit outputFile=".build/logs/junit.xml"/>
25+
</logging>
26+
<php>
27+
<const name="REQUEST_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
28+
<const name="RESPONSE_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
29+
<const name="SERVER_REQUEST_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
30+
<const name="STREAM_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
31+
<const name="UPLOADED_FILE_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
32+
<const name="URI_FACTORY" value="GuzzleHttp\Psr7\HttpFactory"/>
33+
</php>
34+
</phpunit>

src/Header.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
/**
3+
* Class Header
4+
*
5+
* @created 28.03.2021
6+
* @author smiley <smiley@chillerlan.net>
7+
* @copyright 2021 smiley
8+
* @license MIT
9+
*/
10+
11+
namespace chillerlan\HTTP\Utils;
12+
13+
use function array_keys, array_map, array_values, count, explode, implode,
14+
is_array, is_numeric, is_string, strtolower, trim, ucfirst;
15+
16+
/**
17+
*
18+
*/
19+
class Header{
20+
21+
/**
22+
* Normalizes an array of header lines to format ["Name" => "Value (, Value2, Value3, ...)", ...]
23+
* An exception is being made for Set-Cookie, which holds an array of values for each cookie.
24+
* For multiple cookies with the same name, only the last value will be kept.
25+
*
26+
* @param array $headers
27+
*
28+
* @return array
29+
*/
30+
public static function normalize(array $headers):array{
31+
$normalized = [];
32+
33+
foreach($headers as $key => $val){
34+
35+
// the key is numeric, so $val is either a string or an array
36+
if(is_numeric($key)){
37+
38+
// "key: val"
39+
if(is_string($val)){
40+
$header = explode(':', $val, 2);
41+
42+
if(count($header) !== 2){
43+
continue;
44+
}
45+
46+
$key = $header[0];
47+
$val = $header[1];
48+
}
49+
// [$key, $val], ["key" => $key, "val" => $val]
50+
elseif(is_array($val)){
51+
$key = array_keys($val)[0];
52+
$val = array_values($val)[0];
53+
}
54+
else{
55+
continue;
56+
}
57+
}
58+
// the key is named, so we assume $val holds the header values only, either as string or array
59+
else{
60+
if(is_array($val)){
61+
$val = implode(', ', array_values($val));
62+
}
63+
}
64+
65+
$key = implode('-', array_map(fn(string $v):string => ucfirst(strtolower(trim($v))), explode('-', $key)));
66+
$val = trim($val);
67+
68+
// skip if the header already exists but the current value is empty
69+
if(isset($normalized[$key]) && empty($val)){
70+
continue;
71+
}
72+
73+
// cookie headers may appear multiple times
74+
// https://tools.ietf.org/html/rfc6265#section-4.1.2
75+
if($key === 'Set-Cookie'){
76+
// i'll just collect the last value here and leave parsing up to you :P
77+
$normalized[$key][strtolower(explode('=', $val, 2)[0])] = $val;
78+
}
79+
// combine header fields with the same name
80+
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
81+
else{
82+
isset($normalized[$key]) && !empty($normalized[$key])
83+
? $normalized[$key] .= ', '.$val
84+
: $normalized[$key] = $val;
85+
}
86+
}
87+
88+
return $normalized;
89+
}
90+
91+
}

0 commit comments

Comments
 (0)