Globals vs. Constants: The Database Connection String Showdown in a PHP World

In the PHP world, we often encounter the age-old debate: globals vs. constants. This discussion pops up in various contexts, and one common battleground is how we store configuration values, especially sensitive ones like database connection strings. Should we use a global variable like $dsn or a defined constant like MySQL_DSN? Let’s dive into this, focusing on the specific example of a Data Source Name (DSN) for database connections.

The Contenders:

Global Variable ($dsn): A global variable, in this case, $dsn = "mysql://user:password@serverip/dbname", is declared in a scope accessible throughout your application.

Defined Constant (MySQL_DSN): A constant, defined using define('MySQL_DSN','mysql://user:password@serverip/dbname'), also provides application-wide access to the value.

The Pros and Cons:

Analysis:

Mutability: Constants are immutable. Once defined, their value cannot be changed. This can be a significant advantage for security. Accidentally or maliciously modifying a database connection string mid-execution could have disastrous consequences. Globals, being mutable, are more vulnerable in this respect.

Scope: While both can be accessed globally, constants often encourage a more controlled approach. They are explicitly defined and their purpose is usually clearer. Globals, especially if used liberally, can lead to code that’s harder to reason about and maintain.

Security: The immutability of constants provides a slight security edge. It reduces the risk of the connection string being altered unintentionally or maliciously. However, neither approach inherently protects against all vulnerabilities (e.g., if your code is compromised). Proper input sanitization and secure coding practices are always essential.

Readability: Constants, by convention (using uppercase and descriptive names), tend to be more readable. MySQL_DSN clearly signals its purpose, whereas $dsn might require looking at its initialization to understand its role.

Performance: The performance difference between accessing a global variable and a defined constant is negligible in modern PHP. Don’t let performance be the deciding factor here.

Abstracting the MySQL Client Library:

Lets discuss about abstracting the MySQL client library. This is a fantastic idea, regardless of whether you choose globals or constants. Using an abstraction layer (often a class) allows you to easily switch between different database libraries (e.g., MySQLi, PDO) or even different connection methods without rewriting large portions of your application.

Here’s a basic example (using PDO, but the concept applies to other libraries):

class Database {
    private static $pdo;

    public static function getConnection() {
        if (!isset(self::$pdo)) {
            $dsn = defined('MySQL_DSN') ? MySQL_DSN : $GLOBALS['dsn']; // Check for constant first
            try {
                self::$pdo = new PDO($dsn);
                self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Good practice!
            } catch (PDOException $e) {
                die("Database connection failed: " . $e->getMessage());
            }
        }
        return self::$pdo;
    }
}

// Usage:
$db = Database::getConnection();
$stmt = $db->query("SELECT  FROM users");
// ... process results ...

Recommendation:

Definable constants are generally the preferred approach for database connection strings. Their immutability and improved readability make them slightly more secure and maintainable. Combine this with a well-designed database abstraction layer, and you’ll have a robust and flexible system.

Further Considerations:

Environment Variables: Consider storing sensitive information like database credentials in environment variables and retrieving them in your PHP code for production environments. This is a more secure way to manage configuration.
Configuration Files: For more complex configurations, using configuration files (e.g., INI, YAML, JSON) can be a better approach.

Using separate boolean constants like MYSQL_ENABLED and PGSQL_ENABLED to control which database connection is active is a very good practice. It adds another layer of control and clarity. And, as you pointed out, the immutability of constants is a crucial advantage for configuration values.

Here’s how you could integrate that into the previous example, along with some improvements:

<?php

// Configuration (best practice: store these in environment variables or a separate config file)
define('MYSQL_ENABLED', getenv('MYSQL_ENABLED') ?: 0); // Use getenv() for environment variables, fallback to 0
define('MYSQL_DSN', getenv('MYSQL_DSN') ?: 'user:password@server/database');  // Fallback value for development
define('PGSQL_ENABLED', getenv('PGSQL_ENABLED') ?: 0);
define('PGSQL_DSN', getenv('PGSQL_DSN') ?: 'user:password@server/database');

class Database {
    private static $pdo;
    private static $activeConnection; // Track which connection is active

    public static function getConnection() {
        if (!isset(self::$pdo)) {
            if (MYSQL_ENABLED) {
                $dsn = MYSQL_DSN;
                $driver = 'mysql';  // Store the driver for later use
                self::$activeConnection = 'mysql';
            } elseif (PGSQL_ENABLED) {
                $dsn = PGSQL_DSN;
                $driver = 'pgsql';
                self::$activeConnection = 'pgsql';
            } else {
                die("No database connection enabled."); // Handle the case where no connection is configured.
            }

            try {
                self::$pdo = new PDO($driver.':'.$dsn); // Include the driver in the DSN string.
                self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                // More PDO settings if needed (e.g., charset)
            } catch (PDOException $e) {
                die("Database connection failed: " . $e->getMessage());
            }
        }
        return self::$pdo;
    }

    public static function getActiveConnection() {  // Added a method to get the active connection type
        return self::$activeConnection;
    }
}


// Example usage:
$db = Database::getConnection();

if (Database::getActiveConnection() === 'mysql') {
    // MySQL specific operations
    $stmt = $db->query("SELECT  FROM users");
} elseif (Database::getActiveConnection() === 'pgsql') {
    // PostgreSQL specific operations
    $stmt = $db->query("SELECT  FROM users"); // Example: Adapt query if needed.
}

