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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ phpstan-baseline.neon export-ignore
qodana.yaml export-ignore
renovate.json export-ignore
.coderabbit.yaml export-ignore
sonar-project.properties export-ignore
CHANGELOG.md export-ignore
CLAUDE.md export-ignore
14 changes: 10 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
coverage: true

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5

- name: Setup PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2
with:
php-version: ${{ matrix.php }}
extensions: intl, mbstring
Expand All @@ -46,7 +46,7 @@ jobs:
run: echo "dir=$(composer config cache-dir)" >> $GITHUB_OUTPUT

- name: Cache Composer
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: composer-${{ runner.os }}-${{ matrix.php }}-${{ matrix.deps || 'stable' }}-${{ hashFiles('**/composer.json') }}
Expand Down Expand Up @@ -75,14 +75,20 @@ jobs:
run: composer lint

- name: Run static analysis
if: ${{ matrix.php != '7.4' && matrix.php != '8.0' }}
run: composer analyse

- name: Run tests
if: ${{ !matrix.coverage }}
run: composer test

- name: Run tests with coverage
if: ${{ matrix.coverage }}
run: ./vendor/bin/phpunit --colors=always --coverage-clover build/logs/clover.xml

- name: Upload coverage to Codecov
if: ${{ matrix.coverage }}
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
files: build/logs/clover.xml
fail_ci_if_error: false
7 changes: 4 additions & 3 deletions .github/workflows/qodana.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ on:
jobs:
qodana:
runs-on: ubuntu-latest
if: github.repository == 'XOOPS/xmf'
permissions:
contents: write
pull-requests: write
checks: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0

- name: Qodana Scan
uses: JetBrains/qodana-action@v2025.2
uses: JetBrains/qodana-action@99ec27a55aaaf5ba2fd7e5816e66231caed7a72a # v2025.2.4
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
40 changes: 40 additions & 0 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: SonarCloud
on:
push:
branches: [master]
pull_request:
types: [opened, synchronize, reopened]

jobs:
sonarcloud:
name: SonarCloud Analysis
runs-on: ubuntu-latest
if: github.repository == 'XOOPS/xmf'

steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
fetch-depth: 0

- name: Setup PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2
with:
php-version: "8.3"
extensions: intl, mbstring
tools: composer
coverage: xdebug

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

- name: Ensure build directory exists
run: mkdir -p build/logs

- name: Run tests with coverage
run: ./vendor/bin/phpunit --colors=always --coverage-clover build/logs/clover.xml

- name: SonarCloud Scan
if: ${{ secrets.SONAR_TOKEN != '' }}
uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # v7
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Comment on lines +36 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix: secrets context is not available in step-level if conditions.

The secrets context cannot be used in step if expressions—only env, github, inputs, job, matrix, needs, runner, steps, strategy, and vars are available. This condition will cause a workflow syntax error.

Use an environment variable to expose the secret's presence, then check that variable:

🐛 Proposed fix using env variable
       - name: SonarCloud Scan
-        if: ${{ secrets.SONAR_TOKEN != '' }}
+        if: ${{ env.SONAR_TOKEN != '' }}
         uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # v7
         env:
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Alternatively, move the check to job level or use a dedicated step to set an output variable based on secret presence.

🧰 Tools
🪛 actionlint (1.7.10)

[error] 37-37: context "secrets" is not allowed here. available contexts are "env", "github", "inputs", "job", "matrix", "needs", "runner", "steps", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
In @.github/workflows/sonarcloud.yml around lines 36 - 40, The step "SonarCloud
Scan" uses a step-level if: ${{ secrets.SONAR_TOKEN != '' }} which is invalid
because the secrets context isn't available in step if-expressions; fix by
exposing the secret presence via an environment variable or moving the condition
to job-level: set an env like SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} at the job
or workflow level (or add a prior step that writes a step output/var indicating
presence), then change the step's if to check that env/var (e.g., if:
env.SONAR_TOKEN != '' or if: needs.<step>.outputs.sonar_present == 'true'),
keeping the "SonarCloud Scan" uses and SONAR_TOKEN environment mapping intact.

