-
Notifications
You must be signed in to change notification settings - Fork 0
merge dev -> main #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| name: PHP Tests | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main, dev ] | ||
| pull_request: | ||
| branches: [ main, dev ] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| php: ['8.0', '8.1', '8.2', '8.3', '8.4'] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup PHP ${{ matrix.php }} | ||
| uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: ${{ matrix.php }} | ||
| extensions: mbstring, openssl | ||
| coverage: none | ||
|
|
||
| - 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: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} | ||
| restore-keys: ${{ runner.os }}-composer- | ||
|
|
||
| - name: Install dependencies | ||
| run: composer install --prefer-dist --no-progress | ||
|
|
||
| - name: Run PHPUnit | ||
| run: vendor/bin/phpunit --no-coverage | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,6 @@ bin/phpDocumentor.phar | |
|
|
||
| # Composer | ||
| vendor/ | ||
| composer.lock | ||
|
|
||
| # PHPUnit | ||
| .phpunit.result.cache | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to this project will be documented in this file. | ||
|
|
||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). | ||
|
|
||
| ## [Unreleased] | ||
|
|
||
| ### Added | ||
|
|
||
| - **Strict types**: `declare(strict_types=1);` in all PHP library and test files. | ||
| - **Vars::arrayContainsSubstring()**: Alias for `arrayInString()` with clearer naming. | ||
| - **Tests**: New test classes for Crypto, Files, SQLite, Times, and Random. | ||
| - **CI**: GitHub Actions workflow (`.github/workflows/php.yml`) running PHPUnit on PHP 8.0–8.4 for `main` and `dev`. | ||
| - **CHANGELOG.md**: This file. | ||
|
|
||
| ### Changed | ||
|
|
||
| - **Error handling**: Replaced `die()` with exceptions in Network, Random, Files, and Debugger (bootstrap `_All.php` still uses `die()` for fatal startup failures). | ||
| - `Network::getUserIP()` / `getServerIP()`: throw `RuntimeException` when `$die_if_empty` is true and IP cannot be determined. | ||
| - `Random::genStr()`: throw `InvalidArgumentException` for invalid type instead of `die()`. | ||
| - `Files::preventDirect()` default callback: throw `RuntimeException("404 Not found")` after setting 404 response code. | ||
| - `Debugger::output(..., $die = true)`: echo then throw `RuntimeException` instead of `die()`. | ||
| - **Network::ipInRange()**: Removed `echo` on invalid IPs; still returns `null` for invalid input. Fixed check to use `=== false` for `ip2long()` so `0.0.0.0` is valid. | ||
| - **Vars::arrayInString()**: Documented behaviour (any element contains needle); added return type `bool`. | ||
| - **Images**: Docblocks use `\Imagick` and `\ImagickException`; `blur()` has explicit return type `string`. | ||
| - **Composer**: `composer.lock` is no longer ignored so dev and CI use reproducible dependency versions. | ||
|
|
||
| ### Documentation | ||
|
|
||
| - **README**: Get started section documents both Composer and _All.php; module links point to `Docs/classes/*.html`. | ||
| - **TEST_SUMMARY.md**: Updated to include new test classes and strict types / exception behaviour. | ||
| - **REFACTORING_SUMMARY.md**: Can be updated to reference this changelog for recent improvements. | ||
|
|
||
| --- | ||
|
|
||
| ## Previous work (pre-changelog) | ||
|
|
||
| - OOP refactor: namespaces, Base/DI, SQL connection injection, identifier validation, Debugger data/HTML separation, visibility and return types (see `REFACTORING_SUMMARY.md` and `OOP_REVIEW.md`). | ||
| - Crypto: corrected `hash()` argument order, `verifyhash()` with `hash_equals()`, IV handling with embedded IV in ciphertext. | ||
| - Images/SQLite: `parent::__construct()`; SQLite visibility and `$this->res()`. | ||
| - SQL::search(): table and column names validated via `validateIdentifier()`. | ||
| - README and index.php: fixed doc and test links; bootstrap prefers Composer autoload. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace PHPUtils; | ||
|
|
||
| /* ────────────────────────────────────────────────────────────────────────── */ | ||
|
|
@@ -13,70 +15,85 @@ | |
| * @package PHPUtils | ||
| */ | ||
| class Crypto extends Base { | ||
|
|
||
| /** | ||
| * Generates a random IV for the given encryption method | ||
| * Generates a random IV for the given encryption method (hex-encoded for storage). | ||
| * | ||
| * @param mixed $method The encryption method to use | ||
| * @return string The generated IV | ||
| * @param string $method The encryption method to use | ||
| * @return string The generated IV as hex string | ||
| */ | ||
| function genIV(string $method) { | ||
| public function genIV(string $method): string { | ||
| $len = openssl_cipher_iv_length($method); | ||
| $bytes = openssl_random_pseudo_bytes($len); | ||
| return bin2hex($bytes); | ||
| } | ||
|
|
||
| /** | ||
| * Encrypt a string using a password, and optionally an IV | ||
| * Encrypt a string using a password, and optionally an IV. | ||
| * When $iv is true, a random IV is used and prepended to the ciphertext (base64(iv_raw . ciphertext)). | ||
| * | ||
| * @param mixed $str The string to encrypt | ||
| * @param mixed $password The password to use | ||
| * @param mixed $method The encryption method to use. Defaults to aes-256-cbc | ||
| * @param mixed $iv Whether to use an IV or not. Defaults to false | ||
| * @return string The encrypted string | ||
| * @param string $str The string to encrypt | ||
| * @param string $password The password to use | ||
| * @param string $method The encryption method. Defaults to aes-256-cbc | ||
| * @param bool $iv Whether to use a random IV (prepended to output). Defaults to false | ||
| * @return string The encrypted string (when iv=true, base64 of IV + ciphertext) | ||
| */ | ||
| function encryptwithpw(string $str, string $password, string $method = 'aes-256-cbc', bool $iv = false) { | ||
| $iv = ($iv ? $this->genIV($method) : ''); | ||
| return openssl_encrypt($str,$method,$password,iv:$iv); | ||
| public function encryptwithpw(string $str, string $password, string $method = 'aes-256-cbc', bool $iv = false): string { | ||
| if ($iv) { | ||
| $ivRaw = hex2bin($this->genIV($method)); | ||
| $encrypted = openssl_encrypt($str, $method, $password, iv: $ivRaw); | ||
| return base64_encode($ivRaw . $encrypted); | ||
|
Comment on lines
+44
to
+45
|
||
| } | ||
| return openssl_encrypt($str, $method, $password); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Decrypt a string using a password, and optionally an IV | ||
| * Decrypt a string using a password, and optionally an IV. | ||
| * When $iv is empty and the string was produced with iv=true, the embedded IV is used. | ||
| * When $iv is non-empty, it is treated as hex and used as the IV (ciphertext only in $str). | ||
| * | ||
| * @param mixed $str The string to decrypt | ||
| * @param mixed $password The password to use | ||
| * @param mixed $method The encryption method to use. Defaults to aes-256-cbc | ||
| * @param mixed $iv Whether to use an IV or not. Defaults to '' | ||
| * @return string The decrypted string | ||
| * @param string $str The string to decrypt (base64 when IV was embedded, or raw/base64 ciphertext when $iv provided) | ||
| * @param string $password The password to use | ||
| * @param string $method The encryption method. Defaults to aes-256-cbc | ||
| * @param string $iv Optional hex-encoded IV when not embedded. Defaults to '' | ||
| * @return string|false The decrypted string or false on failure | ||
| */ | ||
| function decryptwithpw(string $str, string $password, string $method = 'aes-256-cbc', string $iv = '') { | ||
| return openssl_decrypt($str,$method,$password,iv:$iv); | ||
| public function decryptwithpw(string $str, string $password, string $method = 'aes-256-cbc', string $iv = ''): string|false { | ||
| $ivLen = openssl_cipher_iv_length($method); | ||
| if ($iv !== '') { | ||
| $ivRaw = hex2bin($iv); | ||
| $ciphertext = base64_decode($str, true) ?: $str; | ||
| return openssl_decrypt($ciphertext, $method, $password, iv: $ivRaw); | ||
| } | ||
| $decoded = base64_decode($str, true); | ||
| if ($decoded !== false && strlen($decoded) > $ivLen) { | ||
| $ivRaw = substr($decoded, 0, $ivLen); | ||
| $ciphertext = substr($decoded, $ivLen); | ||
| return openssl_decrypt($ciphertext, $method, $password, iv: $ivRaw); | ||
| } | ||
| return openssl_decrypt($str, $method, $password); | ||
|
Comment on lines
+61
to
+74
|
||
| } | ||
|
|
||
| /** | ||
| * hash | ||
| * Hash a string using the given algorithm. | ||
| * | ||
| * @param mixed $str The string to hash | ||
| * @param mixed $hash The hash method to use. Defaults to sha512 | ||
| * @param string $str The string to hash | ||
| * @param string $hash The hash algorithm. Defaults to sha512 | ||
| * @return string The hashed string | ||
| */ | ||
| function hash(string $str, string $hash = 'sha512') { | ||
| return hash($str, $hash); | ||
| public function hash(string $str, string $hash = 'sha512'): string { | ||
| return hash($hash, $str); | ||
| } | ||
|
|
||
| /** | ||
| * verifyhash | ||
| * | ||
| * Verifies a hash | ||
| * | ||
| * @param mixed $str The string to verify | ||
| * @param mixed $hash The hash to verify against | ||
| * @param mixed $hashmethod The hash method to use. Defaults to sha512 | ||
| * | ||
| * @return bool Whether the hash is valid or not | ||
| * Verify a string against a hash (timing-safe comparison). | ||
| * | ||
| * @param string $str The string to verify | ||
| * @param string $hash The hash to verify against | ||
| * @param string $hashmethod The hash method. Defaults to sha512 | ||
| * @return bool Whether the hash is valid | ||
| */ | ||
| function verifyhash(string $str, string $hash, string $hashmethod = 'sha512') { | ||
| return hash($hashmethod, $str) == $hash; | ||
| public function verifyhash(string $str, string $hash, string $hashmethod = 'sha512'): bool { | ||
| return hash_equals($hash, hash($hashmethod, $str)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace PHPUtils; | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GitHub Actions workflow only installs the
mbstringandopensslextensions. However, the Images class requires theimagickextension (checked in its constructor). Tests that use the Images class will fail in CI unless the imagick extension is added to the workflow, or tests for Images are skipped when the extension is not available.