2 posts tagged “php”
So a client asked me 10 minutes ago if I would mark it on my calendar to disable logins for their web site starting on December 7th, 2009. An easy thing to do when you know the fast and fun way of doing it.
Don't get me wrong, there are plenty of ways to manipulate dates (in PHP), but they seem too high maintenance. I didn't want to convert to unix time or worry about the mktime function when I just needed a quick and dirty solution that I could remember without reviewing syntax.
In other words, I wanted a date that I could manipulate fast! What did I do, I turned to strtotime().
<?php if (strtotime("now") >=strtotime("december 7, 2009")) {
$message="Sorry, the deadline for rewards redemption has passed.";
} ?>
So there you go. I like strtotime because you can use natural dates to do comparisons. Just my preference, but sure beats the alternatives in my opinion. Please comment if you have other cheap tricks for manipulating dates, I'm always interested.
When I set out to stop spammers from exploiting poorly written scripts scattered across various web sites hosted on a Windows server, I had no idea that I was in for such a long journey. I will try to lay out the steps I took in order to solve the problem, which I am happy to report is working well.
The Problem:
PHP as of 5.2.1 provides no way of tracking which script, or even which web site is the source of an email being delivered using PHP's mail() function. Because so many web applications use it, I didn't want to disable it. Furthermore, the idea of combing through all of the code on multiple sites was not intriguing. Furthermore, I can't change someone else's code and I don't want to start isolating customers by turning their scripts off.
The Platform:
Using a Windows 2003 Server and PHP 5.1.2, I thought this would be quick. Basically, the fix isn't that difficult, but finding the solution led me to many options for Linux / Apache, but few for Windows.
The Details:
I first discovered the option of patching mail.c, thanks to Ilia Alshanetsky's blog at http://ilia.ws/archives/149-mail-logging-for-PHP.html.
I wanted to provide similar functionality for Windows, but did not want to recompile PHP in a Windows environment. The patch added code so that every script sent from the server adds x-header information, such as the script and site sending it, as well as logging what goes out.
The Solution: (PHP Sendmail Wrapper Script + Fake Sendmail + php.ini)
I found a few other alternatives until finally deciding on a unique combination of tools to get the job done. First off, if you are not going to change users code, or patch and recompile the PHP source, you have to have some method of capturing the email leaving the web site, but before it gets to the mail server. In comes Sendmail Wrapper from Greg Maclellan (www.gregmaclellan.com)and Fake Sendmail from Byron Jones (http://glob.com.au/sendmail/.)
The Sendmail Wrapper PHP script is a great little script that will accept mail just as if it were sendmail and then deliver it to the real sendmail (or fake sendmail in my case). The clever part here is that you can specify this script as the default mail server in your PHP.INI file. For Windows, just disable the smtp port, host, etc.. and put c:\usr\lib\sendmail_wrapper.php as your path to sendmail. (Yes, specifying the sendmail path will work on Windows).
Setting up Sendmail for Windows was fairly straight forward. The executable sits in c:\usr\lib\sendmail and includes an ini file that lets you forward mail to your real SMTP server and specify a few other options, including a folder to log the messages. Sendmail simply captures the email piped to it from a script.
Putting the two together was fairly easy. I modified the sendmail wrapper script to use the path to sendmail and made sure fake sendmail was up and running. I also decided since I could let fake sendmail do authentication against an SMTP server to put an actual mail account on my mail server specifically for handling the mail processed via php and I added some limitations, one being a quota no more than 500 messages per day.
The final piece of the puzzle was getting PHP to add some extra headers beyond what the Sendmail Wrapper script was providing so I would really have some robust information. I decided to use Environment Variables and PHP's append directive in php.ini to set some variables up on each page. This idea is credited to
Harold Paulson who posted on Greg Maclellan's blog. I made a page called prepend.php and put in in my php append path (or prepend, you choose). I added the following information to mine, although you could really capture anything you wanted to add to the message header).
<?
putenv("REMOTE_ADDR=" . $_SERVER['REMOTE_ADDR']);
putenv("SCRIPT_NAME=" . $_SERVER['SCRIPT_NAME']);
putenv("SERVER_NAME=" . $_SERVER['SERVER_NAME']);
?>
Next, I made a modification to the sendmail_wrapper script to include this information in the headers of the mail.
// additional headers
$add_headers["X-MsgID"] = $messageid;
$add_headers["X-SenderIP"] = $_ENV["REMOTE_ADDR"];
$add_headers["X-WebSite"] = $_ENV["SERVER_NAME"];
$add_headers["X-Script"] = $_ENV["SCRIPT_NAME"];
I replaced the existing line (below) in the script with the above.
if (preg_match("|C:/Program Files/Plexus/Sites/([a-zA-Z0-9\._-]*)(/.*)?|", $_ENV["PWD"], $matches)) {
$add_headers["X-Generating-Domain"] = $matches[1];
}
A few tips on making this work:
Be certain you have assigned
permissions for the user that PHP is running as to have access to
execute this script. Also, I believe in PHP 5 you still need to make
sure cmd.exe has execute permissions to call the script. Finally, you
must execute it using php.exe the CLI (Command Line Interface), not
php-cgi.exe or the script will have trouble reading the STDIN input. If
you ran the PHP binary installer when you originally installed PHP,
head over to http://snaps.php.net/ and download the zip file, which will contain php.exe. Better yet, it might be a good day to upgrade anyway. Don't forget to restart IIS after you make the changes to php.ini.