Birthday reminder by mail

End of november 2000 I published my first freeware program, RealDreams birthday reminder. I wrote it in C++ on Windows using Visual Studio. It was postcard-ware; I asked people to send me a postcard if they liked it. All in all I got about 400 postcards from all parts of the world :)

It had a loyal user base, got translations for half a dozen languages and I made beta tests by sending new versions by e-mail to interested users..

In 2003 I switched to Linux and had to use Wine to keep birthday reminder running. I wrote birthday reminder 3, this time in Java - it ran on my computers, my parent's Mac and other people's windows boxes. Unfortunately, it never reached the full functionality of its predecessor and thus stayed at version 2.95.

birthday reminder was made to run whenever you startup your computer; an event that I rarely do since 2006. Close the lid - the computer sleeps. Open it, it's awake. With rare startups, birthday reminder was invoked very seldomly, losing its usefulness.

bdrem

The only thing I regularly do is - apart from using the terminal - to check my mails. birthday reminder by e-mail was born.

Since I use an LDAP address book, a LDAP source driver was added. At work we use a proprietary CRM, so I added a generic SQL driver to be able to get reminders about our customer's birthdays.

bdrem is able to send emails. For text-only mail clients an ASCII table with upcoming events is included, generated with Console_Table. Mails also contain a colorful HTML table. The MIME mail is composed with Mail_mime.

bdrem HTML output

.phar

bdrem is distributed as a .phar file, containing all dependencies. No need to install anything; just run

$ php bdrem.phar

In 2011 I wrote about working with .phar files, and now I did actually use ideas from that blog post:

$ php bdrem.phar --help
Show help
$ php bdrem.phar config
Extract default configuration file
$ php bdrem.phar readme
Show README

Dependencies

I use phing to automatically build the .phar file. Since I wanted to include all dependencies, I had to make some patches to copy pear package contents (#271, #272, #273, #274) and to make .phar generation work properly (#268). While being at it, I improved phing's documentation and made it more usable (#266, #269, #270).

With all the patches in place, I can collect my dependencies with that code:

 <target name="collectdeps" description="Copy package dependencies to lib/">
  <delete dir="lib/"/>
  <mkdir dir="lib/"/>
 
  <pearPackageFileset id="dep-Console_Color2" package="pear.php.net/Console_Color2"/>
  <pearPackageFileset id="dep-Mail_mime" package="pear.php.net/Mail_mime"/>
  <pearPackageFileset id="dep-PEAR" package="pear.php.net/PEAR">
   <include name="PEAR/Exception.php"/>
   <include name="PEAR.php"/>
   <include name="PEAR5.php"/>
  </pearPackageFileset>
 
  <copy todir="lib/">
   <fileset refid="dep-Console_Color2"/>
   <fileset refid="dep-Mail_mime"/>
   <fileset refid="dep-PEAR"/>
  </copy>
 </target>

and generate the .phar file with this code:

  <delete file="${pharfile}"/>
  <pharpackage basedir="${phing.dir}"
   destfile="${pharfile}"
   stub="${phing.dir}/src/phar-stub.php"
   alias="bdrem.phar"
  >
   <fileset refid="fs.phar"/>
  </pharpackage>

.phar with Apache

Debian's Apache does not handle .phar files automatically, even though I reported the issue in 2011. So now I made a patch and attached it to the report in the hope that it will get included some day.

In the meantime, simply replace the following line in /etc/apache2/mods-enabled/php5.conf:

-<FilesMatch ".+\.ph(p[345]?|t|tml)$">
+<FilesMatch ".+\.ph(ar(|\.bz2|\.gz|\.zip)|p[345]?|t|tml)$">

This makes Apache handle .phar, .phar.gz, phar.bz2 and phar.zip files.

phar stub

I determined that there is no need to use the default phar stub anymore; it was made to provide compatibility with PHP versions that do not support Phar natively. Since Phar is part of PHP's core since 5.3, you can ignore those 37kiB additional code and rather use a minimal custom stub.

webPhar bug

bdrem.phar worked fine on my development machine, but when deploying it to my home server that runs Debian 7 with the default PHP 5.4.4 under lighttpd, I got the ASCII instead of the HTML birthday table in my browser. It seems that Phar::webPhar has a bug that I had to work around with a custom SAPI name check.

Conclusion

After some weeks of coding, I have a beautiful birthday reminder that's accessible via console, web browser, email client and iCalendar.

Phing, Debian and PHP_DocBlockGenerator got some patches that made the world a bit better.

Get it or have a look at the AGPLv3-licensed source code (mirror).

Written by Christian Weiske.

Comments? Please send an e-mail.