<?php
namespace Lia\Utility;
/**
* Build headers for static files like .js or .css or image files
*/
class StaticFile {
/** The absolute file path */
protected $file;
/** Array of headers */
protected $headers = [];
/** headers for the content type & content length */
protected $typeHeaders = [];
/** headers for the cache-state */
protected $cacheHeaders = [];
/** true if request headers indicate the file has been cached on the client */
public $userHasFileCached = false;
/**
* @param $file absolute file path
*/
public function __construct($file){
$this->file = $file;
if (!is_file($file)){
throw new \Lia\Exception\Base("File '{$file}' does not exist");
}
$this->getHeaders();
}
/**
* @return array of headers for content type & content length
*/
public function getContentTypeHeaders(){
if ($this->typeHeaders!=null){
return $this->typeHeaders;
}
$filePath = $this->file;
$type = $this->getFileMimeType($filePath);
if ($type===FALSE){
throw new \Lia\Exception\Base("Cannot determine file type from path '{$filePath}', so cannot get content type headers.");
}
$headers[] = ['Content-type: '.$type];
if (is_file($filePath)){
$headers[] = ['Content-Length: '.filesize($filePath)];
}
$this->typeHeaders = $headers;
return $headers;
}
/**
* @return array of headers for cache-control
*/
public function getCacheHeaders(){
if ($this->cacheHeaders!=null){
return $this->cacheHeaders;
}
$headers = [];
$filePath = $this->file;
$type = $this->getFileMimeType($filePath);
if ($type===FALSE){
throw new \Lia\Exception\Base("Cannot determine file type from path '{$filePath}', so cannot send file headers or file.");
}
/** @bug Caching is impossible if apache_request_headers is unavailable **/
$requestHeaders = function_exists('apache_request_headers') ? \apache_request_headers() : [];
$mtime = filemtime($filePath);
if (isset($headers['If-Modified-Since'])
&& (strtotime($headers['If-Modified-Since']) == $mtime)
&&$mtime !==FALSE)
{
$headers[] = ['Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 304];
$this->userHasFileCached = true;
} else {
$headers[] = ['Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 200];
$headers[] = ['Content-Length: '.filesize($filePath)];
$headers[] = ['Cache-Control: max-age='.(60*60*24*30)];
// readfile($filePath);
}
$this->cacheHeaders = $headers;
return $headers;
}
/**
* @return all headers
*/
public function getHeaders(){
if ($this->headers!=null){
return $this->headers;
}
$headers = [];
$filePath = $this->file;
$type = $this->getFileMimeType($filePath);
if ($type===FALSE){
throw new \Lia\Exception\Base("Cannot determine file type from path '{$filePath}', so cannot send file headers or file.");
}
/** @bug Caching is impossible if apache_request_headers is unavailable **/
$requestHeaders = function_exists('apache_request_headers') ? \apache_request_headers() : [];
$mtime = filemtime($filePath);
if (isset($headers['If-Modified-Since'])
&& (strtotime($headers['If-Modified-Since']) == $mtime)
&&$mtime !==FALSE)
{
$headers[] = ['Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 304];
$headers[] = ['Content-type: '.$type];
$this->userHasFileCached = true;
} else {
$headers[] = ['Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 200];
$headers[] = ['Content-type: '.$type];
$headers[] = ['Content-Length: '.filesize($filePath)];
$headers[] = ['Cache-Control: max-age='.(60*60*24*30)];
// readfile($filePath);
}
$this->headers = $headers;
return $headers;
}
/**
* Get mime type of a file based on its extension
*/
protected function getFileMimeType($filePath){
static $typeMap = NULL;
$typeMap = $typeMap ?? require(dirname(__DIR__,2).'/file/mime_type_map.php');
$ext = pathinfo($filePath,PATHINFO_EXTENSION);
// if (!isset($typeMap['mimes'][$ext]))throw new \Exception("type not available for extension '{$ext}'");
return $typeMap['mimes'][$ext][0] ?? false;
}
}