Home Backend Development PHP Tutorial PHP Master | Monitoring File Integrity

PHP Master | Monitoring File Integrity

Mar 03, 2025 am 08:26 AM

PHP Master | Monitoring File Integrity

Key Points

  • Monitoring file integrity is essential for website management and helps detect when files are added, modified, deleted, or corrupted by maliciously. Hashing the contents of a file is a reliable way to monitor such changes.
  • PHP's hash_file() function can be used to create a file structure configuration file for monitoring. The hash value of each file can be stored for later comparisons to detect any changes.
  • You can set a database table to store the hash value of a file, where file_path stores the path of the file on the server, and file_hash stores the hash value of a file.
  • PHP's RecursiveDirectoryIterator class can be used to traverse the file tree and collect hashes for comparison. The integrity_hashes database can then be updated with these hashes. The array_diff_assoc() function of PHP can be used to check for differences, which helps identify files that have been added, deleted, or changed.

Collaborate on various situations in website management

Consider how to solve the following situations when managing a website:

  • Accidentally adding, modifying or deleting files
  • Maliciously add, modify or delete files
  • Files are corrupted

More importantly, do you know if one of these happens? If your answer is no, please continue reading. In this guide, I will demonstrate how to create a file structure configuration file that can be used to monitor file integrity.

The best way to determine if a file has been changed is to hash its contents. PHP provides multiple hash functions, but for this project, I decided to use the hash_file() function. It provides a variety of different hashing algorithms, which will make my code easy to modify if I decide to change it later. Hash is used in a variety of applications, from password protection to DNA sequencing. The hashing algorithm works by converting data into a fixed-size repeatable encrypted string. They are designed such that even slight modifications to the data should produce very different results. When two or more different data produce the same string result, it is called "conflict". The strength of each hashing algorithm can be measured by its speed and probability of collision. In my example, I will use the SHA-1 algorithm because it is fast, has low probability of conflict, and has been widely used and fully tested. Of course, you are welcome to research other algorithms and use any algorithm you like. After obtaining the hash value of the file, it can be stored for later comparison. If the file hashing later does not return the same hash string as before, then we know that the file has been changed.

Database

First, we need to layout a base table to store the hash value of the file. I will use the following pattern:

CREATE TABLE integrity_hashes (
    file_path VARCHAR(200) NOT NULL,
    file_hash CHAR(40) NOT NULL,
    PRIMARY KEY (file_path)
);
Copy after login
Copy after login

file_path The path to the file on the storage server, since the value is always unique (because two files cannot occupy the same location in the file system), it is our primary key. I specified its maximum length to 200 characters, which should allow some longer file paths. file_hash Stores the hash value of the file, which will be a SHA-1 40-character hexadecimal string.

Collect files

The next step is to build the configuration file for the file structure. We define the path to start collecting files and iterate over each directory recursively until we overwrite the entire branch of the file system and can optionally exclude certain directories or file extensions. We collect the required hash values ​​when it traversing the file tree and then store it in the database or for comparison. PHP provides several ways to traverse the file tree; for simplicity, I will use the RecursiveDirectoryIterator class.

<?php
define("PATH", "/var/www/");
$files = array();

// 要获取的扩展名,空数组将返回所有扩展名
$ext = array("php");

// 要忽略的目录,空数组将检查所有目录
$skip = array("logs", "logs/traffic");

// 构建配置文件
$dir = new RecursiveDirectoryIterator(PATH);
$iter = new RecursiveIteratorIterator($dir);
while ($iter->valid()) {
    // 跳过不需要的目录
    if (!$iter->isDot() && !in_array($iter->getSubPath(), $skip)) {
        // 获取特定文件扩展名
        if (!empty($ext)) {
            // PHP 5.3.4: if (in_array($iter->getExtension(), $ext)) {
            if (in_array(pathinfo($iter->key(), PATHINFO_EXTENSION), $ext)) {
                $files[$iter->key()] = hash_file("sha1", $iter->key());
            }
        } else {
            // 忽略文件扩展名
            $files[$iter->key()] = hash_file("sha1", $iter->key());
        }
    }
    $iter->next();
}
Copy after login
Copy after login