106 changes: 61 additions & 45 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# XMF ChangeLog

## [Unreleased]
## [1.2.33] - 2026-02-08



## [1.2.33-beta2] - 2026-02-07

### Bug Fixes
* Fix `Request::setVar()` writing to literal key `'name'` instead of variable `$name` for ENV and SERVER superglobals
Expand All @@ -23,35 +27,6 @@
* Preserve `Jwt\JsonWebToken::decode()` `object|false` API contract (no longer throws on decode failure)
* Remove dead `get_magic_quotes_gpc()` calls from `Request` (function removed in PHP 8.0)

### Changed
* Use strict comparison (`===`) instead of loose (`==`) in `FilterInput` attribute filtering and `Database\Tables` column lookups
* Fix `FileStorageTest` namespace from `Xmf\Key` to `Xmf\Test\Key` to match autoload-dev configuration
* Fix trailing semicolons in `@throws` PHPDoc tags in `Jwt\JsonWebToken::create()`

### Removed
* Remove redundant `paragonie/random_compat` dependency (native in PHP 7+)

### Infrastructure
* Add PHPStan stub files for XOOPS framework classes to eliminate ~524 false-positive errors
* Configure `phpstan.neon` to scan stubs directory
* Move changelog to `CHANGELOG.md` at repo root; `docs/changelog.md` now redirects
* Simplify `.scrutinizer.yml` to analysis-only; move `stubs/` from `excluded_paths` to `dependency_paths` for constant/class resolution
* Add dedicated PHPStan, PHPCS, and code coverage jobs to GitHub Actions CI workflow
* Generate PHPStan baseline (`phpstan-baseline.neon`) with ~546 existing errors for incremental cleanup
* Add `composer baseline` script with backup/restore safety for PHPStan baseline regeneration
* Update `.gitignore` to exclude `build/` directory (coverage output)
* Update `.gitattributes` with export-ignore for PHPStan, PHPUnit, and stub files
* Add GitHub Copilot custom instructions (`.github/copilot-instructions.md`) and reusable XOOPS template

### Tests
* Add unit tests for `Request::setVar()` ENV and SERVER branches
* Add unit tests for `FilterInput` hex and decimal entity decode
* Add unit test for `Metagen::html2text()` numeric entity conversion
* Add unit test for `IPAddress::normalize()` invalid IP handling
* Add unit tests for `Yaml::read()` and `Yaml::readWrapped()` file size limits

## [1.2.32] - 2025-02-06

### Ulid class overhaul (breaking changes)

**New features:**
Expand All @@ -74,13 +49,13 @@
- The old method incorrectly subtracted a Y2K epoch offset; the new behavior uses standard Unix epoch milliseconds per the ULID spec
* `encodeRandomness()` reimplemented with optimized bit-packing algorithm for correct 80-bit extraction

**Bug fixes:**
**Ulid bug fixes:**
* Fix `getDateTime()` to always return UTC regardless of system timezone
* Fix `decodeTime()` to fully validate the ULID via `isValid()` (rejects invalid chars, overflow, wrong length)
* Fix `decodeRandomness()` to validate the full ULID (including time portion), not just the random part
* Sanitize exception messages to avoid leaking full ULID values into logs

**Test improvements:**
**Ulid test improvements:**
* Replace sleep-based ordering tests with `generateMonotonic()` to eliminate CI flakiness
* Fix spec vector test comment and assertion (correct UTC time: 22:36:16, not 23:29:36)
* Fix `testDecodeTimeThrowsExceptionForInvalidCharacter` to place invalid char in time portion
Expand All @@ -89,21 +64,62 @@
* Use `expectExceptionMessageMatches()` for more robust exception message assertions
* Reduce `testRandomnessDistribution` iterations (10000 to 1000) with wider tolerance to improve speed

