Deep Tech Point
first stop in your tech adventure

PHP hook function

January 28, 2021 | PHP

You might get into a situation where you need to hook some PHP function. There are many reasons why you might need to do that. One of the most obvious cases is debugging. In PHP it is really easy to hook any function using override_function which overrides built-in functions. However, these simple “hacks” are practical only in conditions when you’re dealing with your own code or some relatively simple code you can change with ease.

In a more complex situation, like if you need to hook the PHP mail function without messing with some third-party source code you need to do it a bit differently.

You should know, it is possible to globally hook the PHP mail function for different reasons, and some of the most popular would be logging or filtering. If we take a look at logging purposes, the most optimal course of action would be activating the logging option in the PHP configuration file (usually php.ini). It is as simple as that – uncomment the mail.log line and add that path to the log file. Just like this:

mail.log = /var/log/php_mail.log

You should know that log entries incorporate the full path of the script, line number, “To:” address, and headers. In order to debug, we will have perfectly enough information to address potential problems. On the other hand, for mail filtering mail.log won’t be your solution. It just doesn’t answer your question from the title of this post – how to hook mail function. Hooking is usually defined in a way it gives the developer a choice to mess with the data if he needs to or to completely ‘choke’ the request in case some condition is met. And this is the exact thing you need for proper filtering, particularly when it’s not easy to wrap mail function with your own classes. Moreover, the hooking function gives the system admins the power to protect the system from malicious code, and in this tutorial, we will take a deeper look at the hooking of the PHP mail function. You should keep in mind that this function is far from being the only method for sending an email via PHP, so you really shouldn’t rely on this method, if you’re aiming at the final solution for monitoring your PHP scripts email activity. Keep in mind PHP scripts can access SMTP service directly and in that case, you will need to deploy different solutions for monitoring and filtering. However, you should get to know the hooking mail function, because it is one of the useful tools in the arsenal. Let’s look at how to do it. Don’t worry. It’s very simple. Because we’re hooking the PHP mail function, we will make a simple utility script in PHP. We could do the exact same thing in the bash scripting language, but when you get the idea of the process, the implementation itself will become irrelevant. The basic script:

#!/usr/bin/php

You should save the script in some directory, for example: /usr/local/bin/ with the name ‘sendmail_wrapper’. At this point, you’ve probably already sensed the rest of the solution. No worries, if you didn’t, I won’t keep you hanging. Here’s a short explanation because there’s one more step you need to implement to make sure the script does its work. Go open php.ini, PHP configuration, and find the line ‘sendmail_path’. Uncomment that line (if it’s commented) and write the name of your wrapper script, and don’t forget the full path. Reload PHP service.

While you were editing php.ini, do notice comments on the Sendmail command parameters because sometimes they differ on different Linux systems and if they do you need to edit the script accordingly.

This script equips a simple mail relay between PHP mail function and Sendmail service, (which is usually another relay to the real email service, like Postfix or Exim – nowadays nobody uses Sendmail any more), and it can be applied for logging mail function activity. You could also decide not to relay email if some condition is met. For example, you can filter out an email if you find it is going to a specific email address:

....

while ($mail_line = fgets($handle)) { 
    if (preg_match('/^to: some@email.com/i', $mail_line)) {
        return TRUE;
    }
    $mail .= $mail_line; 
} 
....

You could also modify the script to send alerts, make frequency caps, log some parts of an email when some condition occurs, remove ‘X-Php-Originating-Script’ header, and many other useful things. But more about this in later posts.