Browse Source

Merge branch 'master' of ssh://gogs.vipe.re:6022/KarmaSolutions/KarmaFW

Max F 5 năm trước cách đây
mục cha
commit
1c85028181

+ 43 - 9
src/App.php

@@ -9,7 +9,9 @@ use \KarmaFW\Database\Sql\SqlDb;
 
 use \KarmaFW\App\Request;
 use \KarmaFW\App\Response;
+use \KarmaFW\App\ResponseError;
 use \KarmaFW\App\Pipe;
+use \KarmaFW\App\Container;
 
 
 define('FW_SRC_DIR', __DIR__);
@@ -34,11 +36,13 @@ class App
 
 	protected static $instance = null;
 	protected $middlewares;
+	protected $container;
 
 
 	public function __construct($middlewares=[])
 	{
 		$this->middlewares = $middlewares;
+		$this->container = new Container;
 		self::$instance = $this;
 
 		try {
@@ -77,7 +81,8 @@ class App
 		}
 
 		if (! defined('ENV')) {
-			define('ENV', 'prod');
+			$env = defined('ENVIRONMENT') ? ENVIRONMENT : 'prod';
+			define('ENV', $env);
 		}
 
 		if (! defined('DB_DSN')) {
@@ -105,15 +110,16 @@ class App
 			$response = $pipe->next($request, $response);
 
 		} catch (\Exception $e) {
-			header("HTTP/1.0 500 Internal Server Error");
-			echo "<h1>Server error</h1>";
+            $content = null;
 
-			if (ENV === 'dev') {
-				echo "<pre>";
-				print_r($e);
-				echo "</pre>";
-			}
-			exit;
+            if (ENV == 'dev') {
+                $title = "App CATCHED EXCEPTION";
+                $message = '<pre>' . print_r($e, true) . '</pre>';
+                $content = '<title>' . $title . '</title><h1>' . $title . '</h1><p>' . $message . '</p>';
+            }
+
+            //throw $e;
+            return new ResponseError(500, $content); 
 		}
 
 		return $response;
@@ -212,16 +218,35 @@ class App
 	}
 
 	
+	public function get($key, $default_value=null)
+	{
+		return isset($this->container[$key]) ? $this->container[$key] : $default_value;
+	}
+
+	public function set($key, $value)
+	{
+		$this->container[$key] = $value;
+	}
+
+    public function has($name)
+    {
+        return isset($this->container[$name]);
+    }
+
+
+    // DEPRECATED
 	public static function setData($key, $value=null)
 	{
 		self::$data[$key] = $value;
 	}
 
+	// DEPRECATED
 	public static function getData($key, $default_value=null)
 	{
 		return array_key_exists($key, self::$data) ? self::$data[$key] : $default_value;
 	}
 
+	// DEPRECATED
 	public static function hasData($key)
 	{
 		return array_key_exists($key, self::$data);
@@ -259,6 +284,15 @@ class App
 	}
 
 
+	public static function getApp()
+	{
+		if (isset(self::$instance)) {
+			return self::$instance;
+		}
+		throw new Exception("App is not instancied", 1);
+	}
+
+
 	public static function getDb($instance_name=null, $dsn=null)
 	{
 		/*

+ 20 - 0
src/App/Container.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace KarmaFW\App;
+
+
+class Container extends \ArrayObject
+{
+
+    /*
+    public function __set($name, $val) {
+        $this[$name] = $val;
+    }
+
+    public function __get($name) {
+        return $this[$name];
+    }
+    */
+    
+}
+

+ 45 - 0
src/App/Middlewares/CacheHtml.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace KarmaFW\App\Middlewares;
+
+use \KarmaFW\App\Request;
+use \KarmaFW\App\Response;
+
+
+class CacheHtml
+{
+	protected $cache_duration;
+	protected $cache_dir;
+
+    
+    public function __construct($cache_dir='/tmp', $cache_duration=3600)
+    {
+    	$this->cache_duration = $cache_duration;
+    	$this->cache_dir = $cache_dir;
+    }
+
+
+    public function __invoke(Request $request, Response $response, callable $next)
+    {
+    	$request_uri = $request->SERVER['REQUEST_URI'];
+    	
+    	$cache_key = md5($request_uri);
+    	$cache_file = $this->cache_dir . '/' . $cache_key . '.cache.html';
+
+    	if (is_file($cache_file) && filectime($cache_file) > time() - $this->cache_duration ) {
+    		// Get response content from file cache
+    		$content = file_get_contents($cache_file);
+    		$response->setContent($content);
+        	$response->addHeader('X-Cache-Html', 'hit');
+
+    	} else {
+        	$response = $next($request, $response);
+
+        	file_put_contents($cache_file, $response->getContent());
+        	$response->addHeader('X-Cache-Html', 'miss');
+    	}
+
+        return $response;
+    }
+
+}

