<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -10,18 +10,59 @@
 class Noginn_Controller_Action_Helper_SendFile extends Zend_Controller_Action_Helper_Abstract
 {
     /**
-     * Proxy method for sendFile
+     * Set cache headers
      *
-     * @param string $path Path to the file
-     * @param string $type The mime-type of the file
-     * @param string $filename The filename to send the file as, if null then use the base name of the path
-     * @param string $disposition Whether the file should be sent inline or as an attachment
-     * @param bool $useXSendfile Whether to use the X-Sendfile response header
-     * @return bool Whether the headers and file were sent
+     * @param array $options
      */
-    public function direct($path, $type, $filename = null, $disposition = 'attachment', $useXSendfile = false)
+    public function setCacheHeaders($options)
     {
-        return $this-&gt;sendFile($path, $type, $filename, $disposition, $useXSendfile);
+        $response = $this-&gt;getResponse();
+        
+        $cacheControl = array();
+        if (isset($options['public']) &amp;&amp; $options['public']) {
+            $cacheControl[] = 'public';
+        }
+        if (isset($options['no-cache']) &amp;&amp; $options['no-cache']) {
+            $cacheControl[] = 'no-cache';
+        }
+        if (isset($options['no-store']) &amp;&amp; $options['no-store']) {
+            $cacheControl[] = 'no-store';
+        }
+        if (isset($options['must-revalidate']) &amp;&amp; $options['must-revalidate']) {
+            $cacheControl[] = 'must-revalidate';
+        }
+        if (isset($options['proxy-validation']) &amp;&amp; $options['proxy-validation']) {
+            $cacheControl[] = 'proxy-validation';
+        }
+        if (isset($options['max-age'])) {
+            $cacheControl[] = 'max-age=' . (int) $options['max-age'];
+            $response-&gt;setHeader('Expires', gmdate('r', time() + $options['max-age']), true);
+        }
+        if (isset($options['s-maxage'])) {
+            $cacheControl[] = 's-maxage=' . (int) $options['s-maxage'];
+        }
+
+        $response-&gt;setHeader('Cache-Control', implode(',', $cacheControl), true);
+        $response-&gt;setHeader('Pragma', 'public', true);
+    }
+
+    /**
+     * Validate the cache using the If-Modified-Since request header
+     *
+     * @param int $modified When the file was last modified as a unix timestamp
+     * @return bool
+     */
+    public function notModifiedSince($modified)
+    {
+        if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &amp;&amp; $modified &lt;= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
+            // Send a 304 Not Modified header
+            $response = $this-&gt;getResponse();
+            $response-&gt;setHttpResponseCode(304);
+            $response-&gt;sendHeaders();
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -29,12 +70,10 @@ class Noginn_Controller_Action_Helper_SendFile extends Zend_Controller_Action_He
      *
      * @param string $path Path to the file
      * @param string $type The mime-type of the file
-     * @param string $filename The filename to send the file as, if null then use the base name of the path
-     * @param string $disposition Whether the file should be sent inline or as an attachment
-     * @param bool $useXSendfile Whether to use the X-Sendfile response header
+     * @param array $options
      * @return bool Whether the headers and file were sent
      */
-    public function sendFile($path, $type, $filename = null, $disposition = 'attachment', $useXSendfile = false)
+    public function sendFile($path, $type, $options = array())
     {
         $response = $this-&gt;getResponse();
         
@@ -42,28 +81,49 @@ class Noginn_Controller_Action_Helper_SendFile extends Zend_Controller_Action_He
             return false;
         }
 
+        // Set the cache-control
+        if (isset($options['cache'])) {
+            $this-&gt;setCacheHeaders($options['cache']);
+        }
+
+        // Get the last modified time
+        if (isset($options['modified'])) {
+            $modified = (int) $options['modified'];
+        } else {
+            $modified = filemtime($path);
+        }
+
+        // Validate the cache
+        if (!isset($options['cache']['no-store']) &amp;&amp; $this-&gt;notModifiedSince($modified)) {
+            return true;
+        }
+
         // Set the file name
-        if ($filename !== null) {
-            $filename = $filename;
+        if (isset($options['filename']) &amp;&amp; !empty($options['filename'])) {
+            $filename = $options['filename'];
         } else {
             $filename = basename($path);
         }
 
-        // Set the content disposition (can only be attachment or inline)
-        if ($disposition != 'attachment') {
+        // Set the content disposition
+        if (isset($options['disposition']) &amp;&amp; $options['disposition'] == 'inline') {
             $disposition = 'inline';
+        } else {
+            $disposition = 'attachment';
         }
-        
+
+        $response-&gt;setHttpResponseCode(200);
         $response-&gt;setHeader('Content-Type', $type, true);
         $response-&gt;setHeader('Content-Disposition', $disposition . '; filename=&quot;' . $filename . '&quot;', true);
 
         // Do we want to use the X-Sendfile header or stream the file
-        if ($useXSendfile) {
+        if (isset($options['xsendfile']) &amp;&amp; $options['xsendfile']) {
             $response-&gt;setHeader('X-Sendfile', $path);
             $response-&gt;sendHeaders();
             return true;
         }
-        
+
+        $response-&gt;setHeader('Last-Modified', gmdate('r', $modified), true);
         $response-&gt;setHeader('Content-Length', filesize($path), true);
         $response-&gt;sendHeaders();
 
@@ -74,25 +134,42 @@ class Noginn_Controller_Action_Helper_SendFile extends Zend_Controller_Action_He
     /**
      * Send file data as a download
      *
-     * @param string $data The data to send
+     * @param string $path Path to the file
      * @param string $type The mime-type of the file
      * @param string $filename The filename to send the file as, if null then use the base name of the path
-     * @param string $disposition Whether the file should be sent inline or as an attachment
+     * @param array $options
      * @return bool Whether the headers and file were sent
      */
-    public function sendData($data, $type, $filename, $disposition = 'attachment')
+    public function sendData($data, $type, $filename, $options = array())
     {
         $response = $this-&gt;getResponse();
         
-        if (empty($data) || !$response-&gt;canSendHeaders()) {
+        if (!$response-&gt;canSendHeaders()) {
             return false;
         }
 
-        // Set the content disposition (can only be attachment or inline)
-        if ($disposition != 'attachment') {
-            $disposition = 'inline';
+        // Set the cache-control
+        if (isset($options['cache'])) {
+            $this-&gt;setCacheHeaders($options['cache']);
+        }
+        
+        if (isset($options['modified'])) {
+            // Validate the cache
+            if (!isset($options['cache']['no-store']) &amp;&amp; $this-&gt;notModifiedSince($options['modified'])) {
+                return true;
+            }
+            
+            $response-&gt;setHeader('Last-Modified', gmdate('r', $options['modified']), true);
         }
 
+        // Set the content disposition
+        if (isset($options['disposition']) &amp;&amp; $options['disposition'] == 'inline') {
+            $disposition = 'inline';
+        } else {
+            $disposition = 'attachment';
+        }
+        
+        $response-&gt;setHttpResponseCode(200);
         $response-&gt;setHeader('Content-Type', $type, true);
         $response-&gt;setHeader('Content-Disposition', $disposition . '; filename=&quot;' . $filename . '&quot;', true);
         $response-&gt;setHeader('Content-Length', strlen($data), true);
@@ -101,4 +178,17 @@ class Noginn_Controller_Action_Helper_SendFile extends Zend_Controller_Action_He
         echo $data;
         return true;
     }
+
+    /**
+     * Proxy method for sendFile
+     *
+     * @param string $path Path to the file
+     * @param string $type The mime-type of the file
+     * @param array $options
+     * @return bool Whether the headers and file were sent
+     */
+    public function direct($path, $type, $options = array())
+    {
+        return $this-&gt;sendFile($path, $type, $options);
+    }
 }</diff>
      <filename>Noginn/Controller/Action/Helper/SendFile.php</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>cdd843851baecc857e2b47cbe94a0f74eef1ead3</id>
    </parent>
  </parents>
  <author>
    <name>Tom Graham</name>
    <email>me@noginn.com</email>
  </author>
  <url>http://github.com/noginn/noginn/commit/c0613857805a64420b8f2f2d8e368bec29030dcf</url>
  <id>c0613857805a64420b8f2f2d8e368bec29030dcf</id>
  <committed-date>2009-03-08T05:13:08-07:00</committed-date>
  <authored-date>2009-03-08T05:13:08-07:00</authored-date>
  <message>Re-factored SendFile action helper.</message>
  <tree>0a86427981467208f62e173e694dae6b7f0a840d</tree>
  <committer>
    <name>Tom Graham</name>
    <email>me@noginn.com</email>
  </committer>
</commit>
