From d763532697318b5ba31f9e06be63e4ea3020cd3a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 10:23:17 +0100 Subject: [PATCH 01/15] .gitignore: use top-level file instead of per-directory --- .gitignore | 3 +++ bin/.gitignore | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .gitignore delete mode 100644 bin/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..16e2a21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Ignore temporary files. +/bin/http.log +/bin/http.pid diff --git a/bin/.gitignore b/bin/.gitignore deleted file mode 100644 index 216b80e..0000000 --- a/bin/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -http.log -http.pid \ No newline at end of file From 8151a51796161e369cc9465c43ba695207da76b6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 10:35:07 +0100 Subject: [PATCH 02/15] Composer: normalize the file Command used: ```bash composer-normalize --indent-size=1 --indent-style=tab --profile --no-plugins --no-scripts ``` --- composer.json | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 7e4aa01..c342129 100644 --- a/composer.json +++ b/composer.json @@ -1,18 +1,25 @@ { "name": "requests/test-server", "description": "Test server to respond to Requests' tests!", - "homepage": "http://github.com/RequestsPHP/test-server", "license": "ISC", - "keywords": ["http", "test"], + "type": "library", + "keywords": [ + "http", + "test" + ], "authors": [ { "name": "Ryan McCue", "homepage": "http://ryanmccue.info" } ], + "homepage": "http://github.com/RequestsPHP/test-server", "require": { "php": ">=5.6" }, - "type": "library", - "bin": [ "bin/start.sh", "bin/stop.sh", "bin/serve.php" ] + "bin": [ + "bin/serve.php", + "bin/start.sh", + "bin/stop.sh" + ] } From 04767168b96c443bfcd274e634ce452e944f337e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 10:38:07 +0100 Subject: [PATCH 03/15] Composer: update maintainers list --- composer.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/composer.json b/composer.json index c342129..afd2adc 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,18 @@ { "name": "Ryan McCue", "homepage": "http://ryanmccue.info" + }, + { + "name": "Alain Schlesser", + "homepage": "https://github.com/schlessera" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl" + }, + { + "name": "Contributors", + "homepage": "https://github.com/RequestsPHP/test-server/graphs/contributors" } ], "homepage": "http://github.com/RequestsPHP/test-server", From 25e6d8026f0857b882d9a3e6310dcde317284e20 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 10:49:36 +0100 Subject: [PATCH 04/15] CI: lint the PHP files against all supported versions This commit: * Adds a new `dev` dependency on PHP Parallel Lint for linting PHP files. * Adds a Composer script documenting how this should be run. * Adds a GitHub Actions workflow to run PHP linting against all supported PHP versions. * Ensures that no `composer.lock` file will be created by default. * Ensures that a potentially pre-existing `composer.lock` file and the `vendor` directory do not get committed to the repo. --- .github/workflows/lint.yml | 50 ++++++++++++++++++++++++++++++++++++++ .gitignore | 4 +++ composer.json | 17 ++++++++++++- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..0dda897 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: Lint + +on: + # Run on all pushes and on all pull requests. + push: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: #---------------------------------------------------------------------- + runs-on: ubuntu-latest + + strategy: + matrix: + php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + + name: "Lint: PHP ${{ matrix.php }}" + continue-on-error: ${{ matrix.php == '8.5' }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: error_reporting=-1, display_errors=On, log_errors_max_len=0 + coverage: none + tools: cs2pr + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer + - name: Install Composer dependencies + uses: "ramsey/composer-install@v3" + with: + # For PHP "nightly", we need to install with ignore platform reqs. + composer-options: ${{ matrix.php == '8.5' && '--ignore-platform-req=php+' || '' }} + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") + + - name: Lint against parse errors + run: composer lint -- --checkstyle | cs2pr diff --git a/.gitignore b/.gitignore index 16e2a21..9ef0665 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ # Ignore temporary files. /bin/http.log /bin/http.pid + +# Ignore composer related files +/composer.lock +/vendor diff --git a/composer.json b/composer.json index afd2adc..8a2c6b9 100644 --- a/composer.json +++ b/composer.json @@ -29,9 +29,24 @@ "require": { "php": ">=5.6" }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4" + }, "bin": [ "bin/serve.php", "bin/start.sh", "bin/stop.sh" - ] + ], + "config": { + "lock": false + }, + "scripts": { + "lint": [ + "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . --show-deprecated -e php --exclude vendor --exclude .git" + ] + }, + "scripts-descriptions": { + "lint": "Lint PHP files to find parse errors." + } } From 5e124ee7483731db2325e20525ae8c82abc74191 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 10:53:07 +0100 Subject: [PATCH 05/15] Add dependabot configuration As there is now a GH Actions workflow, it should be kept up to date. --- .github/dependabot.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..564a87c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# Dependabot configuration. +# +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + commit-message: + prefix: "GH Actions:" + labels: + - "testing/chores/QA" From 56506c3c08b1b04d88d2e260f01bb9a789e46d79 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:53:42 +0100 Subject: [PATCH 06/15] CI: run QA on GHA workflows --- .github/workflows/cs.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/cs.yml diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml new file mode 100644 index 0000000..6c8d448 --- /dev/null +++ b/.github/workflows/cs.yml @@ -0,0 +1,35 @@ +name: CS + +on: + # Run on all pushes and on all pull requests. + push: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + actionlint: #---------------------------------------------------------------------- + name: 'Check GHA workflows' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Add problem matcher + if: ${{ github.event_name == 'pull_request' }} + shell: bash + run: | + curl -o actionlint-matcher.json https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json + echo "::add-matcher::actionlint-matcher.json" + + - name: Check workflow files + uses: docker://rhysd/actionlint:latest + with: + args: -color From 456c8452a3583c6fb42c1f7fa1825ee63873f7db Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:56:23 +0100 Subject: [PATCH 07/15] CI: run PHPCS over the code This commit: * Adds new `dev` dependencies on PHPCompatibility and PHP_CodeSniffer. * Adds a PHPCS configuration file to use PSR-12 with some tweaks (tab-indent instead of spaces + a few extra rules). * Adds Composer scripts documenting how this should be run. * Adds a GitHub Actions job to run PHPCS on all commits. * Ensures that local overrides of the PHPCS config do not get committed to the repo. --- .github/workflows/cs.yml | 32 ++++++++++++++++++ .gitignore | 4 +++ .phpcs.xml.dist | 72 ++++++++++++++++++++++++++++++++++++++++ composer.json | 15 ++++++++- 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 .phpcs.xml.dist diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml index 6c8d448..1af918d 100644 --- a/.github/workflows/cs.yml +++ b/.github/workflows/cs.yml @@ -33,3 +33,35 @@ jobs: uses: docker://rhysd/actionlint:latest with: args: -color + + phpcs: #---------------------------------------------------------------------- + name: 'PHPCS' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 'latest' + coverage: none + tools: cs2pr + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer + - name: Install Composer dependencies + uses: "ramsey/composer-install@v3" + with: + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") + + # Check the code-style consistency of the PHP files. + - name: Check PHP code style + id: phpcs + run: composer checkcs -- --report-full --report-checkstyle=./phpcs-report.xml + + - name: Show PHPCS results in PR + if: ${{ always() && steps.phpcs.outcome == 'failure' }} + run: cs2pr ./phpcs-report.xml diff --git a/.gitignore b/.gitignore index 9ef0665..a99da57 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ # Ignore composer related files /composer.lock /vendor + +# Ignore local overrides of the PHPCS config file. +.phpcs.xml +phpcs.xml diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 0000000..ed4f5cf --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,72 @@ + + + + Requests Test Server rules for PHP_CodeSniffer + + + + + . + + + */vendor/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/composer.json b/composer.json index 8a2c6b9..791bf66 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,9 @@ }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.4" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpcompatibility/php-compatibility": "dev-develop", + "squizlabs/php_codesniffer": "^3.11" }, "bin": [ "bin/serve.php", @@ -39,14 +41,25 @@ "bin/stop.sh" ], "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + }, "lock": false }, "scripts": { + "checkcs": [ + "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" + ], + "fixcs": [ + "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" + ], "lint": [ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . --show-deprecated -e php --exclude vendor --exclude .git" ] }, "scripts-descriptions": { + "checkcs": "Check the entire codebase for code-style issues.", + "fixcs": "Fix all auto-fixable code-style issues in the entire codebase.", "lint": "Lint PHP files to find parse errors." } } From b6327e7634869325793cc48209c37705bacb196b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2025 12:37:27 +0100 Subject: [PATCH 08/15] CS: consistent whitespace use --- bin/serve.php | 27 ++++++++++++--------------- lib/routes.php | 11 ++++++----- lib/utils.php | 14 +++++++++----- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/bin/serve.php b/bin/serve.php index 071148c..39f4995 100644 --- a/bin/serve.php +++ b/bin/serve.php @@ -1,18 +1,18 @@ $value) { if ($name === 'CONTENT_TYPE') { @@ -66,7 +64,7 @@ 'url' => $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 'headers' => $headers, 'origin' => $_SERVER['REMOTE_ADDR'], - 'args' => empty($_SERVER['QUERY_STRING']) ? new stdClass : Requests\TestServer\parse_params_rfc( $_SERVER['QUERY_STRING'] ), + 'args' => empty($_SERVER['QUERY_STRING']) ? new stdClass : Requests\TestServer\parse_params_rfc($_SERVER['QUERY_STRING']), ]; $routes = Requests\TestServer\get_routes(); @@ -95,10 +93,9 @@ while (is_callable($data)) { $data = call_user_func($data, $matches); } -} -catch (Exception $e) { +} catch (Exception $e) { http_response_code($e->getCode()); - $data = [ 'message' => $e->getMessage() ]; + $data = ['message' => $e->getMessage()]; } -echo json_encode($data, JSON_PRETTY_PRINT); \ No newline at end of file +echo json_encode($data, JSON_PRETTY_PRINT); diff --git a/lib/routes.php b/lib/routes.php index 0c57d3c..8d7e6ef 100644 --- a/lib/routes.php +++ b/lib/routes.php @@ -4,7 +4,8 @@ use Exception; -function get_routes() { +function get_routes() +{ global $request_data, $base_url; $routes = []; @@ -114,7 +115,7 @@ function get_routes() { if ($args['user'] !== $supplied['user'] || $args['password'] !== $supplied['password']) { http_response_code(401); - header( 'WWW-Authenticate: Basic realm="Fake Realm"' ); + header('WWW-Authenticate: Basic realm="Fake Realm"'); return; } @@ -192,12 +193,12 @@ function get_routes() { $generate_stream = function () use ($num, $response) { foreach (range(0, $num - 1) as $n) { $response['id'] = $n; - yield json_encode( $response, JSON_PRETTY_PRINT ) . "\n"; + yield json_encode($response, JSON_PRETTY_PRINT) . "\n"; } }; header('Transfer-Encoding: chunked'); - foreach ( $generate_stream() as $response ) { + foreach ($generate_stream() as $response) { printf("%x\r\n%s\r\n", strlen($response), $response); flush(); } @@ -237,7 +238,7 @@ function get_routes() { echo '
    '; foreach ($routes as $url => $_) { - echo '
  • ' . htmlspecialchars( $url ) . '
  • '; + echo '
  • ' . htmlspecialchars($url) . '
  • '; } echo '
'; exit; diff --git a/lib/utils.php b/lib/utils.php index 96544a2..489b80f 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -2,8 +2,10 @@ namespace Requests\TestServer; -class Response { - public static function redirect ($path, $code = 302, $relative = false) { +class Response +{ + public static function redirect($path, $code = 302, $relative = false) + { global $base_url; $url = $path; if (!$relative) { @@ -13,7 +15,8 @@ public static function redirect ($path, $code = 302, $relative = false) { header('Location: ' . $url, true, $code); } - public static function generate_post_data() { + public static function generate_post_data() + { global $request_data; $data = $request_data; $data['data'] = file_get_contents('php://input'); @@ -32,7 +35,8 @@ public static function generate_post_data() { } } -function parse_params_rfc($input) { +function parse_params_rfc($input) +{ if (!isset($input) || !$input) return array(); $pairs = explode('&', $input); @@ -45,4 +49,4 @@ function parse_params_rfc($input) { $parsed[$parameter] = $value; } return $parsed; -} \ No newline at end of file +} From 38b24db7d5280949d468202068aad08e84bfb1cf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:20:26 +0100 Subject: [PATCH 09/15] CS/QA: use short arrays --- bin/serve.php | 2 +- lib/utils.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/serve.php b/bin/serve.php index 39f4995..e98962b 100644 --- a/bin/serve.php +++ b/bin/serve.php @@ -27,7 +27,7 @@ } elseif (function_exists('getallheaders')) { $headers = getallheaders(); } else { - $headers = array(); + $headers = []; foreach ($_SERVER as $name => $value) { if ($name === 'CONTENT_TYPE') { if ($value !== '') { diff --git a/lib/utils.php b/lib/utils.php index 489b80f..5bef8eb 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -37,11 +37,11 @@ public static function generate_post_data() function parse_params_rfc($input) { - if (!isset($input) || !$input) return array(); + if (!isset($input) || !$input) return []; $pairs = explode('&', $input); - $parsed = array(); + $parsed = []; foreach ($pairs as $pair) { $split = explode('=', $pair, 2); $parameter = urldecode($split[0]); From 02d5134f4d5ac32854322967c46864239065e4ee Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:21:51 +0100 Subject: [PATCH 10/15] CS/QA: always use braces for control structures --- bin/serve.php | 3 ++- lib/utils.php | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/serve.php b/bin/serve.php index e98962b..4045d74 100644 --- a/bin/serve.php +++ b/bin/serve.php @@ -79,8 +79,9 @@ foreach ($routes as $route => $callback) { $route = preg_replace('#<(\w+)>#i', '(?P<\1>\w+)', $route); $match = preg_match('#^' . $route . '$#i', $here, $matches); - if (empty($match)) + if (empty($match)) { continue; + } $data = $callback; break; diff --git a/lib/utils.php b/lib/utils.php index 5bef8eb..7c10dbb 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -22,8 +22,9 @@ public static function generate_post_data() $data['data'] = file_get_contents('php://input'); $data['form'] = ''; - if (strpos($data['data'], '&') !== false) + if (strpos($data['data'], '&') !== false) { $data['form'] = parse_params_rfc($data['data']); + } $data['json'] = json_decode($data['data']); @@ -37,7 +38,9 @@ public static function generate_post_data() function parse_params_rfc($input) { - if (!isset($input) || !$input) return []; + if (!isset($input) || !$input) { + return []; + } $pairs = explode('&', $input); From e52c576042d55e103d1191720928bf8168e25239 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2025 01:24:37 +0100 Subject: [PATCH 11/15] Response: rename method to CamelCase --- lib/routes.php | 14 +++++++------- lib/utils.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/routes.php b/lib/routes.php index 8d7e6ef..50af472 100644 --- a/lib/routes.php +++ b/lib/routes.php @@ -25,35 +25,35 @@ function get_routes() throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/put'] = function () { if ($_SERVER['REQUEST_METHOD'] !== 'PUT') { throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/patch'] = function () { if ($_SERVER['REQUEST_METHOD'] !== 'PATCH') { throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/delete'] = function () { if ($_SERVER['REQUEST_METHOD'] !== 'DELETE') { throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/options'] = function () { if ($_SERVER['REQUEST_METHOD'] !== 'OPTIONS') { throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/trace'] = function () use ($request_data) { if ($_SERVER['REQUEST_METHOD'] !== 'TRACE') { @@ -67,14 +67,14 @@ function get_routes() throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; $routes['/lock'] = function () { if ($_SERVER['REQUEST_METHOD'] !== 'LOCK') { throw new Exception('Method not allowed', 405); } - return Response::generate_post_data(); + return Response::generatePostData(); }; // Cookies! diff --git a/lib/utils.php b/lib/utils.php index 7c10dbb..1d89585 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -15,7 +15,7 @@ public static function redirect($path, $code = 302, $relative = false) header('Location: ' . $url, true, $code); } - public static function generate_post_data() + public static function generatePostData() { global $request_data; $data = $request_data; From 11ee0aca1c78a976efa32b58d7584b764b10470b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2025 00:59:00 +0100 Subject: [PATCH 12/15] CS/QA: miscellaneous other fixes --- bin/serve.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/serve.php b/bin/serve.php index 4045d74..86a7e6a 100644 --- a/bin/serve.php +++ b/bin/serve.php @@ -64,7 +64,9 @@ 'url' => $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 'headers' => $headers, 'origin' => $_SERVER['REMOTE_ADDR'], - 'args' => empty($_SERVER['QUERY_STRING']) ? new stdClass : Requests\TestServer\parse_params_rfc($_SERVER['QUERY_STRING']), + 'args' => empty($_SERVER['QUERY_STRING']) + ? new stdClass() + : Requests\TestServer\parse_params_rfc($_SERVER['QUERY_STRING']), ]; $routes = Requests\TestServer\get_routes(); From 542327349a87ebc535b3f4c973a88d97307e0631 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:39:31 +0100 Subject: [PATCH 13/15] PHP-cross version: ensure same output independently of PHP version --- lib/routes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes.php b/lib/routes.php index 50af472..b20c8a4 100644 --- a/lib/routes.php +++ b/lib/routes.php @@ -238,7 +238,7 @@ function get_routes() echo '
    '; foreach ($routes as $url => $_) { - echo '
  • ' . htmlspecialchars($url) . '
  • '; + echo '
  • ' . htmlspecialchars($url, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401) . '
  • '; } echo '
'; exit; From f36f3f4f866b296c6af067f09d1d6ce45abf26e4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:49:15 +0100 Subject: [PATCH 14/15] CS/QA: use static closures (not enforced) --- lib/routes.php | 48 ++++++++++++++++++++++++------------------------ lib/utils.php | 9 ++++++--- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/routes.php b/lib/routes.php index b20c8a4..02bf549 100644 --- a/lib/routes.php +++ b/lib/routes.php @@ -10,7 +10,7 @@ function get_routes() $routes = []; // Request data! - $routes['/get'] = function () use ($request_data) { + $routes['/get'] = static function () use ($request_data) { if ($_SERVER['REQUEST_METHOD'] === 'HEAD') { exit; } @@ -20,56 +20,56 @@ function get_routes() } return $request_data; }; - $routes['/post'] = function () { + $routes['/post'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/put'] = function () { + $routes['/put'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'PUT') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/patch'] = function () { + $routes['/patch'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'PATCH') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/delete'] = function () { + $routes['/delete'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'DELETE') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/options'] = function () { + $routes['/options'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'OPTIONS') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/trace'] = function () use ($request_data) { + $routes['/trace'] = static function () use ($request_data) { if ($_SERVER['REQUEST_METHOD'] !== 'TRACE') { throw new Exception('Method not allowed', 405); } return $request_data; }; - $routes['/purge'] = function () { + $routes['/purge'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'PURGE') { throw new Exception('Method not allowed', 405); } return Response::generatePostData(); }; - $routes['/lock'] = function () { + $routes['/lock'] = static function () { if ($_SERVER['REQUEST_METHOD'] !== 'LOCK') { throw new Exception('Method not allowed', 405); } @@ -78,12 +78,12 @@ function get_routes() }; // Cookies! - $routes['/cookies'] = function () { + $routes['/cookies'] = static function () { return [ 'cookies' => $_COOKIE, ]; }; - $routes['/cookies/set'] = function () { + $routes['/cookies/set'] = static function () { foreach ($_GET as $key => $value) { setcookie($key, $value, 0, '/'); } @@ -91,14 +91,14 @@ function get_routes() Response::redirect('/cookies'); exit; }; - $routes['/cookies/set//'] = function ($args) { + $routes['/cookies/set//'] = static function ($args) { $expiry = isset($_GET['expiry']) ? (int) $_GET['expiry'] : 0; setcookie($args['key'], $args['value'], $expiry, '/'); Response::redirect('/cookies'); exit; }; - $routes['/cookies/delete'] = function () { + $routes['/cookies/delete'] = static function () { foreach ($_GET as $key => $value) { setcookie($key, '', time() - 3600, '/'); } @@ -107,7 +107,7 @@ function get_routes() exit; }; - $routes['/basic-auth//'] = function ($args) { + $routes['/basic-auth//'] = static function ($args) { $supplied = [ 'user' => empty($_SERVER['PHP_AUTH_USER']) ? false : $_SERVER['PHP_AUTH_USER'], 'password' => empty($_SERVER['PHP_AUTH_PW']) ? false : $_SERVER['PHP_AUTH_PW'], @@ -126,7 +126,7 @@ function get_routes() }; // Redirects! - $routes['/redirect/'] = function ($args) use ($routes) { + $routes['/redirect/'] = static function ($args) use ($routes) { $num = (int) max((int) $args['number'], 1); if ($num === 1) { Response::redirect('/get'); @@ -138,12 +138,12 @@ function get_routes() Response::redirect(sprintf('/redirect/%d', $num)); exit; }; - $routes['/redirect-to'] = function () { + $routes['/redirect-to'] = static function () { $location = $_GET['url']; header('Location: ' . $location, true, 302); exit; }; - $routes['/relative-redirect/'] = function ($args) { + $routes['/relative-redirect/'] = static function ($args) { $num = (int) max((int) $args['number'], 1); if ($num === 1) { Response::redirect('/get', 302, true); @@ -157,13 +157,13 @@ function get_routes() }; // Miscellaneous! - $routes['/delay/'] = function ($args) use ($routes) { + $routes['/delay/'] = static function ($args) use ($routes) { $delay = min($args['delay'], 10); sleep($delay); return $routes['/get']; }; - $routes['/status/'] = function ($args) use ($base_url) { + $routes['/status/'] = static function ($args) use ($base_url) { $code = (int) $args['code']; switch ($code) { @@ -187,10 +187,10 @@ function get_routes() http_response_code($code); exit; }; - $routes['/stream/'] = function ($args) use ($request_data) { + $routes['/stream/'] = static function ($args) use ($request_data) { $response = $request_data; $num = min($args['num'], 100); - $generate_stream = function () use ($num, $response) { + $generate_stream = static function () use ($num, $response) { foreach (range(0, $num - 1) as $n) { $response['id'] = $n; yield json_encode($response, JSON_PRETTY_PRINT) . "\n"; @@ -205,7 +205,7 @@ function get_routes() echo "0\r\n\r\n"; exit; }; - $routes['/gzip'] = function () use ($request_data) { + $routes['/gzip'] = static function () use ($request_data) { $response = $request_data; $response['gzipped'] = true; @@ -218,7 +218,7 @@ function get_routes() echo $response; exit; }; - $routes['/bytes/'] = function ($args) { + $routes['/bytes/'] = static function ($args) { header('Content-Type: application/octet-stream'); mt_srand(0); @@ -233,7 +233,7 @@ function get_routes() }; // Finally, the index! - $routes['/'] = function () use ($routes) { + $routes['/'] = static function () use ($routes) { header('Content-Type: text/html; charset=utf-8'); echo '
    '; diff --git a/lib/utils.php b/lib/utils.php index 1d89585..e57a866 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -28,9 +28,12 @@ public static function generatePostData() $data['json'] = json_decode($data['data']); - $data['files'] = array_map(function ($data) { - return file_get_contents($data['tmp_name']); - }, $_FILES); + $data['files'] = array_map( + static function ($data) { + return file_get_contents($data['tmp_name']); + }, + $_FILES + ); return $data; } From 17146ac65a4043f1ab6a58631fe8afce4384b6bc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2025 11:33:28 +0100 Subject: [PATCH 15/15] CS/QA: strict comparisons (not enforced) --- bin/serve.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/serve.php b/bin/serve.php index 86a7e6a..e7121cf 100644 --- a/bin/serve.php +++ b/bin/serve.php @@ -12,8 +12,8 @@ if (isset($_SERVER['HTTPS']) && ! empty($_SERVER['HTTPS'])) { $is_secure = true; } elseif ( - (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') - || (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') + (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') + || (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') ) { $is_secure = true; }