+ 11 - 3
src/App/Middlewares/ErrorHandler.php

@@ -4,6 +4,7 @@ namespace KarmaFW\App\Middlewares;
 
 use \KarmaFW\App\Request;
 use \KarmaFW\App\Response;
+use \KarmaFW\App\ResponseError;
 
 
 class ErrorHandler
@@ -24,9 +25,16 @@ class ErrorHandler
             $response = $next($request, $response);
 
         } catch (\Throwable $e) {
-            echo "ErrorHandler CATCHED EXCEPTION" . PHP_EOL; // TODO
-            print_r($e);
-        }
+            $content = null;
+
+            if (ENV == 'dev') {
+                $title = "ErrorHandler CATCHED EXCEPTION";
+                $message = '<pre>' . print_r($e, true) . '</pre>';
+                $content = '<title>' . $title . '</title><h1>' . $title . '</h1><p>' . $message . '</p>';
+            }
+
+            //throw $e;
+            return new ResponseError(500, $content);        }
 
         return $response;
     }

+ 19 - 11
src/App/Middlewares/ForceHttps.php

@@ -4,24 +4,32 @@ namespace KarmaFW\App\Middlewares;
 
 use \KarmaFW\App\Request;
 use \KarmaFW\App\Response;
+use \KarmaFW\App\ResponseRedirect;
 
 
 class ForceHttps
 {
-	
+	protected $redirect_status = 302;
+	protected $redirect_domains = []; // example.com, www.example.com, example.fr, www.example.fr
+
+
+	public function __construct($redirect_status=302, $redirect_domains=[])
+	{
+		$this->redirect_status = $redirect_status;
+		$this->redirect_domains = $redirect_domains;
+	}
+
+
 	public function __invoke(Request $request, Response $response, callable $next)
 	{
-		/*
-		print_r($request); throw new Exception("DEBUG ME", 1);
-		
-
-		$is_ssl = false; // TODO
-		if (! $is_ssl) {
-			$redirect_url = 'https://' . $request->SERVER['SERVER_NAME'] . $request->SERVER['REQUEST_URI'] . (empty($request->SERVER['QUERY_STRING']) ? '' : ('?' . $request->SERVER['QUERY_STRING']));
-			$status = 302;
-			return new ResponseRedirect($redirect_url, $status);
+		if (! $request->isSecure()) {
+			
+			if (empty($this->redirect_domains) || in_array($request->SERVER['SERVER_NAME'], $this->redirect_domains)) {
+				$redirect_url = 'https://' . $request->SERVER['SERVER_NAME'] . $request->SERVER['REQUEST_URI'];
+				return new ResponseRedirect($redirect_url, $this->redirect_status);
+			}
+
 		}
-		*/
 
 		return $next($request, $response);
 	}

+ 65 - 0
src/App/Middlewares/MinimifierCss.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace KarmaFW\App\Middlewares;
+
+use \KarmaFW\App\Request;
+use \KarmaFW\App\Response;
+
+
+class MinimifierCss
+{
+    
+    public function __invoke(Request $request, Response $response, callable $next)
+    {
+        $response = $next($request, $response);
+
+        // TODO: reperer les balises <link href=...> dans le dom, récupérer le css correspondant, le minimifier et le lui créer un id de minification
+
+        return $response;
+    }
+
+
+    // CSS Minifier (source: https://gist.github.com/Rodrigo54/93169db48194d470188f ) => http://ideone.com/Q5USEF + improvement(s)
+    public static function minify_css($input) {
+        if(trim($input) === "") return $input;
+        return preg_replace(
+            array(
+                // Remove comment(s)
+                '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')|\/\*(?!\!)(?>.*?\*\/)|^\s*|\s*$#s',
+                // Remove unused white-space(s)
+                '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/))|\s*+;\s*+(})\s*+|\s*+([*$~^|]?+=|[{};,>~]|\s(?![0-9\.])|!important\b)\s*+|([[(:])\s++|\s++([])])|\s++(:)\s*+(?!(?>[^{}"\']++|"(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')*+{)|^\s++|\s++\z|(\s)\s+#si',
+                // Replace `0(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)` with `0`
+                '#(?<=[\s:])(0)(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)#si',
+                // Replace `:0 0 0 0` with `:0`
+                '#:(0\s+0|0\s+0\s+0\s+0)(?=[;\}]|\!important)#i',
+                // Replace `background-position:0` with `background-position:0 0`
+                '#(background-position):0(?=[;\}])#si',
+                // Replace `0.6` with `.6`, but only when preceded by `:`, `,`, `-` or a white-space
+                '#(?<=[\s:,\-])0+\.(\d+)#s',
+                // Minify string value
+                '#(\/\*(?>.*?\*\/))|(?<!content\:)([\'"])([a-z_][a-z0-9\-_]*?)\2(?=[\s\{\}\];,])#si',
+                '#(\/\*(?>.*?\*\/))|(\burl\()([\'"])([^\s]+?)\3(\))#si',
+                // Minify HEX color code
+                '#(?<=[\s:,\-]\#)([a-f0-6]+)\1([a-f0-6]+)\2([a-f0-6]+)\3#i',
+                // Replace `(border|outline):none` with `(border|outline):0`
+                '#(?<=[\{;])(border|outline):none(?=[;\}\!])#',
+                // Remove empty selector(s)
+                '#(\/\*(?>.*?\*\/))|(^|[\{\}])(?:[^\s\{\}]+)\{\}#s'
+            ),
+            array(
+                '$1',
+                '$1$2$3$4$5$6$7',
+                '$1',
+                ':0',
+                '$1:0 0',
+                '.$1',
+                '$1$3',
+                '$1$2$4$5',
+                '$1$2$3',
+                '$1:0',
+                '$1$2'
+            ),
+        $input);
+    }
+
+}

