Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml,json}]
indent_size = 2

[Makefile]
indent_style = tab
30 changes: 30 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Static Analysis

on:
push:
branches: [main, 2.x, 3.x]
pull_request:
branches: [main, 2.x, 3.x]

jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: json, curl, mbstring
coverage: none
tools: composer:v2

- name: Install dependencies
run: composer update --no-interaction --no-progress --prefer-dist

- name: Run PHPStan
run: vendor/bin/phpstan analyse --no-progress --memory-limit=512M
41 changes: 41 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Tests

on:
push:
branches: [main, 2.x, 3.x]
pull_request:
branches: [main, 2.x, 3.x]

jobs:
phpunit:
name: PHPUnit (PHP ${{ matrix.php }} / ${{ matrix.dependency-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
dependency-version: [prefer-stable]
include:
- php: '7.4'
dependency-version: prefer-lowest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: json, curl, mbstring
coverage: none
tools: composer:v2

# Composer's solver picks PHPUnit 9.x and http-factory-tests 1.x on
# PHP < 8.1, and 10.x / 2.x on PHP >= 8.1, based on the wide ranges in
# composer.json. No manual narrowing required.
- name: Install dependencies
run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --prefer-dist

- name: Run PHPUnit
run: vendor/bin/phpunit --testdox
86 changes: 86 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Changelog

All notable changes to **initphp/http** will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.0.0] - Unreleased

### Added

- **PSR-7 v2 support.** `psr/http-message` constraint widened to `^1.0 || ^2.0`.
- **Stateless `ServerRequest::createFromGlobals()`** that accepts optional `$server/$get/$post/$cookies/$files` arrays and never caches its result. Safe under Swoole, RoadRunner, Octane, FrankenPHP.
- **Content-Type-aware body parsing** in `createFromGlobals` (JSON / urlencoded / multipart).
- **nginx + php-fpm header fallback** in `createFromGlobals` for environments without `apache_request_headers()`.
- **`Client::withTimeout()` / `withConnectTimeout()` / `withFollowRedirects()` / `withCurlOptions()`** for production-grade configuration.
- **`Facadable` trait and `FacadableInterface`** β€” canonical names replacing the misspelled `Facadeble[Interface]` (old names kept as `@deprecated` aliases).
- **`docs/` directory** with PSR-7/17/18 guides, emitter walk-throughs, recipes, status-code reference and an upgrade guide.
- **Comprehensive `tests/Unit/` suite** complementing the upstream PSR integration tests.
- **GitHub Actions CI** matrix covering PHP 7.4 – 8.4 (PHPUnit + PHPStan).
- **PHPStan level 5** static analysis with a baseline of intentional ignores.
- Packagist metadata enrichment (description, keywords, homepage, support links).
- Composer scripts: `composer test`, `composer test:coverage`, `composer phpstan`, `composer ci`.
- EditorConfig, CHANGELOG, contributor-friendly docblocks across `src/`.
- `http-interop/http-factory-tests` dev-dep widened to `^1.1 || ^2.0` so the CI matrix can install the v1 line on PHP 7.4 / 8.0 (the v2 line requires PHP 8.1+).

### Changed (breaking)

- **`Request::createFromGlobals()` removed.** Use `ServerRequest::createFromGlobals()`.
- **`Request::_parameters` bag removed.** All of `__get/__set/__isset/all/get/has/merge/sendRequest` are gone. Use `getParsedBody()` / attributes / explicit `(new Client())->sendRequest($request)`.
- **Custom `InitPHP\HTTP\Message\Interfaces\*` interfaces removed.** Type-hint against `Psr\Http\Message\*Interface` directly. The old interfaces forced mutator contracts that conflicted with PSR-7 immutability.
- **`Client::sendRequest()`** no longer special-cases the concrete `Request` class or silently JSON-encodes a `_parameters` bag.
- **`Client::prepareRequest()`** (used by the verb helpers and `fetch()`) no longer accepts `array`, `DOMDocument`, `SimpleXMLElement`, or "any object". Body must be `string | resource | StreamInterface | null`. The `send_request()` helper still encodes arrays/`toArray()` objects as JSON.
- **`Client` default timeout** changed from 0 (no timeout) to 30 s; default connect timeout 10 s. Pass `->withTimeout(0)` to keep the legacy infinite wait.
- **`Response::redirect()`** always sets `Location`; `Refresh` is added on top when a non-zero delay is requested.
- **`Response::json()`** uses `JSON_THROW_ON_ERROR`; unencodable payloads now raise `InvalidArgumentException` instead of silently producing `false`. Content-Type is `application/json; charset=utf-8`.
- **`UploadedFile::__construct()` `$size` is now `?int`**, matching the PSR-7 nullable contract.
- **`UploadedFile::getSize(): ?int`**, matching the PSR-7 contract.
- **`Stream::__toString()` no longer throws** under any circumstance, per PSR-7's hard requirement.
- **`Stream::write()` string backend** now obeys `fwrite()` semantics (overwrite from cursor, advance position). The legacy prepend-at-position-0 behaviour is gone.
- **`Stream::str2resorce()` renamed** to `Stream::stringToResource()` (private). Materialised detach handle now preserves cursor position.
- **`RequestTrait::updateHostFormUri()` renamed** to `updateHostFromUri()`.
- **HTTP version whitelist widened** to accept `2`, `2.0`, `3`, `3.0` (alongside `1.0` and `1.1`).
- **Native return types added for PSR-7 v2 covariance** on seven methods:
`Stream::close(): void`, `Stream::seek(...): void`, `Stream::rewind(): void`,
`MessageTrait::getHeader($name): array`,
`UploadedFile::getStream(): StreamInterface`, `UploadedFile::moveTo(...): void`,
`Uri::__toString(): string`.
Required by PHP 7.4 + PSR-7 v2 (`Declaration must be compatible with ...`
fatal at class load); PHP 8.0+ accepted the untyped signatures silently
but the fix is uniform across all supported PHP versions.
No call-site change is required (the existing `@return` PHPDoc lines
already documented these types), but subclass overrides must match the
new signatures or stay untyped.

### Fixed

- 500 reason phrase corrected from `'Internal ServerRequest Error'` to `'Internal Server Error'`.
- `Stream::isEmpty()` / `isNotEmpty()` return `false` for streams whose size is null (pipes, sockets), instead of mis-classifying them as empty.
- `Emitter` reason-phrase status-line check uses `!== ''` so a literal `'0'` reason is preserved.
- `Emitter` raises `EmitHeaderException` (not `EmitBodyException`) when `headers_sent()` is true.
- `Client` sets `CURLOPT_POSTFIELDS` for body-bearing methods (POST/PUT/PATCH/DELETE) even when the body is empty, so cURL doesn't silently downgrade the request.
- `Client::sendRequest()` wraps the response body in `php://temp` instead of an in-memory PHP string, avoiding OOM on multi-megabyte downloads.
- `UploadedFile::moveTo()` survives partial-write iterations and retries until the chunk is flushed.
- `ServerRequest::normalizeFiles()` recurses into arbitrarily nested file input names (`file[parent][child][…]`).
- `send_request()` (global helper) requires a URL when the first arg is a method string instead of silently sending to `null`.
- `tests/Unit/FixtureServerTrait` exposes the loopback host through a static method instead of a trait constant, so the unit suite loads on PHP 7.4 / 8.0 / 8.1 (trait constants are a PHP 8.2+ feature).
- `static-analysis.yml` workflow now runs PHPStan with `--memory-limit=512M`, matching the `composer phpstan` script β€” the default 128 MiB triggered an OOM under PHP 7.4 during local reproduction.

### Removed (in addition to breaking changes above)

- `Request::__set/__get/__isset/all/get/has/merge/sendRequest/createFromGlobals` and the static singleton property that backed `createFromGlobals`.
- `Client::sendRequest`'s `instanceof Request` branch.
- `Client::prepareRequest`'s `DOMDocument`/`SimpleXMLElement`/`toArray()`/`get_object_vars()` cascade.
- `src/Message/Interfaces/` directory (six custom interfaces).

### Deprecated

- `InitPHP\HTTP\Facade\Interfaces\FacadebleInterface` (use `FacadableInterface`).
- `InitPHP\HTTP\Facade\Traits\Facadeble` (use `Facadable`).

Both will be removed in 4.0.

## [2.x] - prior releases

See Git history for entries prior to this changelog.
Loading
Loading