PHP Classes
elePHPant
Icontem

File: engine/handler.file.php

Recommend this page to a friend!
  Classes of Kristo Vaher  >  Wave Framework  >  engine/handler.file.php  >  Download  
File: engine/handler.file.php
Role: Application script
Content type: text/plain
Description: File Handler
Class: Wave Framework
MVC framework for building Web sites and APIs
Author: By
Last change: Updated jQuery 1.10.0 and 2.0.1. Added better API versioning support that also takes into account overrides folders. Refactoring of Imager class to reduce duplicate code between Image Handler and Imager. Also fixed the bug introduced in 3.6.2 that generated incorrect image sprite sizes in dynamic image loading. Code review and some minor changes.
Date: 3 years ago
Size: 8,698 bytes
 

Contents

Class file image Download
<?php
/**
 * Wave Framework <http://www.waveframework.com>
 * File Handler
 *
 * File Handler is used for returning a file from web server. It is loaded by Index Controller
 * when a request is made to a file that has an extension that has not already been served by
 * another Handler (such as Resource and Image handlers). File Handler is usually considered
 * for returning documents, videos and audio from the web server. It also allows to return a
 * file within a byte range, like in the case of file streams.
 *
 * @package Index Gateway
 * @author Kristo Vaher <kristo@waher.net>
 * @copyright Copyright (c) 2012, Kristo Vaher
 * @license GNU Lesser General Public License Version 3
 * @tutorial /doc/pages/handler_file.htm
 * @since 1.5.0
 * @version 3.6.4
 */
// INITIALIZATION
// Stopping all requests that did not come from Index Gateway
   
if(!isset($resourceAddress)){
       
header('HTTP/1.1 403 Forbidden');
        die();
    }
   
   
// If access control header is set in configuration
   
if(isset($config['access-control'])){
       
header('Access-Control-Allow-Origin: '.$config['access-control']);
    }
// If filename includes & symbol, then system assumes it should be dynamically generated
   
$parameters=array_unique(explode('&',$resourceFile));
// Getting the downloadable file name
   
$resourceFile=array_pop($parameters);
// The amount of non-filenames in the request
   
$parameterCount=count($parameters);
   
   
// Range of bytes to return
    // This allows user agent to request only part of the file
   
if(isset($_SERVER['HTTP_RANGE'])){
       
$tmp=explode('=',$_SERVER['HTTP_RANGE']);
       
$bytesData=explode('-',array_pop($tmp));
        if(isset(
$bytesData) && is_numeric($bytesData[0]) && is_numeric($bytesData[1])){
           
$bytesFrom=$bytesData[0];
           
$bytesTo=$bytesData[1];
        }
    }
// No cache flag
   
$noCache=array_search('nocache',$parameters);
    if(
$noCache!==false){
       
// Unsetting the key for nocache parameter
       
unset($parameters[$noCache]);
    }
   
   
// Web root is the subfolder on public site
   
$webRoot=str_replace('index.php','',$_SERVER['SCRIPT_NAME']);
// Checking if the file might be loaded from overrides folder
   
if(preg_match('/^'.str_replace('/','\/',$webRoot).'resources\//',$_SERVER['REQUEST_URI'])){
       
// Solving possible overrides folder
       
$overridesFolder=str_replace($webRoot.'resources'.DIRECTORY_SEPARATOR,$webRoot.'overrides'.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR,$resourceFolder);
        if(
file_exists($overridesFolder.$resourceFile)){
           
$resourceFolder=$overridesFolder;
        }
    }
// Default cache timeout of one month, unless timeout is set
   
if(!isset($config['resource-cache-timeout'])){
       
$config['resource-cache-timeout']=31536000; // A year
   
}
// CHECK FOR PARAMETER SUPPORT
// If more than one parameter is set, it returns 404
    // 404 is also returned if file does not actually exist
   
if($parameterCount>1 || ($parameterCount==1 && !$noCache) || !file_exists($resourceFolder.$resourceFile)){
       
// Adding log entry
       
if(isset($logger)){
           
// Assigning custom log data to logger
           
$logger->setCustomLogData(array('category'=>'file','response-code'=>'404'));
           
// Writing log entry
           
$logger->writeLog();
        }
       
// Returning 404 header
       
header('HTTP/1.1 404 Not Found');
        die();
    }
// Last-modified date
   
$lastModified=filemtime($resourceFolder.$resourceFile);
// NOT MODIFIED CHECK
// Checking if file has been modified or not
   
if(!$noCache){
       
// If the request timestamp is exactly the same, then we let the browser know of this
       
if((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])==$lastModified) || (isset($_SERVER['HTTP_IF_RANGE']) && strtotime($_SERVER['HTTP_IF_RANGE'])==$lastModified)){
           
// Adding log entry
           
if(isset($logger)){
               
// Assigning custom log data to logger
               
$logger->setCustomLogData(array('cache-used'=>true,'category'=>'image','response-code'=>'304'));
               
// Writing log entry
               
$logger->writeLog();
            }
           
// Cache headers (Last modified is never sent with 304 header)
           
header('Cache-Control: public,max-age='.$config['resource-cache-timeout']);
           
header('Expires: '.gmdate('D, d M Y H:i:s',($_SERVER['REQUEST_TIME']+$config['resource-cache-timeout'])).' GMT');
           
// Returning 304 header
           
header('HTTP/1.1 304 Not Modified');
            die();
        }
    }
// DETECTING MIME TYPE
// Currently assumed MIME type
   
$mimeType='';
   
// Finding the proper MIME type
   
if(extension_loaded('fileinfo')){
       
// This opens MIME type 'magic' resource for use
       
if($fileInfo=finfo_open(FILEINFO_MIME_TYPE)){
           
// Finding MIME type with magic resource
           
$mimeType=finfo_file($fileInfo,$resourceFolder.$resourceFile);
           
// Resourse is not needed further, so it is closed
           
finfo_close($fileInfo);
        }
    } else {
       
// Since Fileinfo was not available, we use extension-based detection as fallback
       
if(isset($resourceExtension)){
            switch(
$resourceExtension){
                case
'ico':
                   
$mimeType='image/vnd.microsoft.icon;';
                    break;
                case
'zip':
                   
$mimeType='application/zip';
                    break;
                case
'pdf':
                   
$mimeType='application/pdf';
                    break;
                case
'mp3':
                   
$mimeType='audio/mpeg';
                    break;
                case
'gif':
                   
$mimeType='image/gif';
                    break;
                case
'tif':
                   
$mimeType='image/tiff';
                    break;
            }
        }
    }
   
// HEADERS
// Assigning MIME type if it was found
   
if($mimeType && $mimeType!=''){
       
// Detected mime type is set as content-type header
       
header('Content-Type: '.$mimeType.';');
    } else {
       
// Octet stream is a general-use unknown resource, and browsers will often attempt to 'download' such a file
       
header('Content-Type: application/octet-stream;');
       
header('Content-Disposition: attachment; filename='.$resourceFile);
    }
       
   
// If cache is used, then proper headers will be sent
   
if($noCache){
       
// User agent is told to cache these results for set duration
       
header('Cache-Control: no-cache,no-store');
       
header('Expires: '.gmdate('D, d M Y H:i:s',$_SERVER['REQUEST_TIME']).' GMT');
       
header('Last-Modified: '.gmdate('D, d M Y H:i:s',$lastModified).' GMT');
    } else {
       
// User agent is told to cache these results for set duration
       
header('Cache-Control: public,max-age='.$config['resource-cache-timeout']);
       
header('Expires: '.gmdate('D, d M Y H:i:s',($_SERVER['REQUEST_TIME']+$config['resource-cache-timeout'])).' GMT');
       
header('Last-Modified: '.gmdate('D, d M Y H:i:s',$lastModified).' GMT');
    }
// Robots header
   
if(isset($config['file-robots'])){
       
// If file-specific robots setting is defined
       
header('Robots-Tag: '.$config['file-robots'],true);
    } elseif(isset(
$config['robots'])){
       
// This sets general robots setting, if it is defined in configuration file
       
header('Robots-Tag: '.$config['robots'],true);
    } else {
       
// If robots setting is not configured, system tells user agent not to cache the file
       
header('Robots-Tag: noindex,nocache,nofollow,noarchive,noimageindex,nosnippet',true);
    }
   
// OUTPUT
// If user agent only requested part of the file to be returned
   
if(isset($bytesFrom,$bytesTo)){
       
// Getting current output length
       
$contentLength=filesize($resourceFolder.$resourceFile);
        if(
$bytesTo<=$contentLength){
           
// Required for range response
           
header('HTTP/1.1 206 Partial Content');
           
header('Content-Range: bytes '.$bytesFrom.'-'.$bytesTo.'/'.$contentLength);
           
// Content length is defined that can speed up website requests, letting user agent to determine file size
           
header('Content-Length: '.($bytesTo-$bytesFrom));
           
// Returning part of the file
           
$fileHandle=fopen($resourceFolder.$resourceFile,'r');
           
fseek($fileHandle,$bytesFrom);
           
// Returning the data to user agent
           
echo fread($fileHandle,($bytesTo-$bytesFrom));
        } else {
           
header('HTTP/1.1 416 Requested Range Not Satisfiable');
        }
    } else {
       
// Getting current output length
       
$contentLength=filesize($resourceFolder.$resourceFile);
       
// Content length is defined that can speed up website requests, letting user agent to determine file size
       
header('Content-Length: '.$contentLength);
       
// Returning the file to user agent
       
readfile($resourceFolder.$resourceFile);
    }
   
// WRITING TO LOG
// If Logger is defined then request is logged and can be used for performance review later
   
if(isset($logger)){
       
// Assigning custom log data to logger
       
$logger->setCustomLogData(array('cache-used'=>false,'category'=>'file','content-length-used'=>$contentLength));
       
// Writing log entry
       
$logger->writeLog();
    }
?>