Note that I referenced the same folder twice in the $skip array. Just because I chose to ignore a specific directory doesn't mean that the iterator also ignores all subdirectors, depending on your needs, which can be useful or annoying. The logs class gives us access to multiple methods: RecursiveDirectoryIterator

  • Check if we are using valid filesvalid()
  • Determine whether the directory is "." or ".."isDot()
  • Return to the folder name where the file pointer is currently located getSubPath()
  • Return the full path and file namekey()
  • Restart the loopnext()
There are many more methods available, but most of the time the above listed are all the methods we need, although the

method was added in PHP 5.3.4, which returns the file extension. If your PHP version supports it, you can use it to filter unwanted entries instead of what I did with getExtension() . After execution, the code should fill the pathinfo() array with results similar to: $files

<code>Array
(
    [/var/www/test.php] => b6b7c28e513dac784925665b54088045cf9cbcd3
    [/var/www/sub/hello.php] => a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa
    [/var/www/sub/world.php] => da39a3ee5e6b4b0d3255bfef95601890afd80709
)</code>
Copy after login
Copy after login
After building the configuration file, it is very easy to update the database.

<?php
$db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
    DB_USER, DB_PASSWORD);

// 清除旧记录
$db->query("TRUNCATE integrity_hashes");

// 插入更新的记录
$sql = "INSERT INTO integrity_hashes (file_path, file_hash) VALUES (:path, :hash)";
$sth = $db->prepare($sql);
$sth->bindParam(":path", $path);
$sth->bindParam(":hash", $hash);
foreach ($files as $path => $hash) {
    $sth->execute();
}
Copy after login
Copy after login

Check the difference

You now know how to build a new configuration file for the directory structure and how to update records in the database. The next step is to combine it into some kind of real application, such as a cron job with email notifications, an admin interface, or anything else you like. If you just want to collect a list of changed files without caring how they change, the easiest way is to extract the data from the database into an array similar to

and use PHP's $files function to remove unwanted content. array_diff_assoc()

CREATE TABLE integrity_hashes (
    file_path VARCHAR(200) NOT NULL,
    file_hash CHAR(40) NOT NULL,
    PRIMARY KEY (file_path)
);
Copy after login
Copy after login

In this example, $diffs will be populated with any found differences, or if the file structure is complete, it will be an empty array. Unlike array_diff() , array_diff_assoc() will use the key in comparison, which is important when we conflict, such as two empty files have the same hash value. If you want to go a step further, you can add some simple logic to accurately determine how the file is affected, whether it is deleted, changed, or added.

<?php
define("PATH", "/var/www/");
$files = array();

// 要获取的扩展名,空数组将返回所有扩展名
$ext = array("php");

// 要忽略的目录,空数组将检查所有目录
$skip = array("logs", "logs/traffic");

// 构建配置文件
$dir = new RecursiveDirectoryIterator(PATH);
$iter = new RecursiveIteratorIterator($dir);
while ($iter->valid()) {
    // 跳过不需要的目录
    if (!$iter->isDot() && !in_array($iter->getSubPath(), $skip)) {
        // 获取特定文件扩展名
        if (!empty($ext)) {
            // PHP 5.3.4: if (in_array($iter->getExtension(), $ext)) {
            if (in_array(pathinfo($iter->key(), PATHINFO_EXTENSION), $ext)) {
                $files[$iter->key()] = hash_file("sha1", $iter->key());
            }
        } else {
            // 忽略文件扩展名
            $files[$iter->key()] = hash_file("sha1", $iter->key());
        }
    }
    $iter->next();
}
Copy after login
Copy after login

When we traverse the results in the database, we do multiple checks. First, use array_key_exists() to check if the file path in our database appears in $files, and if not, the file must have been deleted. Second, if the file exists but the hash does not match, the file must have been changed or not changed. We store each check into a temporary array called $tmp and finally, if the number in $files is greater than the number in the database, then we know that the remaining unchecked files have been added. Once done, $diffs is either an empty array or contains any differences found in the form of a multidimensional array, which might look like this:

<code>Array
(
    [/var/www/test.php] => b6b7c28e513dac784925665b54088045cf9cbcd3
    [/var/www/sub/hello.php] => a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa
    [/var/www/sub/world.php] => da39a3ee5e6b4b0d3255bfef95601890afd80709
)</code>
Copy after login
Copy after login

To display results in a more user-friendly format (such as the management interface), you can for example iterate over the results and output them as bulleted lists.

<?php
$db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
    DB_USER, DB_PASSWORD);

// 清除旧记录
$db->query("TRUNCATE integrity_hashes");

// 插入更新的记录
$sql = "INSERT INTO integrity_hashes (file_path, file_hash) VALUES (:path, :hash)";
$sth = $db->prepare($sql);
$sth->bindParam(":path", $path);
$sth->bindParam(":hash", $hash);
foreach ($files as $path => $hash) {
    $sth->execute();
}
Copy after login
Copy after login

At this point, you can provide a link to trigger the operation of updating the database with the new file structure (in which case you might choose to store $files in a session variable), or if you do not approve the differences, you can handle them as needed.

Summary

I hope this guide will help you better understand file integrity monitoring. Installing such content on your website is a valuable security measure and you can rest assured that your files will remain the same as you intend. Of course, don't forget to back up regularly. in case.

(The FAQ part of the original text should be retained here, because the content of this part has nothing to do with the code part, belongs to the supplementary description, and does not fall into the category of pseudo-originality)

The above is the detailed content of PHP Master | Monitoring File Integrity. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

What are Enumerations (Enums) in PHP 8.1? What are Enumerations (Enums) in PHP 8.1? Apr 03, 2025 am 12:05 AM

The enumeration function in PHP8.1 enhances the clarity and type safety of the code by defining named constants. 1) Enumerations can be integers, strings or objects, improving code readability and type safety. 2) Enumeration is based on class and supports object-oriented features such as traversal and reflection. 3) Enumeration can be used for comparison and assignment to ensure type safety. 4) Enumeration supports adding methods to implement complex logic. 5) Strict type checking and error handling can avoid common errors. 6) Enumeration reduces magic value and improves maintainability, but pay attention to performance optimization.

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

How does session hijacking work and how can you mitigate it in PHP? How does session hijacking work and how can you mitigate it in PHP? Apr 06, 2025 am 12:02 AM

Session hijacking can be achieved through the following steps: 1. Obtain the session ID, 2. Use the session ID, 3. Keep the session active. The methods to prevent session hijacking in PHP include: 1. Use the session_regenerate_id() function to regenerate the session ID, 2. Store session data through the database, 3. Ensure that all session data is transmitted through HTTPS.

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What is REST API design principles? What is REST API design principles? Apr 04, 2025 am 12:01 AM

RESTAPI design principles include resource definition, URI design, HTTP method usage, status code usage, version control, and HATEOAS. 1. Resources should be represented by nouns and maintained at a hierarchy. 2. HTTP methods should conform to their semantics, such as GET is used to obtain resources. 3. The status code should be used correctly, such as 404 means that the resource does not exist. 4. Version control can be implemented through URI or header. 5. HATEOAS boots client operations through links in response.

How do you handle exceptions effectively in PHP (try, catch, finally, throw)? How do you handle exceptions effectively in PHP (try, catch, finally, throw)? Apr 05, 2025 am 12:03 AM

In PHP, exception handling is achieved through the try, catch, finally, and throw keywords. 1) The try block surrounds the code that may throw exceptions; 2) The catch block handles exceptions; 3) Finally block ensures that the code is always executed; 4) throw is used to manually throw exceptions. These mechanisms help improve the robustness and maintainability of your code.

What are anonymous classes in PHP and when might you use them? What are anonymous classes in PHP and when might you use them? Apr 04, 2025 am 12:02 AM

The main function of anonymous classes in PHP is to create one-time objects. 1. Anonymous classes allow classes without names to be directly defined in the code, which is suitable for temporary requirements. 2. They can inherit classes or implement interfaces to increase flexibility. 3. Pay attention to performance and code readability when using it, and avoid repeatedly defining the same anonymous classes.

See all articles