+ 96 - 0
src/App/Middlewares/MinimifierHtml.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace KarmaFW\App\Middlewares;
+
+use \KarmaFW\App\Request;
+use \KarmaFW\App\Response;
+
+
+class MinimifierHtml
+{
+    
+    public function __invoke(Request $request, Response $response, callable $next)
+    {
+        $response = $next($request, $response);
+
+        if (false) {
+            // modify css link files
+            $content = $response->getContent();
+            preg_match_all('#<link [^>]+"([^>]).css"#', $content, $regs);
+            pre($regs, 1);
+            $js_files = $regs[1];
+        }
+
+        // minimify html
+        $initial_content_length = $response->getContentLength();
+        $content_minimified = self::minify_html($response->getContent());
+        $response->setContent($content_minimified);
+        $final_content_length = $response->getContentLength();
+
+        // add information headers
+        $response->addHeader('X-Unminimified-Content-Length', $initial_content_length);
+        $response->addHeader('X-Minimified-Content-Length', $final_content_length);
+
+        return $response;
+    }
+
+
+
+    // HTML Minifier (source: https://gist.github.com/Rodrigo54/93169db48194d470188f )
+    public static function minify_html($input) {
+        if(trim($input) === "") return $input;
+        // Remove extra white-space(s) between HTML attribute(s)
+        $input = preg_replace_callback('#<([^\/\s<>!]+)(?:\s+([^<>]*?)\s*|\s*)(\/?)>#s', function($matches) {
+            return '<' . $matches[1] . preg_replace('#([^\s=]+)(\=([\'"]?)(.*?)\3)?(\s+|$)#s', ' $1$2', $matches[2]) . $matches[3] . '>';
+        }, str_replace("\r", "", $input));
+        // Minify inline CSS declaration(s)
+        if(strpos($input, ' style=') !== false) {
+            $input = preg_replace_callback('#<([^<]+?)\s+style=([\'"])(.*?)\2(?=[\/\s>])#s', function($matches) {
+                return '<' . $matches[1] . ' style=' . $matches[2] . MinimifierCss::minify_css($matches[3]) . $matches[2];
+            }, $input);
+        }
+        if(strpos($input, '</style>') !== false) {
+          $input = preg_replace_callback('#<style(.*?)>(.*?)</style>#is', function($matches) {
+            return '<style' . $matches[1] .'>'. MinimifierCss::minify_css($matches[2]) . '</style>';
+          }, $input);
+        }
+        if(strpos($input, '</script>') !== false) {
+          $input = preg_replace_callback('#<script(.*?)>(.*?)</script>#is', function($matches) {
+            return '<script' . $matches[1] .'>'. MinimifierJs::minify_js($matches[2]) . '</script>';
+          }, $input);
+        }
+
+        return preg_replace(
+            array(
+                // t = text
+                // o = tag open
+                // c = tag close
+                // Keep important white-space(s) after self-closing HTML tag(s)
+                '#<(img|input)(>| .*?>)#s',
+                // Remove a line break and two or more white-space(s) between tag(s)
+                '#(<!--.*?-->)|(>)(?:\n*|\s{2,})(<)|^\s*|\s*$#s',
+                '#(<!--.*?-->)|(?<!\>)\s+(<\/.*?>)|(<[^\/]*?>)\s+(?!\<)#s', // t+c || o+t
+                '#(<!--.*?-->)|(<[^\/]*?>)\s+(<[^\/]*?>)|(<\/.*?>)\s+(<\/.*?>)#s', // o+o || c+c
+                '#(<!--.*?-->)|(<\/.*?>)\s+(\s)(?!\<)|(?<!\>)\s+(\s)(<[^\/]*?\/?>)|(<[^\/]*?\/?>)\s+(\s)(?!\<)#s', // c+t || t+o || o+t -- separated by long white-space(s)
+                '#(<!--.*?-->)|(<[^\/]*?>)\s+(<\/.*?>)#s', // empty tag
+                '#<(img|input)(>| .*?>)<\/\1>#s', // reset previous fix
+                '#(&nbsp;)&nbsp;(?![<\s])#', // clean up ...
+                '#(?<=\>)(&nbsp;)(?=\<)#', // --ibid
+                // Remove HTML comment(s) except IE comment(s)
+                '#\s*<!--(?!\[if\s).*?-->\s*|(?<!\>)\n+(?=\<[^!])#s'
+            ),
+            array(
+                '<$1$2</$1>',
+                '$1$2$3',
+                '$1$2$3',
+                '$1$2$3$4$5',
+                '$1$2$3$4$5$6$7',
+                '$1$2$3',
+                '<$1$2',
+                '$1 ',
+                '$1',
+                ""
+            ),
+        $input);
+    }
+}

