From 00d33fbdc224e3e1a1e85d12399ee54b7d7a297b Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sun, 23 Aug 2026 20:51:12 +0200 Subject: [PATCH] Adding documentation --- docs/index.md | 8 +- docs/overview.md | 167 +++++++++++++++++++++++++++++++++++++++- docs/v2-to-v3-update.md | 37 ++++++++- docs/v3-to-v4-update.md | 62 ++++++++++++++- 4 files changed, 263 insertions(+), 11 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8ca42a4a..805bd724 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,5 @@ -* [Overview](overview.md) -* [Updating from v2 to v3](v2-to-v3-update.md) -* [Updating from v3 to v4](v3-to-v4-update.md) +* Guide + * [Overview](overview.md) +* Upgrading + * [Updating from v2 to v3](v2-to-v3-update.md) + * [Updating from v3 to v4](v3-to-v4-update.md) diff --git a/docs/overview.md b/docs/overview.md index bd56c040..619f37ec 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -1,3 +1,166 @@ -# Input package +# Overview -TODO +The Input package is the request-side counterpart to the application's response: it wraps the +superglobals and returns filtered values through a single API. + +```bash +composer require joomla/input +``` + +## What is in the package + +| Class | Source | Purpose | +|---|---|---| +| `Joomla\Input\Input` | `$_REQUEST` | The base class; also the type of `$input->get`, `$input->post`, … | +| `Joomla\Input\Cookie` | `$_COOKIE` | Adds `set()` writing a real cookie | +| `Joomla\Input\Files` | `$_FILES` | Pivots the upload array into per-file entries | +| `Joomla\Input\Json` | `php://input` | Decodes a JSON request body | + +## Reading values + +Every read goes through a filter. The default is `cmd`: + +```php +use Joomla\Input\Input; + +$input = new Input(); + +$input->get('name'); // filtered with 'cmd' +$input->get('name', 'anonymous'); // with a default +$input->get('body', '', 'raw'); // unfiltered +``` + +The `get()` shorthands are resolved through `__call()`, so the type name is the filter name: + +| Call | Filter | +|---|---| +| `getInt()`, `getUint()`, `getFloat()` | numeric | +| `getBool()` | boolean | +| `getWord()`, `getAlnum()`, `getCmd()` | restricted character sets | +| `getBase64()` | base64 alphabet | +| `getString()`, `getHtml()` | sanitised text | +| `getPath()` | file path | +| `getUsername()` | control characters and `<>"'%&` removed | +| `getRaw()` | nothing | + +Anything else — `getFoobar()` — silently falls back to string filtering rather than raising an +error, so a typo in the method name returns a value instead of failing. + +## The sub-inputs + +Magic properties give access to the other superglobals, each wrapped in its own `Input`: + +```php +$input->get->getInt('page'); // $_GET +$input->post->getString('title'); // $_POST +$input->server->getString('REQUEST_METHOD'); +$input->env->getString('PATH'); +$input->cookie->getString('lang'); // Joomla\Input\Cookie +$input->files->get('upload'); // Joomla\Input\Files +$input->json->getString('name'); // Joomla\Input\Json +``` + +Note that `isset($input->post)` returns `false` — the class implements `__get()` but not +`__isset()`. + +## Writing values + +```php +$input->set('view', 'articles'); // overwrite +$input->def('layout', 'default'); // only if not already present +$input->exists('view'); // true +count($input); // Countable +``` + +These change the `Input` object only; the superglobals are untouched. + +## Reading several values at once + +```php +$data = $input->getArray([ + 'id' => 'uint', + 'title' => 'string', + 'tags' => ['name' => 'string'], // nested +]); +``` + +Called without arguments, `getArray()` returns everything — but be aware that it then uses each +*value* as the filter name for its own key, which is not what the docblock describes. Pass an +explicit map whenever the result matters. + +`getArray()` also assumes nested keys exist: `getArray(['a' => ['b' => 'int']], $source)` raises a +warning and a `TypeError` if `$source['a']` is missing. Supply defaults or check first. + +## Request method + +```php +$input->getMethod(); // 'GET', 'POST', … +$input->getInputForRequestMethod(); // the $_GET or $_POST input +``` + +For `PUT`, `PATCH` and `DELETE` there is no superglobal, so `getInputForRequestMethod()` returns +the `$_REQUEST`-backed instance — which means the request body of those methods is **not read at +all**. Use `Joomla\Input\Json` or parse `php://input` yourself for them. + +## Cookies + +```php +use Joomla\Input\Cookie; + +$cookies = new Cookie(); + +$cookies->set('lang', 'de', [ + 'expires' => time() + 86400, + 'path' => '/', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'Lax', +]); +``` + +The options array is handed straight to `setcookie()`. Nothing is added, so **omitting `secure`, +`httponly` or `samesite` means the cookie is written without them**. Always pass them explicitly. + +The return value of `setcookie()` is discarded, so a failed call — headers already sent, invalid +name — still updates the object's own data and reports nothing. + +## Uploaded files + +```php +$file = $input->files->get('avatar'); + +// ['name' => …, 'type' => …, 'tmp_name' => …, 'error' => …, 'size' => …] +``` + +Multi-file inputs are pivoted, so `files->get('attachments')` returns a list of such arrays rather +than PHP's column-wise structure. + +> **The filter argument is ignored.** `Files::get()` accepts a third `$filter` parameter and never +> applies it. The returned `name` and `type` are the raw, client-supplied values. Never build a +> path from `name` without sanitising it yourself, and never trust `type` — validate the real MIME +> type with `finfo` instead. + +`Files::set()` is deliberately a no-op, but the inherited `def()` still writes, so file entries can +be injected into the object. + +## JSON bodies + +```php +use Joomla\Input\Json; + +$json = new Json(); + +$json->getString('title'); +$json->getRaw(); // the undecoded body +``` + +The body is read and decoded on construction regardless of the request's `Content-Type`. A body +that is not valid JSON yields an empty input rather than an error, so an API cannot distinguish +"malformed JSON" from "no fields sent" — check `getRaw()` if that matters. + +## Not part of this package + +* No PSR-7. There is no bridge from or to `ServerRequestInterface`. +* No `UploadedFileInterface`, no upload validation helpers (`UPLOAD_ERR_*`, size, MIME). +* No trusted-proxy handling for `X-Forwarded-For` or `X-Forwarded-Proto`. +* No `remove()`, no `ArrayAccess`, no `IteratorAggregate`. diff --git a/docs/v2-to-v3-update.md b/docs/v2-to-v3-update.md index bdb1f3e8..f449d7a6 100644 --- a/docs/v2-to-v3-update.md +++ b/docs/v2-to-v3-update.md @@ -1,5 +1,36 @@ -## Updating from v2 to v3 +# Updating from v2 to v3 -### Minimum supported PHP version raised +Release 3.0.0 raises the PHP requirement and reformats the codebase. **No public or protected +method signature changed**, so code written against 2.x keeps working on PHP 8.1. -All Framework packages now require PHP 8.1 or newer. +## At a glance + +| | v2 (2.0.4) | v3 (3.0.0) | +|---|---|---| +| PHP | `^7.2.5` | `^8.1.0` | +| Public API | — | unchanged | +| Coding style | Joomla Coding Standard | PSR-12 | + +## Minimum supported PHP version raised + +All Framework packages now require **PHP 8.1** or newer. + +## No API changes + +Every method on `Input`, `Cookie`, `Files` and `Json` has the same signature in 3.0.0 as in 2.0.0. +The deprecated `Cookie::set()` signature described in the +[v3 to v4 guide](v3-to-v4-update.md) is still present and still emits a deprecation notice. + +## Codebase converted to PSR-12 + +The package was reformatted from the Joomla Coding Standard to PSR-12. This touches nearly every +line and changes no behaviour, so a `git diff` between 2.x and 3.x is almost entirely noise. Use +`git diff -w` when looking for real changes. + +## Dependency changes + +| Package | v2 (2.0.4) | v3 (3.0.0) | +|---|---|---| +| `php` | `^7.2.5` | `^8.1.0` | +| `joomla/filter` | `^1.0 \| ^2.0` | `^3.0` | +| `symfony/deprecation-contracts` | `^2.1` | `^2 \| ^3` | diff --git a/docs/v3-to-v4-update.md b/docs/v3-to-v4-update.md index 847bf62f..619cc2df 100644 --- a/docs/v3-to-v4-update.md +++ b/docs/v3-to-v4-update.md @@ -1,5 +1,61 @@ -## Updating from v3 to v4 +# Updating from v3 to v4 -### Minimum supported PHP version raised +Release 4.0.0 raises the PHP requirement and removes the legacy `Cookie::set()` signature that had +been deprecated since 1.4.0. -All Framework packages now require PHP 8.3 or newer. +## At a glance + +| | v3 (3.0.2) | v4 (4.0.0) | +|---|---|---| +| PHP | `^8.1.0` | `^8.3.0` | +| `Cookie::set()` positional signature | deprecated, works | **removed** | +| `joomla/filter` | `^3.0` | `^4.0` | + +## Minimum supported PHP version raised + +All Framework packages now require **PHP 8.3** or newer. + +## The legacy `Cookie::set()` signature was removed + +Before 1.4.0 the method took the cookie attributes as positional arguments. 1.4.0 added the +options-array form and kept a compatibility layer that inspected `func_get_args()`; 4.0.0 removes +that layer. + +```php +// Removed in 4.0.0 - the positional form +$cookie->set('lang', 'de', time() + 86400, '/', 'example.com', true, true); + +// The options form, available since 1.4.0 +$cookie->set('lang', 'de', [ + 'expires' => time() + 86400, + 'path' => '/', + 'domain' => 'example.com', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'Lax', +]); +``` + +Passing anything other than an array as the third argument now reaches `setcookie()` unchanged and +raises a `TypeError` there rather than being translated. + +The options form supports `samesite`, which the positional form never could — worth setting while +you are changing these call sites anyway. + +To find them: + +```bash +grep -rn -- '->set(' src/ | grep -i cookie +``` + +## No other API changes + +Apart from the removed compatibility layer, `Input`, `Cookie`, `Files` and `Json` are unchanged. + +## Dependency changes + +| Package | v3 (3.0.2) | v4 (4.0.0) | +|---|---|---| +| `php` | `^8.1.0` | `^8.3.0` | +| `joomla/filter` | `^3.0` | `^4.0` | +| `symfony/deprecation-contracts` | `^2 \| ^3` | unchanged |