Skip to content

Conversation

@Darknetzz
Copy link
Owner

This pull request introduces several improvements across the codebase, focusing on stricter type safety, improved error handling, enhanced cryptography utilities, and better documentation and testing. Notably, it replaces most uses of die() with exceptions for more robust error handling, adds strict type declarations to all PHP files, and updates the cryptography and image manipulation methods for clarity and correctness. Continuous integration is also introduced for automated testing.

Error handling improvements:

  • Replaced most instances of die() with appropriate exceptions throughout the codebase, including in Network, Random, Files, Debugger, and Images classes. This ensures that fatal errors are handled in a more controlled and testable way. (PHPUtils/Network.php [1] [2]; PHPUtils/Random.php [3]; PHPUtils/Files.php [4]; PHPUtils/Debugger.php [5]; PHPUtils/Images.php [6] [7]

Type safety and code modernization:

  • Added declare(strict_types=1); to all PHP library and test files to enforce strict type checking. (PHPUtils/API.php [1] PHPUtils/Auth.php [2] PHPUtils/Base.php [3] PHPUtils/Calendar.php [4] PHPUtils/Crypto.php [5] PHPUtils/Debugger.php [6] PHPUtils/Files.php [7] PHPUtils/Funcs.php [8] PHPUtils/Images.php [9] PHPUtils/Navigation.php [10] PHPUtils/Network.php [11] PHPUtils/Random.php [12]
  • Updated function signatures and docblocks for stricter type hinting and clearer documentation, especially in Crypto and Images classes. (PHPUtils/Crypto.php [1] PHPUtils/Images.php [2] [3] [4]

Cryptography and utility enhancements:

  • Improved the Crypto class: clarified IV handling, fixed the hash() argument order, and made verifyhash() use timing-safe comparison. (PHPUtils/Crypto.php PHPUtils/Crypto.phpL18-R97)
  • Improved Network::ipInRange() to properly validate IPs and removed direct output on error. (PHPUtils/Network.php PHPUtils/Network.phpL34-R36)

Continuous Integration and Testing:

  • Added a GitHub Actions workflow (.github/workflows/php.yml) to run PHPUnit tests on PHP versions 8.0–8.4 for main and dev branches, ensuring automated testing and compatibility.
  • Added new test classes for Crypto, Files, SQLite, Times, and Random.

Documentation and changelog:

  • Added a CHANGELOG.md following the Keep a Changelog format to document all notable changes and improvements.
  • Updated documentation to reflect new features, strict types, and exception behavior.

These changes collectively improve the safety, maintainability, and reliability of the codebase.

… handling

- Changed documentation file paths from "Docs/PHPDocumentor/classes" to "Docs/classes".
- Updated test folder path from "test" to "tests".
- Improved error messages in the Images class and added exception handling.
- Refactored Crypto class methods to include type hints and return types.
- Enhanced SQL class to validate table and column identifiers to prevent SQL injection.
- Updated README to reflect Composer usage and improved module documentation.
- Adjusted bootstrap file for PHPUnit tests to prefer Composer autoloading.
…cumentation

- Added `declare(strict_types=1);` to all PHP files for stricter type checking.
- Improved error handling by replacing `die()` with exceptions in various classes.
- Updated README and other documentation files to reflect recent changes and improvements.
- Enhanced test summaries to include new test cases and requirements.
- Removed `composer.lock` from `.gitignore` to allow tracking of dependencies.
@Darknetzz Darknetzz self-assigned this Feb 3, 2026
Copilot AI review requested due to automatic review settings February 3, 2026 15:15
@gitguardian
Copy link

gitguardian bot commented Feb 3, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - Generic Password 9cf7350 tests/CryptoTest.php View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request merges the dev branch into main, introducing significant improvements to code quality, type safety, error handling, and testing infrastructure. The changes focus on modernizing the codebase with strict type declarations, replacing die() calls with exceptions, fixing cryptography bugs, and establishing CI/CD with GitHub Actions.

Changes:

  • Added declare(strict_types=1); to all PHP files for stricter type checking
  • Replaced die() with exceptions in Network, Random, Files, and Debugger classes for better error handling
  • Fixed critical bugs in Crypto class (hash argument order, timing-safe comparison) and attempted IV handling improvements
  • Added comprehensive test coverage: CryptoTest, FilesTest, SQLiteTest, TimesTest, RandomTest
  • Introduced GitHub Actions CI workflow for automated testing on PHP 8.0-8.4
  • Updated documentation with Composer installation instructions and CHANGELOG.md

Reviewed changes

Copilot reviewed 39 out of 41 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
composer.lock Added with locked dependency versions (contains future dates)
.github/workflows/php.yml New CI workflow for automated PHPUnit testing
CHANGELOG.md New changelog documenting all improvements
PHPUtils/*.php Added strict types, improved error handling, fixed bugs
tests/*.php Added strict types to all test files
tests/*Test.php New test classes for Crypto, Files, SQLite, Times, Random
tests/bootstrap.php Updated to prefer Composer autoload
README.md Updated with Composer instructions and new doc links
index.php Fixed doc and test file path references
TEST_SUMMARY.md Updated with new test information
Comments suppressed due to low confidence (1)

PHPUtils/Images.php:97

  • The textToImage method is missing namespace prefixes for Imagick classes. Since the file uses declare(strict_types=1); and is in the PHPUtils namespace, references to Imagick classes should be prefixed with backslash:
  • Line 90: new ImagickDraw() should be new \ImagickDraw()
  • Line 94: Imagick::GRAVITY_NORTHWEST should be \Imagick::GRAVITY_NORTHWEST
  • Line 97: new Imagick($imagePath) should be new \Imagick($imagePath)

Also, line 60 correctly uses new Imagick($imagePath) but this should also be new \Imagick($imagePath) for consistency.

            $image = new Imagick($imagePath);
            $image->blurImage($radius, $sigma, $channel);
            $image->writeImage($tmpFullPath);

            // Schedule the file deletion when the script execution is finished
            register_shutdown_function(function() use ($tmpFullPath, $image) {
                $image->clear();
                $image->destroy();
                unlink($tmpFullPath);
            });

            return $tmpRelativePath; // return the path of the temporary file
        } catch (\ImagickException $e) {
            throw new \RuntimeException("Error blurring image: " . $e->getMessage(), 0, $e);
        }
    }

    /**
     * Add text to an image.
     * 
     * @param string $text The text to add to the image.
     * @param string $imagePath The path to the image file.
     * @param string $fontPath The path to the font file.
     * @param int $fontSize The font size.
     * @param int $x The x-coordinate of the text position.
     * @param int $y The y-coordinate of the text position.
     * @param string $color The color of the text.
     * @throws ImagickException If an error occurs while adding the text to the image.
     */
    public function textToImage(string $text, string $imagePath, string $fontPath, int $fontSize, int $x, int $y, string $color = 'black') {
        $draw = new ImagickDraw();
        $draw->setFont($fontPath);
        $draw->setFontSize($fontSize);
        $draw->setFillColor($color);
        $draw->setGravity(Imagick::GRAVITY_NORTHWEST);
        $draw->annotation($x, $y, $text);

        $image = new Imagick($imagePath);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +44 to +45
$encrypted = openssl_encrypt($str, $method, $password, iv: $ivRaw);
return base64_encode($ivRaw . $encrypted);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

In the encryptwithpw method, when $iv is true, the encrypted string returned by openssl_encrypt is already base64-encoded by default (unless the OPENSSL_RAW_DATA option is used). Concatenating the raw IV bytes with a base64 string and then base64-encoding the result creates incorrect data. The decryptwithpw method expects raw bytes concatenated before base64 encoding.

This should use OPENSSL_RAW_DATA option to get raw encrypted bytes, then concatenate with the raw IV, then base64 encode:

$encrypted = openssl_encrypt($str, $method, $password, OPENSSL_RAW_DATA, $ivRaw);

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +74
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);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The decryptwithpw method needs to be consistent with the encryption. When $iv is provided as a parameter, the code should use OPENSSL_RAW_DATA for decryption to match the expected format. When auto-detecting embedded IV, it assumes raw bytes were concatenated before base64 encoding, but this won't work correctly if openssl_encrypt returns base64 by default.

Copilot uses AI. Check for mistakes.
Comment on lines +427 to +439
return $this->res($call["status"], $call["data"]);
$call_status = $call["status"];
$call_data = $call["data"];
if (is_string($call_data)) {
$call_data = clean($call_data);
}
if ($call_status == "ERROR") {
return res("ERROR", $call_data);
return $this->res("ERROR", $call_data);
}
if ($call_data["status"] == "ERROR") {
return res("ERROR", $call_data);
return $this->res("ERROR", $call_data);
}
return res($call_status, $call_data);
return $this->res($call_status, $call_data);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

Lines 428-439 are unreachable code. Line 427 returns early with return $this->res($call["status"], $call["data"]);, so all the subsequent logic that processes $call_status and $call_data will never execute. This appears to be dead code that should either be removed or the early return on line 427 should be removed if the additional processing is intended.

Copilot uses AI. Check for mistakes.
$call_status = $call["status"];
$call_data = $call["data"];
if (is_string($call_data)) {
$call_data = clean($call_data);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

On line 431, the call to clean() should be $this->clean($call_data) to call the instance method. However, this code is currently unreachable due to the early return on line 427.

Suggested change
$call_data = clean($call_data);
$call_data = $this->clean($call_data);

Copilot uses AI. Check for mistakes.
Comment on lines +45 to 47
$now = new \DateTime('now');
$then = new \DateTime($time);
$diff = $now->diff($then);
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

In the relativeTime method, the variable names $now and $then have been swapped compared to their intended semantics. Line 45 creates $now from the current time, and line 46 creates $then from the input $time parameter. However, the original code had $then = new DateTime('now') and $now = new DateTime($time), suggesting that $time (the parameter) represents the "now" point and we're calculating relative to it.

The current implementation calculates the diff from "now" to the past time in $time, which means:

  • If $time is in the past, the diff will be negative/inverted
  • The logic expects $time to be a past timestamp to show "X days ago"

The corrected semantics should be: calculate how long ago $time was from now. The swap is actually correct for this use case, but the variable names are confusing. Consider renaming for clarity or verifying the intended behavior with tests.

Suggested change
$now = new \DateTime('now');
$then = new \DateTime($time);
$diff = $now->diff($then);
$currentTime = new \DateTime('now');
$inputTime = new \DateTime($time);
$diff = $currentTime->diff($inputTime);

Copilot uses AI. Check for mistakes.
function sqlite_create_table(SQLite3 $db, string $table_name, array $columns = ["column_name" => "column_type"]) : array {
public function sqlite_create_table(\SQLite3 $db, string $table_name, array $columns = ["column_name" => "column_type"]) : array {
try {
if (sqlite_table_exists($db, $table_name)) {
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The call to sqlite_table_exists() on line 133 is missing the $this-> prefix. It should be $this->sqlite_table_exists($db, $table_name) to call the instance method. This will cause a fatal error when this function is invoked.

Suggested change
if (sqlite_table_exists($db, $table_name)) {
if ($this->sqlite_table_exists($db, $table_name)) {

Copilot uses AI. Check for mistakes.
function sqlite_select(SQLite3 $db, string $table, array $columns = ["*"], string $where = "", array $params = [], string $order = "", string $limit = "") : array {
public function sqlite_select(\SQLite3 $db, string $table, array $columns = ["*"], string $where = "", array $params = [], string $order = "", string $limit = "") : array {
try {
if (!sqlite_table_exists($db, $table)) {
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The call to sqlite_table_exists() on line 299 is also missing the $this-> prefix. It should be $this->sqlite_table_exists($db, $table) to call the instance method.

Suggested change
if (!sqlite_table_exists($db, $table)) {
if (!$this->sqlite_table_exists($db, $table)) {

Copilot uses AI. Check for mistakes.
return res($call_status, $call_data);
return $this->res($call_status, $call_data);

} catch (Exception $e) {
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

All catch blocks in SQLite.php catch Exception but should catch \Exception since the file uses declare(strict_types=1); and is in the PHPUtils namespace. Without the leading backslash, PHP will look for PHPUtils\Exception which doesn't exist. This affects lines 116, 145, 161, 177, 197, 223, 247, 280, 327, 368, 398, and 441.

Suggested change
} catch (Exception $e) {
} catch (\Exception $e) {

Copilot uses AI. Check for mistakes.
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, openssl
Copy link

Copilot AI Feb 3, 2026

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 mbstring and openssl extensions. However, the Images class requires the imagick extension (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.

Copilot uses AI. Check for mistakes.
@Darknetzz
Copy link
Owner Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Feb 6, 2026

@Darknetzz I've opened a new pull request, #28, to work on those changes. Once the pull request is ready, I'll request review from you.

@Darknetzz Darknetzz merged commit 6157205 into main Feb 6, 2026
7 of 12 checks passed
Darknetzz added a commit that referenced this pull request Feb 6, 2026
Merge pull request #27 from Darknetzz/dev
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants