Creating a Download Controller in Zend Framework

We’re playing around with a Zend Form Element Captcha Image and we need to keep the images generated somewhere. In the public folder? I’d rather not. The same applies for user uploads, and session files. However our browsers won’t be able to map an image from the url if its in the non public folders. So I’m setting up a Download Controller.

Ok so we need folders for all this stuff. In the shell at the root of the site:

mkdir uploads
mkdir session
mkdir captcha
chmod 777 uploads
chmod 777 session
chmod 777 captcha 
cd library
mkdir fonts
chmod 777 fonts

Next thing – let’s not hard code any paths. We create an ini file called
/application/configs/paths.ini
and type this out:

[paths]
uploads = /../uploads/
captcha = /../captcha/
fonts = /../library/fonts/
captchafont = Tahoma.ttf

And of course copy and paste the Tahoma.ttf file into /library/fonts.

If you haven’t created your own library, you should do it. Certain components you write will be useful in lots of sites. In this example, a standard contact form can be reused over and over again.
Create a folder in the library. Your classes will start in the Zend way; Zend_Form, Zend_Date, so choose your folder name carefully 😉 For my own nostalgic reasons of programming Atari ST’s when I was younger, my library is called TTB.
In your application.ini, add the following line:

autoloaderNamespaces[] = "TTB_"

replacing TTB with your folder name. Then put a forms folder in that and create a Contact.php

In the init section of the form (TTB_Form_Contact), we want to get the paths for the fonts for the captcha, so we create a $config variable:

//get the relevant path configuration
 $config = new Zend_Config_Ini( APPLICATION_PATH.'/configs/paths.ini', array('paths'));

And the captcha element looks like this:

$captcha = new Zend_Form_Element_Captcha('captcha', array(
    'captcha' => array(
        'captcha' => 'Image',
        'wordLen' => 6,
        'timeout' => 300,
        'width'   => 300,
        'height'  => 100,
        'imgUrl'  => '/captcha',
        'imgDir'  => APPLICATION_PATH . $config->captcha,
        'font'    => APPLICATION_PATH .$config->fonts.$config->captchafont
        )
    ));

our standard captcha URL is /captcha, so we need to set up a route. In your initRoutes in the bootstrap:

//route for download
$router->addRoute('download', new Zend_Controller_Router_Route('download/:file', array('controller' => 'download', 'action' => 'index')));
//route for captchas
$router->addRoute('captcha', new Zend_Controller_Router_Route('captcha/:file', array('controller' => 'download', 'action' => 'captcha')));

This sets up URL’s like /download/photo.jpg, or /captcha/jgf235jf4fuiy2gfc.png. They point to a download controller, so lets create one:

class DownloadController extends Zend_Controller_Action
{
    /** @var string $path the relevant folder */
    protected $_path;
    public function init()
    {
        //get the relevant path
         $this->config = new Zend_Config_Ini( APPLICATION_PATH.'/configs/paths.ini', array('paths'));
    }
    public function indexAction()
    {
        $this->_path = $this->config->uploads;
        $this->generate();
    }
    public function captchaAction()
    {
        $this->_path = $this->config->captcha;
        $this->generate();
    }
}

This sets the path to be used before rendering the image, which happens in $this->generate(), the meat and bones of the download controller:

private function generate()
{
    $file = $this->getRequest()->getParam('file');

    // disable view and layout 
    Zend_Layout::getMvcInstance()->disableLayout(); 
    $this->_helper->viewRenderer->setNoRender(); 

    // setup realpath to image 
    $path_to_image = APPLICATION_PATH.$this->_path.$file;  

    //set mimetype (content-type image/jpeg etc)
    $mtype = '';

    // magic_mime module installed?
    if (function_exists('mime_content_type')) 
    {
         $mtype = mime_content_type($path_to_image);
    }
    // fileinfo module installed?
    else if (function_exists('finfo_file')) 
    {
        $finfo = finfo_open(FILEINFO_MIME); // return mime type
        $mtype = finfo_file($finfo, $path_to_image);
        finfo_close($finfo); 
    } 
    // set headers 
    header("Content-Type: ".$mtype);

    // Open the file for reading
    $fh = fopen($path_to_image, 'r'); 

    // And pass it through to the browser
    fpassthru($fh);
}

Now you have an awesome captcha, a great way of configuring your paths, and a download controller which can serve up images from the protected areas of your site!

Advertisements

One thought on “Creating a Download Controller in Zend Framework

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s