+ 47 - 0
src/App/Middlewares/MinimifierJs.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace KarmaFW\App\Middlewares;
+
+use \KarmaFW\App\Request;
+use \KarmaFW\App\Response;
+
+
+class MinimifierJs
+{
+    
+    public function __invoke(Request $request, Response $response, callable $next)
+    {
+        $response = $next($request, $response);
+
+        // TODO: reperer les balises <script src=...> dans le dom, récupérer le css correspondant, le minimifier et le lui créer un id de minification
+
+        return $response;
+    }
+
+
+	// JavaScript Minifier (source: https://gist.github.com/Rodrigo54/93169db48194d470188f )
+	public static function minify_js($input) {
+	    if(trim($input) === "") return $input;
+	    return preg_replace(
+	        array(
+	            // Remove comment(s)
+	            '#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*(?=[\n\r]|$)|^\s*|\s*$#',
+	            // Remove white-space(s) outside the string and regex
+	            '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s',
+	            // Remove the last semicolon
+	            '#;+\}#',
+	            // Minify object attribute(s) except JSON attribute(s). From `{'foo':'bar'}` to `{foo:'bar'}`
+	            '#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i',
+	            // --ibid. From `foo['bar']` to `foo.bar`
+	            '#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i'
+	        ),
+	        array(
+	            '$1',
+	            '$1$2',
+	            '}',
+	            '$1$3',
+	            '$1.$3'
+	        ),
+	    $input);
+	}
+}