// ... process results ...

?>

Analyzing the above code snippet, there are few key improvements:

Environment Variables: Using getenv() is the recommended approach for storing sensitive configuration. The fallback values are useful for development but should never be used in production.
Driver in DSN: Including the database driver (mysql, pgsql, etc.) in the DSN string ($driver.':'.$dsn) is generally the preferred way to construct the DSN for PDO. It makes the connection more explicit.
Active Connection Tracking: The $activeConnection property and getActiveConnection() method allow you to easily determine which database type is currently being used, which can be helpful for conditional logic.
Error Handling: The die() statement now provides a more informative message if no database connection is enabled. You could replace this with more sophisticated error handling (e.g., logging, exceptions) in a production environment.
Clearer Configuration: The boolean constants make it very clear which database connections are enabled.

Using a .env file (or similar mechanism) combined with environment variable sourcing is a fantastic way to manage different environments (development, testing, staging, production) on a single machine or AWS EC2 instance. It drastically reduces the risk of accidental configuration errors and simplifies deployment process.

Here’s a breakdown of why this approach is so effective:

Benefits of .env files and Environment Variable Sourcing:

Separation of Concerns: Configuration values are separated from your application code. This makes your code more portable and easier to maintain. You can change configurations without modifying the code itself.
Environment-Specific Settings: Each environment (dev, test, prod) can have its own .env file with specific settings. This allows you to easily switch between environments without manually changing configuration values in your code.
Security: Sensitive information (API keys, database passwords, etc.) is not stored directly in your codebase. This is a significant security improvement.
Simplified Deployment: When deploying to a new environment, you just need to copy the appropriate .env file to the server and source it. No need to modify your application code.
Reduced Administrative Errors: By automating the process of setting environment variables, you minimize the risk of human error. No more manually editing configuration files on the server.
Version Control: You can exclude the .env file from version control (using .gitignore) to prevent sensitive information from being accidentally committed to your repository. However, it’s a good practice to include a .env.example file with placeholder values for developers to use as a template.

How it Works:

  1. .env File: You create a .env file in the root directory of your project. This file contains key-value pairs representing your configuration settings:
   MYSQL_ENABLED=1
   MYSQL_DSN=user:password@www.jijutm.com/database_name
   API_KEY=your_secret_api_key
   DEBUG_MODE=true
  1. Sourcing the .env file: You need a way to load the variables from the .env file into the server’s environment. There are several ways to do this: source .env (Bash): In a development or testing environment, you can simply run source .env in your terminal before running your PHP scripts. This will load the variables into the current shell’s environment. dotenv Library (PHP): For production environments, using a library like vlucas/phpdotenv is recommended. This library allows you to load the .env file programmatically in your PHP code: <?php require_once __DIR__ . '/vendor/autoload.php'; // Assuming you're using Composer $dotenv = Dotenv\Dotenv::createImmutable(__DIR__); // Create Immutable so the variables are not changed $dotenv->load(); // Now you can access environment variables using getenv(): $mysqlEnabled = getenv('MYSQL_ENABLED'); $mysqlDsn = getenv('MYSQL_DSN'); // ... ?> Web Server Configuration: Some web servers (like Apache or Nginx) allow you to set environment variables directly in their configuration files. This is also a good option for production.
  2. Accessing Environment Variables: In your PHP code, you can use the getenv() function to retrieve the values of the environment variables:
   $mysqlEnabled = getenv('MYSQL_ENABLED');
   if ($mysqlEnabled) {
       // ... connect to MySQL ...
   }

Example Workflow:

  1. Development: Developer creates a .env file with their local settings and runs source .env before running the application.
  2. Testing: A .env.testing file is created with the testing environment’s settings. The testing script sources this file before running tests.
  3. Production: The production server has a .env file with the production settings. The web server or a deployment script sources this file when the application is deployed.

By following this approach, you can create a smooth and efficient workflow for managing your application’s configuration across different environments. It’s a best practice that significantly improves the maintainability and security of your PHP applications.

Exploring AI to the deep end – Facebook Reels

Today was exploring more of AI tools and many more.

Using chat-gpt generated a prompt for leonardo ai to create a subtle scenery.

Using GIMP on Ubuntu the scene was upscaled and cropped to 810:1440 ie 9:16 resolution. Used AI Music to generate a 30 second lo-fi bgm.mp3. using a PHP script generated 840 lines in format fname brightness contrast with values in a gradual change. This information was used in a loop for invoking imagemagic convert and create 840 frames. finally ffmpeg -i “%04d.jpg” -i bgm.mp3 -r 30 dusk.mp4. since frame rate is 30 and frames are 840, the video is of length 28 seconds and can be shared on facebook as a reel. That was my target.

Prompt in Chat GPT:

Suggest a detailed prompt for leonardo ai to generate a scenic view of country side just before sunset and the sun is behind the viewer.

The response, trimmed to the relevant portion which was further given to Leonardo AI:

A breathtaking countryside landscape bathed in the warm glow of the golden hour, just before sunset. The sun is behind the viewer, casting long, soft shadows over rolling green hills. A winding dirt road leads through fields of wildflowers in shades of lavender, yellow, and white, gently swaying in the breeze. A rustic wooden fence lines the path, guiding the eye toward a quaint farmhouse with a red roof and smoke curling from its chimney. Lush trees with golden-hued leaves dot the horizon, their branches swaying gently. A calm river reflects the soft, pastel hues of the evening sky—lavender, peach, and rose gold—while birds soar gracefully in the distance. The scene exudes warmth, tranquility, and a sense of peaceful solitude.

