Login   Register  
PHP Classes
elePHPant
Icontem

File: engine/handler.file.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  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: 1 year 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>|| ($parameterCount==&& !$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();
    }
?>