+ 37 - 0
src/App/Middlewares/RedirectToDomain.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace KarmaFW\App\Middlewares;
+
+use \KarmaFW\App\Request;
+use \KarmaFW\App\Response;
+use \KarmaFW\App\ResponseRedirect;
+
+
+class RedirectToDomain
+{
+	protected $target_domain = 'example.com';
+	protected $redirect_domains = []; // www.example.com, example.fr, www.example.fr
+
+
+	public function __construct($target_domain, $redirect_domains=[])
+	{
+		$this->target_domain = strtolower($target_domain);
+		$this->redirect_domains = $redirect_domains;
+	}
+
+
+	public function __invoke(Request $request, Response $response, callable $next)
+	{
+		if (strtolower($request->SERVER['SERVER_NAME']) != $this->target_domain) {
+
+			if (empty($this->redirect_domains) || in_array($this->target_domain, $this->redirect_domains)) {
+				$redirect_url = 'https://' . $this->target_domain . $request->SERVER['REQUEST_URI'];
+				return new ResponseRedirect($redirect_url, $this->redirect_status);
+			}
+
+		}
+
+		return $next($request, $response);
+	}
+
+}

+ 5 - 1
src/App/Middlewares/SessionHandler.php

@@ -17,7 +17,11 @@ class SessionHandler
 
 		session_start();
 		
-		return $next($request, $response);
+		$response = $next($request, $response);
+
+		session_write_close();
+
+		return $response;
 	}
 
 }

+ 11 - 2
src/App/Middlewares/UrlRouter.php

@@ -4,6 +4,7 @@ namespace KarmaFW\App\Middlewares;
 
 use \KarmaFW\App\Request;
 use \KarmaFW\App\Response;
+use \KarmaFW\App\ResponseError;
 use \KarmaFW\App\ResponseError404;
 use \KarmaFW\App\ResponseRedirect;
 use \KarmaFW\App\ResponseFile;
@@ -38,8 +39,16 @@ class UrlRouter
 			$response = $next($request, $response);
 
 		} catch (\Throwable $e) {
-			echo "UrlRouter CATCHED EXCEPTION" . PHP_EOL; // TODO
-			print_r($e);
+			$content = null;
+
+			if (ENV == 'dev') {
+				$title = "UrlRouter CATCHED EXCEPTION";
+				$message = '<pre>' . print_r($e, true) . '</pre>';
+				$content = '<title>' . $title . '</title><h1>' . $title . '</h1><p>' . $message . '</p>';
+			}
+
+			//throw $e;			
+			return new ResponseError(500, $content);
 		}
 
 		return $response;

+ 10 - 2
src/App/Pipe.php

@@ -2,6 +2,13 @@
 
 namespace KarmaFW\App;
 
+//use \KarmaFW\App\Request;
+//use \KarmaFW\App\Response;
+
+
+// https://mnapoli.fr/presentations/forumphp-middlewares/
+// https://github.com/oscarotero/psr7-middlewares
+
 
 class Pipe
 {
@@ -13,9 +20,10 @@ class Pipe
         $this->services = $services;
     }
 
-    public function run()
+
+    public function process(Request $request, Response $response)
     {
-        
+        return $this->next($request, $response);
     }
 
     public function next(Request $request, Response $response)

+ 54 - 2
src/App/Request.php

@@ -7,6 +7,7 @@ class Request
 {
 	protected $url = null;
 	protected $method = null;
+	protected $client_ip = null;
 	public $GET = null;
 	public $POST = null;
 	public $COOKIE = null;
@@ -20,14 +21,29 @@ class Request
 	{
 		$this->url = $url;
 		$this->method = $method;
+
+		//print_r($_SERVER); exit;
 	}
 
 
 	public static function createFromArgv()
 	{
 		// TODO
-		//$request = new self($url, $method);
-		//return $request;
+		$request = new self(null, null);
+
+
+		$request->GET = isset($_GET) ? $_GET : [];
+		$request->POST = isset($_POST) ? $_POST : [];
+		$request->COOKIE = isset($_COOKIE) ? $_COOKIE : [];
+		$request->SESSION = isset($_SESSION) ? $_SESSION : [];
+		$request->ENV = isset($_ENV) ? $_ENV : [];
+		$request->FILES = isset($_FILES) ? $_FILES : [];
+		$request->SERVER = isset($_SERVER) ? $_SERVER : [];
+
+		$client_ip = null;
+		$request->setClientIp($client_ip);
+		
+		return $request;
 	}
 
 
@@ -55,6 +71,24 @@ class Request
 		$request->FILES = isset($_FILES) ? $_FILES : [];
 		$request->SERVER = isset($_SERVER) ? $_SERVER : [];
 
+
+		// Set Server name (if behind a proxy)
+		if (! empty($request->SERVER['HTTP_X_FORWARDED_HOST'])) {
+			// if "ProxyPreserveHost On" is not set in apache
+			$request->SERVER['HTTP_HOST']   = $request->SERVER['HTTP_X_FORWARDED_HOST'];
+			$request->SERVER['SERVER_NAME'] = $request->SERVER['HTTP_X_FORWARDED_HOST'];
+		}
+
+		// Set Client IP
+		$client_ip = null;
+		if (! empty($request->SERVER['REMOTE_ADDR'])) {
+			$client_ip = $request->SERVER['REMOTE_ADDR'];
+		}
+		if (! empty($request->SERVER['HTTP_X_FORWARDED_FOR'])) {
+			$client_ip = $request->SERVER['HTTP_X_FORWARDED_FOR'];
+		}
+		$request->setClientIp($client_ip);
+
 		return $request;
 	}
 
