FastFileRouter.php

<?php

namespace Lia;

class FastFileRouter {


    /**
     * Very quickly deliver a php file by appending the url to a directory
     * Request url must end with a forward slash `/`
     * GET params are removed from url
     * `..` is removed from url
     *
     * @param $dir the directory to route from
     * @param $args array of arguments to `extract()` prior to `require()`ing the file
     */
    static public function php($dir,$args=[]){
        $url = substr($_SERVER['REQUEST_URI'],0,strpos($_SERVER['REQUEST_URI'], '?')-1);
        $url = str_replace('..','',$url);

        if (!file_exists($file=$dir.$url.'.php')){
            return;
        }
        extract($args);

        require($file);

        exit;
    }

    /**
     * Very quickly deliver a file. Supports browser caching.
     * Uses a very fast implementation for getting mimetypes. Each file extension has a `*.txt` file that contains its mimetype.
     *
     * @note does not send php files ...
     *
     * @param $dir directory to route from
     */
    static public function file($dir, $url=null, $path_append=''){
        $file = $dir.str_replace('..','', $url??$_SERVER['REQUEST_URI']);
        if (!is_file($file.$path_append))return;
        if (strtolower(substr($file,-4))=='.php')return;
        static::send_file($file,$path_append);
        exit;
    }

    /**
     * Set the file name via headers. 
     * Literally `header("Content-Disposition: filename=\"$file_name\"", false);`
     *
     * @param $file_name the name of the downloaded file
     * @return void
     */
    static public function set_download_file_name($file_name){
        header("Content-Disposition: filename=\"$file_name\"",false);
    }
    /**
     * send headers & output file
     */
    static public function send_file($file_path, $path_append=''){

        $type = static::get_mime_type($file_path);
        $file_path = $file_path.$path_append;
        // var_dump($file_path);
        // var_dump($path_append);
        // exit;

        /** @bug Caching is impossible if apache_request_headers is unavailable **/
        $request_headers = function_exists('apache_request_headers') ? \apache_request_headers() : [];
        $mtime = filemtime($file_path);

        if (isset($request_headers['If-Modified-Since']) 
            && (strtotime($request_headers['If-Modified-Since']) == $mtime) 
            &&$mtime !==FALSE) 
        {
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 304);
            header('Content-type: '.$type);
        } else {
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', $mtime).' GMT', true, 200);
            header('Content-type: '.$type);
            header('Content-Length: '.filesize($file_path));
            header('Cache-Control: max-age='.(60*60*24*30));
            readfile($file_path);
        }

    }

    static public function get_mime_type($file_path){
        $ext = substr($file_path, strrpos($file_path,'.')+1);
        if (strlen($ext)>6)exit;


        $file = __DIR__.'/../../file/mime_types/'.$ext.'.txt';
        return file_get_contents($file);
    }
}