## [1.2.31] - 2024-11-27
### Changed
* Use strict comparison (`===`) instead of loose (`==`) in `FilterInput` attribute filtering and `Database\Tables` column lookups
* Fix `FileStorageTest` namespace from `Xmf\Key` to `Xmf\Test\Key` to match autoload-dev configuration
* Fix trailing semicolons in `@throws` PHPDoc tags in `Jwt\JsonWebToken::create()`
* Update composer.json by @mambax7 in #119
* Update composer, phpstan, phpcs by @mambax7 in #122

### Removed
* Remove redundant `paragonie/random_compat` dependency (native in PHP 7+)

### Infrastructure
* Add PHPStan stub files for XOOPS framework classes to eliminate ~524 false-positive errors
* Configure `phpstan.neon` to scan stubs directory
* Move changelog to `CHANGELOG.md` at repo root; `docs/changelog.md` now redirects
* Simplify `.scrutinizer.yml` to analysis-only; move `stubs/` from `excluded_paths` to `dependency_paths` for constant/class resolution
* Add dedicated PHPStan, PHPCS, and code coverage jobs to GitHub Actions CI workflow
* Generate PHPStan baseline (`phpstan-baseline.neon`) with ~546 existing errors for incremental cleanup
* Add `composer baseline` script with backup/restore safety for PHPStan baseline regeneration
* Update `.gitignore` to exclude `build/` directory (coverage output)
* Update `.gitattributes` with export-ignore for PHPStan, PHPUnit, and stub files
* Add GitHub Copilot custom instructions (`.github/copilot-instructions.md`) and reusable XOOPS template

### Tests
* Add unit tests for `Request::setVar()` ENV and SERVER branches
* Add unit tests for `FilterInput` hex and decimal entity decode
* Add unit test for `Metagen::html2text()` numeric entity conversion
* Add unit test for `IPAddress::normalize()` invalid IP handling
* Add unit tests for `Yaml::read()` and `Yaml::readWrapped()` file size limits

Comment on lines +67 to +95
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor: Add blank lines below headings for markdown consistency.