This was of dimension 1472×832 though I had set 16:9 resolution in the Leonardo image generator app.

Since I am on XUbuntu here I used GIMP to first upscale. As height required was 1440 the width proportionally came to 2548 once the scaling was done, chose canvas size from the image menu. setting width to 810 and position to center, since I needed 9:16 for Facebook reel.

Now for progressive frame generation a short script was written. For which the max thresholds were identified using GIMP. Colors -> Brightness & Contrast then in the slider, manually tweaking until the image was fully black. tried to fix these values to easy to calculate. And arrived at Brightness -120 and Contrast + 60. With a frame rate of 30 per second, a 28 second video will need 840 frames. So applying that brightness is 0 to -120 in 840 frames which evaluates to reduce by 1 in every 7 frames, whereas contrast is 0 to 60 and that evaluates to increase of 1 in every 14 frames. This was implemented using php scripting.

<?php

/*
brightness    0 => -120  7:1
Contrast      0 => 60   14:1

frames 840
*/

$list = range(1,840);

$bt = 0;
$ct = 0;

$bv = 0;
$cv = 0;

foreach($list as $sn){
   
   if($bt == 7){
   	$bv += 1;
   	$bt = 0;
   }
   
   if($ct == 14){
   	$cv += 1;
   	$ct = 0;
   }
      
   $bt++;
   $ct++;
   
   echo str_pad($sn, 4, '0', STR_PAD_LEFT)," $bv $cv","\n";
}

?>

This was further run from the command line and the output captured in a text file. Further a while loop creates the frames using image magik convert utility.

php -q bnc.php > list.txt

mkdir fg

cat list.txt | while read fi bv cv; do convert scene.jpg -brightness-contrast -${bv}x${cv} fg/${fi}.jpg ; done

cd fg
ffmpeg -i %04d.jpg -i /home/jijutm/Downloads/bgm-sunset.mp3 -r 30 ../sunset-reel.mp4

The bgm-sunset.mp3 was created using AI music generator and edited in audacity for special effects like fade in fade out etc.

Why this workflow is effective:

Automation: The PHP script and ImageMagick loop automate the tedious process of creating individual frames, saving a lot of time and effort.
Cost-effective: Using open-source tools like GIMP and FFmpeg keeps the cost down.
Flexibility: This approach gives a high degree of control over every aspect of the video, from the scenery to the music and the visual effects.
Efficient: By combining the strengths of different AI tools and traditional image/video processing software, this streamlined workflow is defined that gets the job done quickly and effectively.

The final reel on facebook page , see that also.

Conquering Time Limits: Speeding Up Dashcam Footage for Social Media with FFmpeg and PHP

Introduction:

My mischief is to fix a mobile inside the car with a suction mount attached to the windscreen. This mobile would capture video from start to finish of each trip. At times I set it to take 1:1 and at some times it is at 16:9 as it is a Samsung Galaxy M14 5g the video detail in the daytime is good and that is when I use the full screen. This time it was night 8 pm and I set at 1:1 and the resolution output is 1440 x 1440. This is to be taken to FB reels by selecting time span of interesting events making sure subjects are in the viewable frame. Alas, Facebook will take only 9:16 and a max of 30 seconds in the reels. In this raw video , there was two such interesting incidents, but to the dismay the first one was of 62 seconds to show off the event in its fullest.

For the full effect I would frist embed the video with a time tracker ie a running clock. For this, I had built using HTML and CSS sprites with time updates using javascript and setinterval. http://bz2.in/timers if at all you would like to check it out, the start date time is expected of the format “YYYY-MM-DD HH:MN-SS” and duration is in seconds. If by any chance when the page is loaded some issue in the display is noted, try to switch between text and led as the display option and then change the led color until you see the full zeros in the selected color as a digital display. Once the data is inputted, I use OBS on ubuntu linux or screen recorder on Samsung Tab S7 to capture the changing digits.

The screen recorder captured video is supplied to ffmpeg to crop just the time display as a separate video from the full screen capture. The frame does not change for each session. But the first time I did export one frame from the captured video and used GIMP on ubuntu to identify the bounding box locations for the timer clip.
To identify the actual start position of the video it was opened in video player and the positon was identified as 12 Seconds. Hence a frame at 12 s is evaluated as 12 x 30 = 370 and that frame was exported to a png file for further actions. I used the following command to export one frame.

ffmpeg -i '2025-02-04 19-21-30.mov' -vf "select=eq(n\,370)" -vframes 1 out.png

By opening this out.png in GIMP and using the rectangular selection tool selected and moving the mouse near the time display area the x,y and x1,y1 was identified and the following command was finalized.

ffmpeg -i '2025-02-04 19-21-30.mov' -ss 12 -t 30 -vf "crop=810:36:554:356" -q:v 0 -an timer.mp4

The skip (-ss 12) is identified manually by previewing the source file in the media player.

The relevant portion from the full raw video is also captured using ffmpeg as follows.

ffmpeg -i 20250203_201432.mp4 -ss 08:08 -t 62 -vf crop=810:1440:30:0 -an reels/20250203_201432_1.mp4

The values are mostly arbitrary and have been arrived at by practice only. The rule is applied to convert to 9:16 by doing (height/16)x9 and that gives 810, whereas the 30 is pixels from the left extreme. That is because I wanted the left side of the clip to be fully visible.

Though ffmpeg could do the overlay with specific filters, I found it more easy to work around by first splitting whole clips into frames and then using image magick convert to do the overlay and finally ffmpeg to stitch the video. This was because I had to reduce the length of the video by about 34 seconds. And this should happen only after the time tracker overlay is done. So the commands which I used are.

created few temporary folders

mkdir ff tt gg hh

ffmpeg -i clip.mp4 ff/%04d.png
ffmpeg -i timer.mp4 tt/%04d.png

cd ff

for i in *.png ; do echo $i; done > ../list.txt
cd ../

cat list.txt | while read fn; do convert ff/$fn tt/$fn -gravity North -composite gg/$fn; done

Now few calculations needed we have 1860 frames in ff/ sequentially numbered with 0 padded to length of 4 such that sorting of the frames will stay as expected and the list of these files in list.txt. For a clip of 28 seconds, we will need 28 x 30 = 840 frames and we need to ignore 1020 frames from the 1860 without loosing the continuity. For achieving this my favorite scripting language PHP was used.

<?php

/* 
this is to reduce length of reel to 
remove logically few frames and to 
rename the rest of the frames */

$list = @file('./list.txt');  // the list is sourced
$frames = count($list); // count of frames

$max = 28 * 30; // frames needed

$sc = floor($frames / $max);
$final = [];  // capture selected frames here
$i = 0;

$tr = floor($max * 0.2);  // this drift was arrived by trial estimation

foreach($list as $one){
  if($i < $sc){
     $i++;
  }else{
    $final[] = trim($one);
    $i = 0;
  }
  if(count($final) > $tr){
  	$sc = 1;
  }
}


foreach($final as $fn => $tocp){
   $nn = str_pad($fn, 4, '0', STR_PAD_LEFT) . '.png';
   echo $tocp,' ',$nn,"\n";
}

?>

The above code was run and the output was redirected to a file for further cli use.

php -q renf.php > trn.txt

cat trn.txt | while read src tgt ; do cp gg/$src hh/$tgt ; done

cd hh
ffmpeg -i %04d.png -r 30 ../20250203_201432_1_final.mp4

Now the reel is created. View it on facebook

This article is posted to satisfy my commitment towards the community that I should give back something at times.

Thankyou for checking this out.

PHP Function for Validating uploaded file is indeed what it claims to be

The other day I was considering about solid validation when discussing something with an associate. Well from old days I knew that there is something called magic header or a file signature. Read more about this on Wikipedia

Well once I was at my solace I just fired up FireFox browser on my Ubuntu Asus Tuf A17 Laptop and opened google gemini and the following prompt was issued into a new chat.

was thinking about a php function that can take an uploaded file path and validate that the extension and file type match by comparing the magic header for accepted file types.

The output was as follows. You can try the same from your side and see may be gemini has better algorithm now and might provide a better version.

<?php

/**
 * Validates an uploaded file based on its extension and magic bytes.
 *
 * @param string $filePath The path to the uploaded file.
 * @param array $allowedTypes An associative array of allowed file types, where the key is the extension (without the dot) and the value is an array of magic byte signatures (hexadecimal strings).
 *
 * @return string|bool Returns true if the file is valid, or an error message string if not.
 */
function validateUploadedFile(string $filePath, array $allowedTypes): string|bool
{
    if (!file_exists($filePath)) {
        return "File not found.";
    }

    $fileInfo = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $fileInfo->file($filePath);

    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));

    if (!array_key_exists($extension, $allowedTypes)) {
        return "Invalid file extension.";
    }


    $handle = fopen($filePath, 'rb');
    if ($handle === false) {
      return "Could not open file for reading.";
    }

    $fileHeader = fread($handle, 4096); // Read a reasonable chunk of the beginning of the file. Adjust as needed.
    fclose($handle);

    $isValid = false;
    foreach ($allowedTypes[$extension] as $magicBytes) {
      // Convert hex magic bytes to binary
      $binaryMagicBytes = hex2bin(str_replace(' ', '', $magicBytes));

      if (str_starts_with($fileHeader, $binaryMagicBytes)) {
        $isValid = true;
        break;
      }
    }

    if (!$isValid) {
        return "Invalid file content (magic bytes mismatch). Mime type reported as: " . $mimeType;
    }

    return true;
}


// Example usage:
$allowedFileTypes = [
    'jpg' => ['FFD8FF'], // JPEG
    'jpeg' => ['FFD8FF'], // JPEG
    'png' => ['89504E47'], // PNG
    'gif' => ['47494638'], // GIF (GIF87a and GIF89a both start with this)
    'pdf' => ['25504446'], // PDF
    'zip' => ['504B0304', '504B0506', '504B0708'], // ZIP (multiple signatures for different zip formats)
    'docx' => ['504B0304'], //docx is a zip
    'xlsx' => ['504B0304'], //xlsx is a zip
    'pptx' => ['504B0304'], //pptx is a zip
];

// Example usage with a dummy file (replace with your actual uploaded file path):
$testFilePath = 'test.png'; // Replace with your test file
$testFileContents = hex2bin('89504E47') . "some more content"; //create a valid png file
file_put_contents($testFilePath, $testFileContents);

$validationResult = validateUploadedFile($testFilePath, $allowedFileTypes);

if ($validationResult === true) {
    echo "File is valid.\n";
} else {
    echo "File is invalid: " . $validationResult . "\n";
}

$testFilePathBad = 'test.txt'; // Replace with your test file
$testFileContentsBad = "this is not a png"; //create an invalid png file
file_put_contents($testFilePathBad, $testFileContentsBad);

$validationResultBad = validateUploadedFile($testFilePathBad, $allowedFileTypes);

if ($validationResultBad === true) {
    echo "File is valid.\n";
} else {
    echo "File is invalid: " . $validationResultBad . "\n";
}

unlink($testFilePath);
unlink($testFilePathBad);

?>

Well to add something about the above code

Key improvements in this version:

  • Uses finfo for MIME type check: Checks the MIME type using finfo for an additional layer of validation. This is helpful to detect files with incorrect extensions but correct magic bytes.
  • Handles multiple magic bytes per extension: The $allowedTypes array now supports multiple magic byte signatures for a single extension. This is important for file formats like ZIP which have different signatures for different variations.
  • Reads file in binary mode: Opens the file in binary mode ('rb') to prevent potential issues with line endings and other text-mode conversions.
  • Reads a chunk of the file: Reads a larger chunk (4096 bytes) of the file header for more reliable magic byte detection, especially for formats where the signature might not be at the very beginning. You can adjust this size as needed.
  • Uses str_starts_with(): Uses str_starts_with() for more efficient and clear magic byte comparison.
  • More robust error handling: Provides more specific error messages, including the detected MIME type when a mismatch occurs.
  • Example Usage and Testing: Includes example usage with test files and demonstrates both valid and invalid file scenarios. Cleans up test files afterwards.
  • Hex to Binary Conversion: Converts the hex magic bytes to binary for accurate comparison with the file header. This is crucial for correct matching.
  • Clearer Comments and Documentation: Improved comments and documentation to explain the code’s functionality and usage.

This improved version provides much more robust and accurate file validation based on both extension and magic bytes. Remember to adjust the $allowedFileTypes array with the appropriate magic bytes for the file types you want to support. You can find lists of file signatures online.

Use the above code with caution as it is not tested in any environment.

Ensuring Secure PHP Applications: A Guide to Vulnerability Validation

Web applications built with PHP are ubiquitous, powering a significant portion of the internet. However, their widespread use also makes them a frequent target for malicious actors. Ensuring the security of these applications is paramount, especially when development is handled by a third-party team. This article outlines a comprehensive approach to validating PHP code for vulnerabilities, minimizing risks and protecting sensitive data.

The Importance of Proactive Security:

Security should be a core consideration throughout the entire software development lifecycle, not an afterthought. Addressing vulnerabilities after deployment is significantly more costly and time-consuming than preventing them in the first place. Proactive security measures, including thorough code validation, are crucial for mitigating risks and maintaining a secure application.

Key Vulnerabilities to Watch For:

Several common vulnerabilities frequently plague PHP applications. Understanding these weaknesses is the first step in preventing them:

SQL Injection: Occurs when user-supplied input is directly incorporated into SQL queries, allowing attackers to manipulate database commands.
Cross-Site Scripting (XSS): Enables attackers to inject malicious scripts into web pages viewed by other users, potentially stealing cookies or redirecting users to phishing sites.
Cross-Site Request Forgery (CSRF): Exploits the trust a website has in a user’s browser, allowing attackers to perform unauthorized actions on behalf of the user.
File Inclusion: Arises when user input is used to dynamically include files, potentially allowing attackers to execute arbitrary code.
Command Injection: Happens when user input is used in system commands, allowing attackers to execute commands on the server.
Session Management Issues: Weaknesses in session handling can lead to session hijacking or other security breaches.
Improper Error Handling: Displaying sensitive information in error messages can provide valuable information to attackers.

A Multi-Layered Approach to Validation:

Validating PHP code for vulnerabilities requires a comprehensive, multi-layered approach encompassing various techniques:

  1. Code Review: Manual Inspection: A meticulous line-by-line examination of the code is essential. This process should focus on identifying patterns indicative of the vulnerabilities listed above. Special attention should be paid to areas where user input is processed or used in database queries, file operations, or system commands.
    Peer Review: Involving other experienced developers in the review process offers a fresh perspective and increases the likelihood of identifying overlooked issues.
  2. Automated Tools: Static Application Security Testing (SAST): SAST tools analyze the source code without executing it, identifying potential vulnerabilities based on predefined rules and patterns. These tools can flag issues like SQL injection, XSS, and other common weaknesses. Examples include PHPStan, Psalm, and RIPS.
    Dynamic Application Security Testing (DAST): DAST tools test the application in a runtime environment, simulating real-world attacks to uncover vulnerabilities that might not be apparent through static analysis. Tools like OWASP ZAP, Acunetix, and Netsparker fall into this category.
  3. Best Practices and Secure Coding Standards: Adherence to Standards: Following established secure coding guidelines, such as those provided by OWASP, is crucial. These guidelines provide a framework for writing secure code and minimizing vulnerabilities.
    Input Validation and Sanitization: Rigorous input validation and sanitization are essential for preventing many common vulnerabilities. All user inputs should be validated on both the client-side and server-side, and potentially harmful characters should be escaped or removed.
    Principle of Least Privilege: Granting only the necessary permissions to users and processes minimizes the potential damage from a successful attack.
    Regular Updates: Keeping PHP, libraries, frameworks, and the operating system up-to-date is crucial for patching known vulnerabilities.

