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, andfile_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. Theintegrity_hashes
database can then be updated with these hashes. Thearray_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) );
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(); }
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 files
valid()
- 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 name
key()
- Restart the loop
next()
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>
<?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(); }
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) );
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(); }
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>
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(); }
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!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

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

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

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,

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.

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.

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.

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.

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.

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.

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.