@@ -69,6 +103,24 @@ class Request
 		return $this->method;
 	}
 
+	public function getClientIp()
+	{
+		return $this->client_ip;
+	}
+
+	public function setClientIp($client_ip)
+	{
+		$this->client_ip = $client_ip;
+	}
+
+	public function isSecure()
+	{
+		return (! empty($this->SERVER['HTTPS']) && $this->SERVER['HTTPS'] == 'On')
+		    || (! empty($this->SERVER['REQUEST_SCHEME']) && $this->SERVER['REQUEST_SCHEME'] == 'https')
+		    || (! empty($this->SERVER['HTTP_X_FORWARDED_HTTPS']) && $this->SERVER['HTTP_X_FORWARDED_HTTPS'] == 'On')
+		    || (! empty($this->SERVER['HTTP_X_FORWARDED_SCHEME']) && $this->SERVER['HTTP_X_FORWARDED_SCHEME'] == 'https');
+	}
+
 	/*
 
 	public function setUrl($url)

+ 5 - 4
src/App/Response.php

@@ -88,6 +88,11 @@ class Response
 		$this->content_type = $content_type;
 	}
 
+	public function getBody()
+	{
+		return $this->getContent(); 
+	}
+
 	public function getContent()
 	{
 		return $this->content;
@@ -147,12 +152,8 @@ class Response
 		}
 
 		if (! empty($this->status)) {
-			// TODO
-
 			$status_name = empty($this->status_name) ? "Unknown http status" : $this->status_name;
-
 			header('HTTP/1.0 ' . $this->status . ' ' . $status_name);
-
 			$this->headers['X-Status'] = $this->status . ' ' . $status_name;
 		}
 

+ 6 - 1
src/App/ResponseFile.php

@@ -29,8 +29,13 @@ class ResponseFile extends Response
 			$this->headers['Content-Length'] = 0;
 
 		} else {
+			$content_type = mime_content_type($this->file_path);
+			if (empty($content_type)) {
+				$content_type = "application/octet-stream";
+			}
+
 			$this->headers['Content-Length'] = filesize($this->file_path);
-			$this->headers['Content-Type'] = "application/octet-stream";
+			$this->headers['Content-Type'] = $content_type;
 			$this->headers['Content-Transfer-Encoding'] = "Binary";
 			$this->headers['Content-disposition'] = 'attachment; filename="' . basename($this->file_path) . '"';
 		}

+ 142 - 0
src/Controllers/MinimifierController.php

@@ -0,0 +1,142 @@
+<?php
+
+namespace KarmaFW\Controllers;
+
+use \KarmaFW\Routing\Controllers\WebAppController;
+use \KarmaFW\App\Middlewares\MinimifierJs;
+use \KarmaFW\App\Middlewares\MinimifierCss;
+
+
+class MinimifierController extends WebAppController
+{
+	
+	public function minimifier_js($arguments=[])
+	{
+		//pre($arguments, 1);
+
+		$file_url = $arguments['file_url'];
+
+		$document_root = APP_DIR . '/public';
+
+		if (! is_dir($document_root)) {
+			if (! empty($_SERVER['DOCUMENT_ROOT'])) {
+				$document_root = realpath($_SERVER['DOCUMENT_ROOT']);
+
+			} else {
+				$document_root = '';
+			}
+		}
+
+		if ($document_root) {
+			$file_path = $document_root . $file_url;
+
+			if ($file_path != realpath($file_path) || substr($file_path, -3) != '.js') {
+				// file path invalid or not a js file
+				redirect($file_url);
+				/*
+				header('HTTP/1.1 404 Not Found');
+				echo "ERROR 404";
+				exit;
+				*/
+			}
+
+			if (! is_file($file_path)) {
+				// file not found
+				redirect($file_url);
+				/*
+				header('HTTP/1.1 404 Not Found');
+				echo "ERROR 404";
+				exit;
+				*/
+
+			} else {
+				header('Content-type: text/javascript');
+
+				//if (ENV == 'dev' && ! (defined('MINIMIFY_JS') && MINIMIFY_JS ) ) {
+				if (false) {
+					// NO minimification
+					readfile($file_path);
+
+				} else {
+					// minimification
+					$content = file_get_contents($file_path);
+					$content = MinimifierJs::minify_js($content);
+					echo $content;
+
+					// TODO: gerer cache-expire, expires, ...
+				}
+			}
+		}
+	}
+
+	
+	public function minimifier_css($arguments=[])
+	{
+		//pre($arguments, 1);
+
+		$file_url = $arguments['file_url'];
+
+		$document_root = APP_DIR . '/public';
+
+		if (! is_dir($document_root)) {
+			if (! empty($_SERVER['DOCUMENT_ROOT'])) {
+				$document_root = realpath($_SERVER['DOCUMENT_ROOT']);
+
+			} else {
+				$document_root = '';
+			}
+		}
+
+		if ($document_root) {
+			$file_path = $document_root . $file_url;
+
+			if ($file_path != realpath($file_path) || substr($file_path, -4) != '.css') {
+				// file path invalid or not a css file
+				redirect($file_url);
+				/*
+				header('HTTP/1.1 404 Not Found');
+				echo "ERROR 404";
+				exit;
+				*/
+			}
+
+			if (! is_file($file_path)) {
+				// file not found
+				redirect($file_url);
+				/*
+				header('HTTP/1.1 404 Not Found');
+				echo "ERROR 404";
+				exit;
+				*/
+
+			} else {
+				header('Content-type: text/css');
+
+				if (false) {
+					// NO minimification
+					readfile($file_path);
+
+				} else {
+					// minimification
+					$content = file_get_contents($file_path);
+					$content = MinimifierCss::minify_css($content);
+					echo $content;
+
+					// TODO: gerer cache-expire, expires, ...
+				}
+			}
+
+		} else {
+			// Error document root not found
+			redirect($file_url);
+		}
+	}
+
+	protected function redirectToUrl($url)
+	{
+		$continue_url = "";
+		redirect($continue_url);
+		//return new ResponseRedirect($continue_url, 302);
+	}
+
+}