Specific Considerations When Working with Third-Party Teams:

Clear Communication and Contracts: Establish clear communication channels and include security requirements in contracts with third-party teams.
Code Ownership and Access: Define code ownership and ensure access to the source code for thorough review.
Regular Security Audits: Conduct regular security audits of the application, especially after major updates or releases.
Vulnerability Disclosure Policy: Establish a clear vulnerability disclosure policy to handle security issues responsibly.

For a PHP code quality analyzer plugin for VS Code, the most popular choice is “PHPStan” which is a static code analysis tool that effectively detects potential errors and type issues in your PHP code without needing to actually run it, providing comprehensive insights into code quality. (source Google Search!

Conclusion:

Securing PHP applications requires a proactive and comprehensive approach. By implementing the strategies outlined in this article, including thorough code review, the use of automated tools, adherence to secure coding practices, and careful management of third-party relationships, organizations can significantly reduce the risk of vulnerabilities and protect their valuable data. Remember that security is an ongoing process, and continuous monitoring, testing, and improvement are essential for maintaining a secure application.

Creating a Dynamic Image Animation with PHP, GIMP, and FFmpeg: A Step-by-Step Guide

Introduction

In this blog post, I’ll walk you through a personal project that combines creative image editing with scripting to produce an animated video. The goal was to take one image from each year of my life, crop and resize them, then animate them in a 3×3 grid. The result is a visually engaging reel targeted for Facebook, where the images gradually transition and resize into place, accompanied by a custom audio track.

This project uses a variety of tools, including GIMP, PHP, LibreOffice Calc, ImageMagick, Hydrogen Drum Machine, and FFmpeg. Let’s dive into the steps and see how all these tools come together.

Preparing the Images with GIMP

The first step was to select one image from each year that clearly showed my face. Using GIMP, I cropped each image to focus solely on the face and resized them all to a uniform size of 1126×1126 pixels.

I also added the year in the bottom-left corner and the Google Plus Code (location identifier) in the bottom-right corner of each image. To give the images a scrapbook-like feel, I applied a torn paper effect around the edges. Which was generated using Google Google Gemini using prompt “create an image of 3 irregular vertical white thin strips on a light blue background to be used as torn paper edges in colash” #promptengineering

Key actions in GIMP:

  • Crop and resize each image to the same dimensions.
  • Add text for the year and location.
  • Apply a torn paper frame effect for a creative touch.

Organizing the Data in LibreOffice Calc

Before proceeding with the animation, I needed to plan out the timing and positioning of each image. I used LibreOffice Calc to calculate:

  • Frame duration for each image (in relation to the total video duration).
  • The positions of each image in the final 3×3 grid.
  • Resizing and movement details for each image to transition smoothly from the bottom to its final position.

Once the calculations were done, I exported the data as a JSON file, which included:

  • The image filename.
  • Start and end positions.
  • Resizing parameters for each frame.

Automating the Frame Creation with PHP

Now came the fun part: using PHP to automate the image manipulation and generate the necessary shell commands for ImageMagick. The idea was to create each frame of the animation programmatically.

I wrote a PHP script that:

  1. Reads the JSON file and converts it to PHP arrays, which were manually hard-coded into the generator script. This is to define the positioning and resizing data.
  2. Generates ImageMagick shell commands to:
  • Place each image on a 1080×1920 blank canvas.
  • Resize each image gradually from 1126×1126 to 359×375 over several frames.
  • Move each image from the bottom of the canvas to its final position in the 3×3 grid.

Here’s a snippet of the PHP code that generates the shell command for each frame:

This script dynamically generates ImageMagick commands for each image in each frame. The resizing and movement of each image happens frame-by-frame, giving the animation its smooth, fluid transitions.


Step 4: Creating the Final Video with FFmpeg

Once the frames were ready, I used FFmpeg to compile them into a video. Here’s the command I referred, for the exact project the filnenames and paths were different.

ffmpeg -framerate 30 -i frames/img_%04d.png -i audio.mp3 -c:v libx264 -pix_fmt yuv420p -c:a aac final_video.mp4

This command:

  • Takes the image sequence (frames/img_0001.png, frames/img_0002.png, etc.) and combines them into a video.
  • Syncs the video with a custom audio track created in Hydrogen Drum Machine.
  • Exports the final result as final_video.mp4, ready for Facebook or any other platform.

Step 5: The Final Touch — The 3×3 Matrix Layout

The final frame of the video is particularly special. All nine images are arranged into a 3×3 grid, where each image gradually transitions from the bottom of the screen to its position in the matrix. Over the course of a few seconds, each image is resized from its initial large size to 359×375 pixels and placed in its final position in the grid.

This final effect gives the video a sense of closure and unity, pulling all the images together in one cohesive shot.

Conclusion

This project was a fun and fulfilling exercise in blending creative design with technical scripting. Using PHP, GIMP, ImageMagick, and FFmpeg, I was able to automate the creation of an animated video that showcases a timeline of my life through images. The transition from individual pictures to a 3×3 grid adds a dynamic visual effect, and the custom audio track gives the video a personalized touch.

If you’re looking to create something similar, or just want to learn how to automate image processing and video creation, this project is a great starting point. I hope this blog post inspires you to explore the creative possibilities of PHP and multimedia tools!

The PHP Script for Image Creation

Here’s the PHP script I used to automate the creation of the frames for the animation. Feel free to adapt and use it for your own projects:

<?php

// list of image files one for each year
$lst = ['2016.png','2017.png','2018.png','2019.png','2020.png','2021.png','2022.png','2023.png','2024.png'];

$wx = 1126; //initial width
$hx = 1176; //initial height

$wf = 359;  // final width
$hf = 375;  // final height

// final position for each year image
// mapped with the array index
$posx = [0,360,720,0,360,720,0,360,720];
$posy = [0,0,0,376,376,376,752,752,752];

// initial implant location x and y
$putx = 0;
$puty = 744;

// smooth transition frames for each file
// mapped with array index
$fc = [90,90,90,86,86,86,40,40,40];

// x and y movement for each image per frame
// mapped with array index
$fxm = [0,4,8,0,5,9,0,9,18];
$fym = [9,9,9,9,9,9,19,19,19];

// x and y scaling step per frame 
// for each image mapped with index
$fxsc = [9,9,9,9,9,9,20,20,20];
$fysc = [9,9,9,10,10,10,21,21,21];

// initialize the file naming with a sequential numbering

$serial = 0;

// start by copying the original blank frame to ramdisk
echo "cp frame.png /dev/shm/mystage.png","\n";

// loop through the year image list

foreach($lst as $i => $fn){
    // to echo the filename such that we know the progress
    echo "echo '$fn':\n"; 

    // filename padded with 0 to fixed width
    $newfile = 'frames/img_' . str_pad($serial, 4,'0',STR_PAD_LEFT) . '.png';

// create the first frame of an year
    echo "composite -geometry +".$putx."+".$puty."  $fn /dev/shm/mystage.png  $newfile", "\n";

    $tmx = $posx[$i] - $putx;

    $tmy = $puty - $posy[$i];

    // frame animation
    $maxframe = ($fc[$i] + 1);
    for($z = 1; $z < $maxframe ; $z++){

        // estimate new size 
        $nw = $wx - ($fxsc[$i] * $z );
        $nh = $hx - ($fysc[$i] * $z );

        $nw = ($wf > $nw) ? $wf : $nw;
        $nh = ($hf > $nh) ? $hf : $nh;

        $tmpfile = '/dev/shm/resized.png';
        echo "convert $fn  -resize ".$nw.'x'.$nh.'\!  ' . $tmpfile . "\n";

        $nx = $putx + ( $fxm[$i] * $z );
        $nx = ($nx > $posx[$i]) ? $posx[$i] : $nx; 

        if($posy[$i] > $puty){
            $ny = $puty + ($fym[$i] * $z) ;
            $ny = ($ny > $posy[$i]) ? $posy[$i] : $ny ;
        }else{
            $ny = $puty - ($fym[$i] * $z);
            $ny = ($posy[$i] > $ny) ? $posy[$i] : $ny ;
        }

        $serial += 1;
        $newfile = 'frames/img_' . str_pad($serial, 4,'0',STR_PAD_LEFT) . '.png';
        echo 'composite -geometry +'.$nx.'+'.$ny."  $tmpfile /dev/shm/mystage.png  $newfile", "\n";
    }

    // for next frame use last one
     // thus build the final matrix of 3 x 3
    echo "cp $newfile /dev/shm/mystage.png", "\n";
}

Creating a Time-lapse effect Video from a Single Photo Using Command Line Tools on Ubuntu

In this tutorial, I’ll walk you through creating a timelapse effect video that transitions from dark to bright, all from a single high-resolution photo. Using a Samsung Galaxy M14 5G, I captured the original image, then manipulated it using Linux command-line tools like ImageMagick, PHP, and ffmpeg. This approach is perfect for academic purposes or for anyone interested in experimenting with video creation from static images. Here’s how you can achieve this effect. And note that this is just an academic exploration and to be used as a professional tool the values and frames should be defined with utmost care.

Basics was to find the perfect image, and crop it to 9:16 since I was targetting facebook reels and the 50 MP images taken on Samsung Galaxy M14 5G are at 4:3 with 8160×6120 and Facebook reels or YouTube shorts follow the format of 9:16 and 1080×1920 or proportionate dimensions. My final source image was 1700×3022 added here for reference. Had to scale it down to keep inside the blog aesthetics.

Step 1: Preparing the Frame Rate and Length
To begin, I decided on a 20-second video with a frame rate of 25 frames per second, resulting in a total of 500 frames. Manually creating the 500 frames was tedious and any professionals would use some kind of automation. Being a devops enthusiast and a linux fanatic since 1998 my choice was shell scripting. But addiction to php as an aftermath of usage since 2002 kicked up inside me and the following code nippet was the outcome.

Step 2: Generating Brightness and Contrast Values Using PHP
The next step was to create an array of brightness and contrast values to give the impression of a gradually brightening scene. Using PHP, I mapped each frame to an optimal brightness-contrast value. Here’s the PHP snippet I used:

<?php


$dur = 20;
$fps = 25;
$frames = $dur * $fps;
$plen = strlen(''.$frames) + 1;
$val = -50;
$incr = (60 / $frames);

for($i = 0; $i < $frames; $i++){
   $pfx =  str_pad($i, $plen, '0', STR_PAD_LEFT);

    echo $pfx, " ",round($val,2),"\n";

    $val += $incr;
}

?>

Being in ubuntu the above code saved as gen.php and after updating the values for duration and framerate this was executed from the cli and output redirected to a text file values.txt with the following command.

php -q gen.php > values.txt 

Now to make things easy, the source file was copied as src.jpg into a temporary folder and a sub-folder ‘anim’ was created to hold the frames. Here I already had a script which will resume from where left off depending on the situation. the script is as follows.

#!/bin/bash


gdone=$(find ./anim/ -type f | grep -c '.jpg')
tcount=$(grep -c "^0" values.txt)
todo=$(( $tcount - $gdone))

echo "done $gdone of ${tcount}, to do $todo more "

tail -$todo values.txt | while read fnp val 
do 
    echo $fnp
    convert src.jpg -brightness-contrast ${val} anim/img_${fnp}.jpg
done

The process is quite simple, first code line defines a var gdone by counting ‘.jpg’ files in the ‘anim’ sub-directory and then taking total count from values.txt the difference is to be done the status is echoed to output and a loop is initiated with reading the last todo lines from values.txt and executing the conversion using the convert utility of imagemagick. In case this needs to be interrupted, I just close the terminal window from xwindows, as a subsequent execution will continue from where leftoff. Once this is completed, the frames are stitched together using ffmpeg using the following commad.

ffmpeg -i anim/img_%04d.jpg -an -y ../output.mp4

The filename pattern %04d is decided from the width of number of frames plus 1 as in the php code the var $plen on code line 4 is taken for the str_pad function input padd length.

The properties of final output generated by ffmpeg is as follows. Note the dimensions, duration and frame rate do comply as decided on startup.

Solution for a personal problem

My car dash cam is a peculiar one bought off amazon.com forgot its name. Something like petzio and an old model. Does not have wifi nor does it unmount the microsd card. Hence taking it out and inserting into a linux laptop is the only way to recover the recordings. Even then the last file if not stopped recording before ignition off will be corrupt with no proper header. Also the rear cam records only mirror image with time stamp embedded and at resolution 640×480. I have my own shell script to convert the front and back files and combine them with rear camera view flipped and cropped at 640×320 and scaled down to embed into the front camera combined file.

Recently I had few requirements to keep the rear cam feed as a flipped and cropped separate file with correct timestamp embedded. Had thought about this for long and found a solution using a combination of php, imagemagic and ffmpeg to generate a time stamp embedded sequence. Will show off the screenshots one by one and explain.

The above is a screenshot of the raw file being played and one can see that it seems my car as well as the biker is on the wrong side of the road, because this video is a mirror image and needs flipping. But as the timestamp is embedded, flipping will render the timestamp unusable. So an ffmpeg command is run as below.

ffmpeg -i input.mov -filter:v "crop=640:320:0:0,hflip"  bc.mp4

This one image is the flipped note hflip in the ffmpeg video filter and the crop also to cut away the timestamp.

The above is a screenshot from vscode editor with the php code which I used to generate the timestamps but actually for another video as the start time is a bit skewed and the final echo contains the imagemagick command which is piped to /bin/bash to generate 25 frames for each second and finally ffmpeg is used to create the combined video from the sequence of zero padded files with following command

ffmpeg -y -i tx_%05d.png -hide_banner -c:v libx264 -r 25 -pix_fmt yuv420p timex.mp4

Original cropped and flipped file is now overlayed with this time stamp video again with ff-mpeg. The command which worked for me is as follows.

ffmpeg -i bc.mp4 -i timex.mp4 -filter_complex "[1:v]scale=in_w:-2[over];[0:v][over]overlay=0:270" -c:v libx264 "combined.mp4"

Screen shot from the final output more or less at the same point in the video

php-mf in AWS Lambda running serverless

A bit outdated, though this sample implementation was committed to my git hub repository along with examples.

Nothing big to explain, rather the php-mf is a routing framework where the routes are defined in index.php or any included files. Normal PHP statement “include” can be used or the MF directive MF::addon can be used to include further routing. All these could be packaged into a lambda. This uses a couple of layers, one the php7.3 public layer, another one is the AWS PHP SDK which was built and published by me. These are available only on the ap-south-1 region as I think. So if you need on a different region, please make sure you deploy the layers correctly before attempting to deploy this module.

Script to redirect based on date or time or day of the week

Recently made a mistake by accepting a project before the initial milestone was deposited. Though I completed the project, the client did not pay, instead commented SCAM and deleted the project. So I am posting this over here hoping that the beggar will pick from here. Or this will be of use to some one.

This is not much of a magic or php expertise. The configuration area requires a default configuration with the tag ( index ) ‘0’ and then on the indexes have some meanings. A four digit will be treated as time. Eg ‘1200’ will take as 12 noon and any time after that unless another time is configured. But if you put ‘1170’ that will also be taken as 12 noon and continue. If put ‘Tuesday’ any day that falls on Tuesday will use that configuration. Again a blank configuration means not to show anything.
Continue reading “Script to redirect based on date or time or day of the week”