From 890305bb9b3a66098d861b7616f68b664abe24d3 Mon Sep 17 00:00:00 2001 From: hakito Date: Wed, 5 Oct 2011 12:09:38 +0300 Subject: [PATCH] Added support for Data URIs to be automatically embedded into the cached CSS file for browser that support it. --- views/helpers/asset.php | 142 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/views/helpers/asset.php b/views/helpers/asset.php index 539f185..8435bc1 100644 --- a/views/helpers/asset.php +++ b/views/helpers/asset.php @@ -247,7 +247,7 @@ function __process($type, $assets) { //check if the cached file exists $scripts = Set::extract('/script', $assets); - $fileName = $folder->find($this->__generateFileName($scripts) . '_([0-9]{10}).' . $type); + $fileName = $folder->find($this->__generateFileName($scripts, $type) . '_([0-9]{10}).' . $type); if ($fileName) { //take the first file...really should only be one. $fileName = $fileName[0]; @@ -309,6 +309,14 @@ function __process($type, $assets) { $buffer = $this->__preprocessCss($asset, $buffer); } + // Replace with Data Uri + if (self::__dataURIsupported()) + { + $w = '[ \t\r\n\f]*'; + $quote = '["\']?'; + $css_uri = '(url\('.$w.$quote.')([^\)"\']+)('.$quote.$w.'\))'.$w.'/\*DATA_URI\*/'; + $buffer = preg_replace_callback('|'.$css_uri.'|', 'AssetHelper::__replaceWithDataUri', $buffer); + } $tidy->parse($buffer); $buffer = $tidy->print->plain(); break; @@ -323,7 +331,7 @@ function __process($type, $assets) { } //write the file - $fileName = $this->__generateFileName($scripts) . '_' . $ts . '.' . $type; + $fileName = $this->__generateFileName($scripts, $type) . '_' . $ts . '.' . $type; $file = new File($this->paths['wwwRoot'] . $this->options['cachePaths'][$type] . DS . $fileName); $file->write(trim($scriptBuffer)); } @@ -405,16 +413,20 @@ function __findFile(&$asset, $type) { * Generate the cached filename. * * @param array $names an array of the original file names + * @param string $type css or js * @return string * @access private */ - function __generateFileName($names) { + function __generateFileName($names, $type) { $fileName = Sanitize::paranoid(str_replace('/', '-', implode('_', $names)), array('_', '-')); if ($this->options['md5FileName']) { $fileName = md5($fileName); } + if (self::__dataURIsupported() && $type == 'css') + $fileName .= '_embedded'; + return $fileName; } @@ -428,5 +440,129 @@ function __getPath($type) { return false; } + + /** + * + * Detect browser and version + * @param unknown_type $user_agent + * @return number|multitype:string number browser and version + */ + private static function __detect_browser ( $user_agent = '' ) + { + if (! function_exists ( 'stripos' )) { + function stripos ( $haystack , $needle , $offset = 0 ) { + return strpos ( strtolower ( $haystack ), strtolower ( $needle ), $offset ); + } + } + $user_agent = empty( $user_agent ) ? $_SERVER [ 'HTTP_USER_AGENT' ] : $user_agent ; + $browser = array( 'name' => 'default' , 'ver' => 0 ); + if ( stripos ( $user_agent , 'Opera' ) !== false ) { + $browser [ 'name' ] = 'opera' ; + if( stripos ( $user_agent , 'Version' ) !== false ) { + # Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.2.15 Version/10.00 + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'version/' , strtolower ( $user_agent )))))); + } + else { + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , substr ( $user_agent , ( stripos ( $user_agent , 'opera' ) + strlen ( 'opera' ) + 1 ))))); + } + } + elseif ( stripos ( $user_agent , 'MSIE' ) !== false ) { + $browser [ 'name' ] = 'ie' ; + $browser [ 'ver' ] = rtrim ( current ( explode ( ' ' , trim ( end ( explode ( 'msie' , strtolower ( $user_agent )))))), ';' ); + } + ## Webkit (Safari/Chrome) + elseif ( stripos ( $user_agent , 'AppleWebKit' ) !== false ) { + $browser [ 'name' ] = 'applewebkit' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , substr ( $user_agent , ( stripos ( $user_agent , 'applewebkit' ) + strlen ( 'AppleWebKit' ) + 1 ))))); + } + ## Gecko/Netscape/Firefox/Flock/Mozilla/Camino/SeaMonkey + elseif ( stripos ( $user_agent , 'Gecko' ) !== false && stripos ( $user_agent , 'like Gecko' ) === false ) { + if ( stripos ( $user_agent , 'Navigator' ) !== false ) { + ##Netscape 9+ + $browser [ 'name' ] = 'netscape' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'navigator/' , strtolower ( $user_agent )))))); + } + elseif ( stripos ( $user_agent , 'Firefox' ) !== false ) { + ## Firefox 0.10 + + $browser [ 'name' ] = 'firefox' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'firefox/' , strtolower ( $user_agent )))))); + } + elseif( stripos ( $user_agent , 'Netscape6' ) !== false ){ + #Netscape 6 + $browser [ 'name' ] = 'netscape' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'netscape6/' , strtolower ( $user_agent )))))); + } + elseif( stripos ( $user_agent , 'Netscape' ) !== false ){ + ## Netscape 7-9 + $browser [ 'name' ] = 'netscape' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'netscape/' , strtolower ( $user_agent )))))); + } + } + elseif( stripos ( $user_agent , 'Googlebot' ) !== false ){ + ## Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) + $browser [ 'name' ] = 'googlebot' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'googlebot/' , strtolower ( $user_agent ))))), ';' ); + } + elseif( stripos ( $user_agent , 'msnbot' ) !== false ){ + ## msnbot/1.0 (+http://search.msn.com/msnbot.htm) + $browser [ 'name' ] = 'msnbot' ; + $browser [ 'ver' ] = trim ( current ( explode ( ' ' , end ( explode ( 'msnbot/' , strtolower ( $user_agent ))))), ';' ); + } + elseif( stripos ( $user_agent , 'Yahoo! Slurp' ) !== false ){ + ## Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp) + $browser [ 'name' ] = 'yahoo' ; + $browser [ 'ver' ] = 1 ; + } + $browser [ 'ver' ] = (float) $browser [ 'ver' ]; + return $browser ; + } + + private static $DATA_URI_SUPPORTED = null; + + /** + * + * Detect browser data uri support + */ + private static function __dataURIsupported () + { + if (self::$DATA_URI_SUPPORTED != null) + return self::$DATA_URI_SUPPORTED; + $supported = false ; + $browser = self::__detect_browser (); + if ( $browser [ 'name' ] == 'ie' && $browser [ 'ver' ]> 7.9 ) { + $supported = true ; + } + elseif( $browser [ 'name' ] == 'applewebkit' ) { + $supported = true ; + } + elseif( ( $browser [ 'name' ] == 'firefox' && $browser [ 'ver' ]> 2 ) || ( $browser [ 'name' ] == 'opera' && $browser [ 'ver' ]> 8 ) || ( $browser [ 'name' ] == 'netscape' && $browser [ 'ver' ]> 7 )) { + $supported = true ; + } + self::$DATA_URI_SUPPORTED == $supported; + return $supported ; + } + + /** + * + * Function for preg_replace_callback to substitute all URIs with Data URIs containing base 64 encoded file data + * If file cannot be found or mime type cannot be determined the uri string is returned. + * @param array $matches + */ + private static function __replaceWithDataUri($matches) + { + $file_loc = APP.DS.WEBROOT_DIR.$matches[2]; + $filename = realpath($file_loc); + + if (!file_exists($filename)) + return ($matches[0]); + + $imagetype = exif_imagetype($filename); + if ($imagetype === false) + return ($matches[0]); + $mime = image_type_to_mime_type($imagetype); + + $data_uri = "data:$mime;base64,".base64_encode(file_get_contents($filename)); + return $matches[1].$data_uri.$matches[3]; + } } ?> \ No newline at end of file