+ 7 - 3
www/index.php

@@ -27,15 +27,19 @@ $app = new App([
     new KarmaMiddlewares\TrafficLogger,
     new KarmaMiddlewares\ErrorHandler,
     new KarmaMiddlewares\ResponseTime,
-    new KarmaMiddlewares\ForceHttps,
+    //new KarmaMiddlewares\MinimifierHtml,
+    //new KarmaMiddlewares\MinimifierJs,
+    //new KarmaMiddlewares\MinimifierCss,
+    //new KarmaMiddlewares\RedirectToDomain('www.mydomain.com', ['mydomain.com', 'mydomain.fr', 'www.mydomain.fr']),
+    //new KarmaMiddlewares\ForceHttps(302, ['www.mydomain.com']),
     //new KarmaMiddlewares\GzipEncoding,
     //new KarmaMiddlewares\MaintenanceMode,
     new KarmaMiddlewares\SessionHandler,
     //'handle404',
     //'Authentification',
-    //'CacheHtml',
-    //new KarmaMiddlewares\UrlPrefixRouter,
+    //new KarmaMiddlewares\CacheHtml(APP_DIR . '/var/cache/html', 3600),
     //new KarmaMiddlewares\CommandRouter($argv),
+    //new KarmaMiddlewares\UrlGroupRouter,
     new KarmaMiddlewares\UrlRouter,
 ]);