Max F 5 роки тому
батько
коміт
e9bc8dedd5

+ 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;
+    }
+
+}

+ 9 - 3
src/App/Middlewares/ForceHttps.php

@@ -10,19 +10,25 @@ 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)
+	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)
 	{
 		if (! $request->isSecure()) {
-			$redirect_url = 'https://' . $request->SERVER['SERVER_NAME'] . $request->SERVER['REQUEST_URI'];
-			return new ResponseRedirect($redirect_url, $this->redirect_status);
+			
+			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);
+    }
+
+}

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

@@ -0,0 +1,88 @@
+<?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);
+
+        $initial_content_length = $response->getContentLength();
+
+        $content_minimified = self::minify_html($response->getContent());
+        $response->setContent($content_minimified);
+        
+        $final_content_length = $response->getContentLength();
+
+        $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;
 	}
 
 }

+ 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,
 ]);