Several section headings (### Changed, ### Removed, ### Infrastructure, ### Tests) are missing the blank line after them that markdownlint expects (MD022). While this doesn't affect rendering in most parsers, it improves consistency with the rest of the file.

📝 Example fix pattern
 ### Changed
+
 * Use strict comparison (`===`) instead of loose (`==`)...

Apply similar blank lines after ### Removed, ### Infrastructure, and ### Tests headings.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Changed
* Use strict comparison (`===`) instead of loose (`==`) in `FilterInput` attribute filtering and `Database\Tables` column lookups
* Fix `FileStorageTest` namespace from `Xmf\Key` to `Xmf\Test\Key` to match autoload-dev configuration
* Fix trailing semicolons in `@throws` PHPDoc tags in `Jwt\JsonWebToken::create()`
* Update composer.json by @mambax7 in #119
* Update composer, phpstan, phpcs by @mambax7 in #122
### Removed
* Remove redundant `paragonie/random_compat` dependency (native in PHP 7+)
### Infrastructure
* Add PHPStan stub files for XOOPS framework classes to eliminate ~524 false-positive errors
* Configure `phpstan.neon` to scan stubs directory
* Move changelog to `CHANGELOG.md` at repo root; `docs/changelog.md` now redirects
* Simplify `.scrutinizer.yml` to analysis-only; move `stubs/` from `excluded_paths` to `dependency_paths` for constant/class resolution
* Add dedicated PHPStan, PHPCS, and code coverage jobs to GitHub Actions CI workflow
* Generate PHPStan baseline (`phpstan-baseline.neon`) with ~546 existing errors for incremental cleanup
* Add `composer baseline` script with backup/restore safety for PHPStan baseline regeneration
* Update `.gitignore` to exclude `build/` directory (coverage output)
* Update `.gitattributes` with export-ignore for PHPStan, PHPUnit, and stub files
* Add GitHub Copilot custom instructions (`.github/copilot-instructions.md`) and reusable XOOPS template
### Tests
* Add unit tests for `Request::setVar()` ENV and SERVER branches
* Add unit tests for `FilterInput` hex and decimal entity decode
* Add unit test for `Metagen::html2text()` numeric entity conversion
* Add unit test for `IPAddress::normalize()` invalid IP handling
* Add unit tests for `Yaml::read()` and `Yaml::readWrapped()` file size limits
### Changed
* Use strict comparison (`===`) instead of loose (`==`) in `FilterInput` attribute filtering and `Database\Tables` column lookups
* Fix `FileStorageTest` namespace from `Xmf\Key` to `Xmf\Test\Key` to match autoload-dev configuration
* Fix trailing semicolons in `@throws` PHPDoc tags in `Jwt\JsonWebToken::create()`
* Update composer.json by `@mambax7` in `#119`
* Update composer, phpstan, phpcs by `@mambax7` in `#122`
### Removed
* Remove redundant `paragonie/random_compat` dependency (native in PHP 7+)
### Infrastructure
* Add PHPStan stub files for XOOPS framework classes to eliminate ~524 false-positive errors
* Configure `phpstan.neon` to scan stubs directory
* Move changelog to `CHANGELOG.md` at repo root; `docs/changelog.md` now redirects
* Simplify `.scrutinizer.yml` to analysis-only; move `stubs/` from `excluded_paths` to `dependency_paths` for constant/class resolution
* Add dedicated PHPStan, PHPCS, and code coverage jobs to GitHub Actions CI workflow
* Generate PHPStan baseline (`phpstan-baseline.neon`) with ~546 existing errors for incremental cleanup
* Add `composer baseline` script with backup/restore safety for PHPStan baseline regeneration
* Update `.gitignore` to exclude `build/` directory (coverage output)
* Update `.gitattributes` with export-ignore for PHPStan, PHPUnit, and stub files
* Add GitHub Copilot custom instructions (`.github/copilot-instructions.md`) and reusable XOOPS template
### Tests
* Add unit tests for `Request::setVar()` ENV and SERVER branches
* Add unit tests for `FilterInput` hex and decimal entity decode
* Add unit test for `Metagen::html2text()` numeric entity conversion
* Add unit test for `IPAddress::normalize()` invalid IP handling
* Add unit tests for `Yaml::read()` and `Yaml::readWrapped()` file size limits
🧰 Tools
🪛 LanguageTool

[uncategorized] ~87-~87: The official name of this software platform is spelled with a capital “H”.
Context: ...Add GitHub Copilot custom instructions (.github/copilot-instructions.md) and reusable ...

(GITHUB)

🪛 markdownlint-cli2 (0.20.0)

[warning] 67-67: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 74-74: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 77-77: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 89-89: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In `@CHANGELOG.md` around lines 67 - 95, Add a single blank line immediately after
each top-level section heading to satisfy markdownlint MD022: insert one empty
line below the headings "### Changed", "### Removed", "### Infrastructure", and
"### Tests" in the changelog so each heading is followed by a blank line before
the list content.

## [1.2.33-beta1] - 2025-09-10

* updating copyright by @mambax7 in #114
* update composer.json by @mambax7 in #115
* add php_codesniffer and phpstan by @mambax7 in #116
* add SendmailRunner by @mambax7 in #117
* update phpstan and php_codesniffer versions by @mambax7 in #118

## [1.2.32] - 2025-03-10

* Update firebase/php-jwt to 6.11.0 with PHP 7.4 compatibility

## [1.2.31] - 2024-11-28
* Updated Debug for Kint changes (mamba)
* Added Issues Template (mamba)
* PHP 8.4 Implicitly nullable parameters (mamba)
* Update PhpUnit versions (mamba)
* Upgrade Smarty to 4.5.5

## [1.2.30] - 2024-05-30
## [1.2.30] - 2024-06-16
* Upgrade Smarty to 4.5.3

## [1.2.29] - 2023-11-20
## [1.2.29] - 2023-12-05
* Add Random::generateSecureRandomBytes()
* Replace random_bytes() with generateSecureRandomBytes() for PHP 5.6

## [1.2.28] - 2023-10-30
## [1.2.28] - 2023-11-01
* Updates to library dependencies
* PHP 8.0 Error Suppression operator issues
* Handle case of no permissionHandler found
Expand All @@ -122,13 +138,13 @@
## [1.2.25] - 2021-05-07
* Add \Xmf\Module\Admin::renderNavigation() method

## [1.2.24] - 2021-03-25
## [1.2.24] - 2021-03-26
* Fixes for PHP 5.3 compatibility

## [1.2.23] - 2021-02-15
## [1.2.23] - 2021-02-16
* Additional fix in Debug for Kint 3.3

## [1.2.22] - 2021-02-13
## [1.2.22] - 2021-02-14
* Fixes in Debug for Kint 3.3

## [1.2.21] - 2021-02-13
Expand All @@ -143,7 +159,7 @@
## [1.2.19] - 2020-02-13
* \Xmf\Yaml::read() eliminate PHP warning if specified file does not exist

## [1.2.18] - 2019-12-01
## [1.2.18] - 2019-12-02
* PHP 7.4 ready
* Fix error in Database\Table::loadTableFromYamlFile()
* Add Uuid::packAsBinary() and Uuid::unpackBinary() methods
Expand All @@ -161,7 +177,7 @@
* Add dirname() method to helper classes
* Changes Request::hasVar() default for $hash to 'default'

## [1.2.14] - 2018-03-30
## [1.2.14] - 2018-03-31
* Add serialization to non-scalar log data
* Improved handling of custom key storage
* Add some unit testing
Expand Down Expand Up @@ -212,25 +228,25 @@
## [1.1.3] - 2016-08-13
* Fix XoopsRequest class not found in StripSlashesRecursive method

## [1.1.2] - 2016-08-06
## [1.1.2] - 2016-08-07
* Fix Can't check isUserAdmin on Anonymous

## [1.1.1] - 2016-07-28
* firebase/php-jwt to 4.0.0
* Bump min PHP to 5.3.9 to allow symfony/yaml 2.8.*

## [1.1.0] - 2016-07-14
## [1.1.0] - 2016-07-15
* Add Xmf\Database\Migrate class to provide schema synchronization capabilities for modules
* Bug fixes in Xmf\Database\Tables including option to disable automatic quoting of values in update() and insert()

## [1.0.2] - 2016-06-01
## [1.0.2] - 2016-05-31
* Fix issues with file name validation in Xmf\Language::loadFile()
* Add method Request::hasVar($name, $hash) to determine if a variable name exists in hash

## [1.0.1] - 2016-03-30
* Remove @version from docblock, consistent with XoopsCore25

## [1.0.0] - 2016-03-25
## [1.0.0] - 2016-03-28
* Fix minor typos
* Add version to changelog

Expand Down
12 changes: 2 additions & 10 deletions phpcs.xml.dist → phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,14 @@
<!-- Use PSR-12 as the base standard -->
<rule ref="PSR12"/>

<!-- Relax line length: warn at 200 chars instead of the default 120 -->
<!-- Disable line length check (can be overly strict for documentation) -->
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="200"/>
<property name="absoluteLineLimit" value="0"/>
</properties>
<severity>0</severity>
</rule>

<!-- Exclude patterns -->
<exclude-pattern>*/_archive/*</exclude-pattern>
<exclude-pattern>*/docs/*</exclude-pattern>
<exclude-pattern>*/tests/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>

<!-- Allow test files to have different class naming -->
<rule ref="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>*/tests/*</exclude-pattern>
</rule>
</ruleset>
19 changes: 0 additions & 19 deletions phpunit10.xml.dist

This file was deleted.

2 changes: 1 addition & 1 deletion qodana.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: "1.0"

linter: jetbrains/qodana-php:latest
linter: jetbrains/qodana-php:2025.2

profile:
name: qodana.recommended
Expand Down
12 changes: 12 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sonar.organization=xoops
sonar.projectKey=XOOPS_xmf
sonar.projectName=XMF

sonar.sources=src
sonar.tests=tests
sonar.sourceEncoding=UTF-8

sonar.php.version=7.4
sonar.php.coverage.reportPaths=build/logs/clover.xml

sonar.exclusions=vendor/**,stubs/**,build/**
Loading