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
13 changes: 10 additions & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
.gitignore export-ignore
.gitattributes export-ignore
/Examples export-ignore
# Exclude from Composer dist tarballs.
/.github export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php-cs-fixer.dist.php export-ignore
/.phpunit.cache export-ignore
/docs export-ignore
/phpstan.neon.dist export-ignore
/phpunit.xml.dist export-ignore
/tests export-ignore
139 changes: 139 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: CI

on:
push:
branches: [main, "*.x"]
pull_request:
branches: [main, "*.x"]

jobs:
validate:
name: composer validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
coverage: none
tools: composer:v2
- run: composer validate --strict

cs:
name: PHP-CS-Fixer
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
extensions: ctype, mbstring, iconv
coverage: none
tools: composer:v2
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Check coding standards
run: composer cs-check

stan:
name: PHPStan
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
extensions: ctype, mbstring, iconv
coverage: none
tools: composer:v2
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run PHPStan
run: composer stan

tests:
name: PHPUnit (PHP ${{ matrix.php }}, ${{ matrix.deps }})
runs-on: ubuntu-latest
needs: validate
strategy:
fail-fast: false
matrix:
php: ["7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]
deps: ["highest"]
include:
- php: "7.4"
deps: "lowest"
- php: "8.4"
deps: "lowest"
steps:
- uses: actions/checkout@v4

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ctype, mbstring, iconv
coverage: none
tools: composer:v2

- name: Validate composer.json
run: composer validate --no-check-publish

- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"

- name: Cache composer dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: composer-${{ matrix.php }}-${{ matrix.deps }}-${{ hashFiles('**/composer.json') }}
restore-keys: composer-${{ matrix.php }}-${{ matrix.deps }}-

- name: Install highest dependencies
if: matrix.deps == 'highest'
run: composer update --prefer-dist --no-progress --no-interaction

- name: Install lowest dependencies
if: matrix.deps == 'lowest'
run: composer update --prefer-dist --no-progress --no-interaction --prefer-lowest --prefer-stable

- name: Run PHPUnit
run: vendor/bin/phpunit

coverage:
name: Coverage
runs-on: ubuntu-latest
needs: tests
steps:
- uses: actions/checkout@v4

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
extensions: ctype, mbstring, iconv
coverage: pcov
tools: composer:v2

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

- name: Run PHPUnit with coverage
run: vendor/bin/phpunit --coverage-clover=coverage.xml

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-clover
path: coverage.xml
retention-days: 14

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
flags: phpunit
fail_ci_if_error: false
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
/.vscode/
/.vs/
/vendor/
/composer.lock
/composer.lock
/build/
/.phpunit.cache/
/.phpunit.result.cache
/.php-cs-fixer.cache
32 changes: 32 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
->in([__DIR__ . '/src', __DIR__ . '/tests'])
->name('*.php');

return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'@PSR12:risky' => true,
'@PHP74Migration' => true,
'@PHP74Migration:risky' => true,
'array_syntax' => ['syntax' => 'short'],
'declare_strict_types' => true,
'native_function_invocation' => [
'include' => ['@compiler_optimized'],
'scope' => 'namespaced',
'strict' => true,
],
'no_unused_imports' => true,
'ordered_imports' => [
'imports_order' => ['class', 'function', 'const'],
'sort_algorithm' => 'alpha',
],
'single_quote' => true,
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
])
->setFinder($finder)
->setCacheFile(__DIR__ . '/build/php-cs-fixer.cache');
85 changes: 85 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Changelog

All notable changes to `initphp/escaper` are documented here.

The format follows [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).

## [Unreleased]

## [2.0.0]

A reliability- and correctness-focused major release. Several bug fixes
in this release are visible from the outside, so the version bump is
necessary even though the public surface is unchanged. See
[`UPGRADE-2.0.md`](./UPGRADE-2.0.md) for a step-by-step migration guide.

### Added

- Dedicated exception hierarchy under `InitPHP\Escaper\Exception\`:
`EscaperException` (base, extends `\RuntimeException`),
`EncodingNotSupportedException`, `EncodingConversionException`,
`InvalidContextException`, `InvalidUtf8Exception`.
- Full PHPUnit test suite under `tests/` (62 tests, 100 assertions,
~91% line coverage).
- GitHub Actions CI: `composer validate`, PHP-CS-Fixer, PHPStan (max),
PHPUnit on PHP 7.4 – 8.4, coverage upload.
- PHPStan configuration at the `max` level with zero reported issues.
- PHP-CS-Fixer configuration based on `@PSR12` and
`@PHP74Migration` rule sets.
- Developer documentation under `docs/` covering each escape context,
encoding handling, exceptions and security notes.
- `Esc::reset()` helper to clear the memoised `Escaper` cache (used by
tests; useful when the calling code wants to drop cached instances).
- `composer.json` scripts: `test`, `test-coverage`, `stan`, `cs-check`,
`cs-fix`, `ci`.

### Changed

- **`Esc::esc()` recursion** now propagates `$encoding` into recursive
calls. Previously the encoding was dropped on every inner call,
silently defaulting to UTF-8 for nested arrays.
- **`Esc::esc()` instance cache** is now keyed by encoding. The previous
cache compared `$escaper->getEncoding()` (`'utf-8'`) against the raw
`$encoding` argument (often `null`), so the cache rebuilt on every
default call.
- **`Escaper` constructor** raises `EncodingNotSupportedException`
instead of `\Exception`. (Still catchable via `\Exception` /
`\RuntimeException`.)
- **`HTML attribute` matcher** evaluates the C0/C1 control-character
check against the decoded code point, so `U+0080`–`U+009F` are now
correctly replaced with `U+FFFD` when they arrive in multibyte UTF-8
form. Previously only single-byte controls were caught.
- **`composer.json`** now requires `ext-mbstring`. `ext-iconv` remains
optional and is preferred when present (`suggest` entry added).
- **PHPDoc blocks** rewritten across the package to reflect the actual
code behaviour.

### Fixed

- **Silent data loss on encoding-conversion failure.** When `iconv` /
`mb_convert_encoding` returned `false`, `Escaper::convertEncoding()`
previously returned an empty string and let it propagate, masking
real failures. It now raises `EncodingConversionException`.
- **`isUtf8()`** uses explicit `=== 1` comparison against
`preg_match()` instead of relying on PHP's loose type coercion in a
`bool` return.
- **Misleading error message** in `convertEncoding()`: the "MB_String
plugin is required" text appeared even when iconv was tried first.
Replaced with "Either ext-iconv or ext-mbstring is required".
- **Unused callable properties** (`$htmlAttrMatcher`, `$jsMatcher`,
`$cssMatcher`) removed. The matchers are now passed inline to
`preg_replace_callback`.

### Removed

- **`Examples/`** directory removed. The same scenarios are documented
under [`docs/`](./docs) with verified output for each example.

## [1.0]

Initial release.

[Unreleased]: https://github.com/InitPHP/Escaper/compare/2.0.0...HEAD
[2.0.0]: https://github.com/InitPHP/Escaper/compare/1.0...2.0.0
[1.0]: https://github.com/InitPHP/Escaper/releases/tag/1.0
23 changes: 0 additions & 23 deletions Examples/Attr.php

This file was deleted.

28 changes: 0 additions & 28 deletions Examples/Css.php

This file was deleted.

20 changes: 0 additions & 20 deletions Examples/Html.php

This file was deleted.

24 changes: 0 additions & 24 deletions Examples/Js.php

This file was deleted.

Loading
Loading