One of the requirements for the upcoming public release of Officeshots.org is that all uploaded files are run through a virus scanner before they are made available. Picking a virus scanner for this job was easy. ClamAV is open source, well supported, actively maintained and comes pre-packaged for Debian Lenny which we use for the Officeshots servers. Finding a PHP library to interact with ClamAV proved harder though. The 3rd party library page for ClamAV points to two different libraries that provide PHP bindings for ClamAV but both appear to be dead and expunged from the internet. So, I created my own using the clamd TCP API, and because Officeshots is built using CakePHP I implemented it as a Cake plugin.
You can download the clamd-0.1.tar.gz plugin or check out the source from my Subversion repository with the following command:
- ~$ svn checkout https://svn.jejik.com/cakephp/plugins/clamd/trunk clamd
Or you can browse the repository online. In the rest of this article I will show you how you can use this plugin.
Install ClamAV (on Debian)
Start off by installing ClamAV. On Debian and derivative distributions this is very simple.
- ~# aptitude install clamav clamav-freshclam
Make sure that the ClamAV daemon is running and that freshclam regularly updates the virus definition database. On Debian Lenny this will be done automatically. Please refer to the ClamAV installation guide for installation on other Linux distributions or on Windows machines. After you have installed the ClamAV daemon you can test it with the clamdscan command.
- ~$ clamdscan somefile.odt
- /home/you/somefile.odt: OK
- ----------- SCAN SUMMARY -----------
- Infected files: 0
- Time: 0.011 sec (0 m 0 s)
Install the Clamd CakePHP plugin
This is really easy. Extract the package and move the clamd directory to your plugins directory in your CakePHP application.
- ~$ tar -zxvf clamd-0.1.tar.gz
- ~$ mv clamd your-cakephp/app/plugins/
Configuration
Start by including the Clamd plugin.
- App::import('Core', 'clamd.Clamd');
When you create the Clamd object you can pass the configuration to the constructor. The configuration consists of options that will be passed to fsockopen(). For example:
- $Clamd = new Clamd(
- 'host' => '127.0.0.1',
- 'port' => 3310,
- 'timeout' => 60
- );
You can also connect to a local Unix socket. Here is how you connect to the default socket on Debian Lenny:
- $Clamd = new Clamd(
- 'host' => 'unix:///var/run/clamav/clamd.ctl',
- 'port' => 0
- );
Usage
To test the Clamd connection you can use the ping() method.
- echo $Clamd->ping() ? 'Success!' : $Clamd->lastError();
You can use the scan method to scan a single file. The result will be one on the Clamd constants Clamd::OK, Clamd::FOUND or Clamd::ERROR.
- if ($Clamd->scan('/path/to/file', $message) === Clamd::FOUND) {
- echo "The file is infected with '$message'!\n";
- }
You can also recursively scan an entire directory. You will get back an array containing the results of the scan. Note that this array only contains files that returned Clamd::FOUND or Clamd::ERROR. Scanned files which are clean will not be returned. A result looks like this:
- array(3) {
- ['file'] => '/full/path/to/file'
- ['status'] => self::FOUND | self::ERROR
- ['message'] => virus name | error message
- }
Also, by default Clamd stops scanning as soon as the first infection is found. Pass TRUE as the second parameter to scan all files. Example usage:
- $results = $Clamd->rscan('/path/to/directory', true);
- foreach ($results as $result) {
- if ($result['status'] === Clamd::FOUND) {
- echo "File '$result[file]' is infected with '$result[message]'!\n";
- }
- }
The Clamd shell
The Clamd plugin also contains a simple interactive Cake Shell which you can use to test Clamd and scan files interactively. You can start the shell from your app directory with:
- ~$ cake clamd
You can use the following commands in the interactive shell:
- exit|quit|q
- Quit the shell
- connect <host> [<port> [<timeout>]]
- Connect to a ClamAV daemon
- ping
- Send a PING command to the clamav daemon
- scan <file>
- Scan <file> for viruses
- rscan <directory>
- Recursively scan <directory> for viruses. Only infected files and errors are returned.
- help
- Show the help
Comments
#1 David Persson (http://cakephp.org)
Anyways good work!
P.s.: I did something like that with the queue plugin: https://github.com/davidpersson/queue/tree
#2 Sander Marechal (http://www.jejik.com)
By the way, we apparently think alike. Guess what I wrote at the same time as the Clamd plugin? A Beantalkd Queue plugin for CakePHP so I could run the scanning process in the background :-)
Comments have been retired for this article.