How to Trace PHP Scripts Sending Emails in Apache Without Mod_SuPHP or Suexec


2 views

When debugging email-sending functionality in a standard Apache/PHP environment (without mod_suphp or suexec), identifying the exact PHP script responsible for sending emails can be challenging. The mail logs typically only show the UID (usually 'apache' user) without revealing the originating script path.

Here are several approaches to pinpoint the problematic script:

1. Mail Header Injection

Modify your mail() function calls to include identifiable headers:


// Add this to your mail sending code temporarily
$headers = "X-Script-Location: " . __FILE__ . "\r\n";
mail($to, $subject, $message, $headers);

This will appear in the email headers when received.

2. Custom Logging Wrapper

Create a wrapper function for mail() that logs script information:


function logged_mail($to, $subject, $message, $additional_headers = '', $additional_parameters = '') {
    $log_entry = date('Y-m-d H:i:s') . " - Script: " . __FILE__ . "\n";
    $log_entry .= "From IP: " . $_SERVER['REMOTE_ADDR'] . "\n";
    file_put_contents('/path/to/mail.log', $log_entry, FILE_APPEND);
    return mail($to, $subject, $message, $additional_headers, $additional_parameters);
}

3. Process Monitoring

Use strace to monitor PHP processes in real-time:


# Run this command as root
strace -f -p $(pgrep -u apache php) -e trace=execve,write 2>&1 | grep -i mail

PHP Function Overriding

Override the mail() function temporarily using runkit:


runkit_function_redefine('mail', '$to, $subject, $message, $additional_headers, $additional_parameters', 
    'error_log("Mail sent from: ".__FILE__." to $to with subject: $subject"); 
    return mail($to, $subject, $message, $additional_headers, $additional_parameters);');

SMTP Log Analysis

If using SMTP (like PHPMailer), configure logging:


$mail = new PHPMailer(true);
$mail->SMTPDebug = SMTP::DEBUG_CONNECTION;
$mail->Debugoutput = function($str, $level) {
    file_put_contents('/path/to/smtp.log', "$level: $str\n", FILE_APPEND);
};
  • Implement centralized mail sending through a single class/function
  • Use proper authentication for mail sending scripts
  • Regularly audit scripts with mail functionality
  • Consider using queue systems for better tracking

When working with a standard Apache+PHP setup (without suEXEC or mod_suphp), identifying which PHP script is sending emails can be frustrating. The mail logs typically only show the Apache user (usually 'www-data' or 'apache') as the sender, making it impossible to trace back to the specific script.

Here are several approaches to track email-sending scripts:

1. Custom Mail Wrapper Function

Create a centralized mail function that logs script details:


function logged_mail($to, $subject, $message, $headers = '') {
    $backtrace = debug_backtrace();
    $caller = $backtrace[0];
    $log = sprintf(
        "[%s] Mail sent by %s (line %d)\n",
        date('Y-m-d H:i:s'),
        $caller['file'],
        $caller['line']
    );
    file_put_contents('/var/log/php_mail.log', $log, FILE_APPEND);
    return mail($to, $subject, $message, $headers);
}

2. PHP open_basedir and Error Logging

Configure PHP to log script execution:


// In php.ini
open_basedir = /var/www/example.com
log_errors = On
error_log = /var/log/php_errors.log

3. Apache Custom Log Format

Modify your Apache configuration to include PHP script information:


LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{SCRIPT_FILENAME}e" combined_with_script
CustomLog /var/log/apache2/access_with_script.log combined_with_script

Using PHP's register_shutdown_function

Track emails by examining the call stack at shutdown:


register_shutdown_function(function() {
    $emails_sent = count(get_defined_vars()['__mail_queue'] ?? []);
    if ($emails_sent > 0) {
        error_log("Script ".__FILE__." sent $emails_sent emails");
    }
});

X-PHP-Script Header Injection

Add script identification to email headers:


$headers .= "X-PHP-Script: ".__FILE__."\r\n";
mail($to, $subject, $message, $headers);

Consider these architectural improvements:

  • Implement a centralized mail service class
  • Use dependency injection for mail functionality
  • Implement rate limiting for emails
  • Create middleware for mail monitoring