Location: PHPKode > scripts > PHP smart client loader > SM_2.3.php
<?PHP
/*!	
	http://code.google.com/p/phpscl/
	Feel Free To Use of course with needed modification
	This component is provided as it without any warranty
	Smart Client Loader v 1.0
	Don't remove this header from components files 
	Don't remove the http headr that sent with data to client 'X-Powered-By'
	http://mhameen.blogspot.com/
	hide@address.com
	hide@address.com 
	!--Don't remove this information
*/
#this file should included once "require_once or include_once"
	include_once 'jsmin.php';
	define('cssreq','ssm_css');
	define('jsreq','ssm_js');
	define ('cachepath',__DIR__.'/cache/');
	define ('csspath',__DIR__.'/css/');
	define ('jspath',__DIR__.'/js/');
	define('syl_Real_before_Symbolic',0);
	define('syl_RealPath',1);
	define('syl_SymbolicLinked',2);
	define('syl_Symbolic_before_Real',3);
	define('fileslist','flist');
	define('debugExt','debugExt');
	define('releaseExt','releaseExt');
	define('combine','combine');
	define('debug','debug');
	define('lang','lang');
	define('minify','minify');
	define('expirein','expirein');
	define('compress','compress');
	define('syl','syl');
	define('compresslevel','compresslevel');
	define('autoappendExt','autoappendExt');
	
	define('fileRedirect',false); #'true' in css @import,url('') use http reircted or 'false' proceess by SSM use cache & http compression 'recommended'

	$SSMdefaults = array(debugExt=>'debug',releaseExt=>'min',combine=>1,debug=>0,lang=>'',minify=>1,expirein=>365,compress=>1,syl=>0,compresslevel=>-1,autoappendExt=>1);
	$SSMsymbolicLink = array();	

	$requrl = $_SERVER['REQUEST_URI'];
	$requrlparts = explode('/',$requrl);
	if(in_array(cssreq,$requrlparts))SM_Request::processRequest(cssreq);
	if(in_array(jsreq,$requrlparts))SM_Request::processRequest(jsreq);
	
class SM{

	private $optionsStr='';
	private $html='';
	/*private $inst=null;	
	public static function addcss ($css,$options=array()){
	}	
	public static function addjs ($js,$options=array()){
	}*/
	
	private function getOptionsQuery($options){
		foreach($options as $k=>$v){
		$v = $v ? $v : 0;
		switch($k){ 
			  case 'combine' 	: $this->optionsStr .='&b='.$v;break;
			  case 'debug' 		: $this->optionsStr .='&d='.$v;break;
			  case 'debugExt' 	: $this->optionsStr .='&dext='.$v;break;
			  case 'releaseExt' : $this->optionsStr .='&rext='.$v;break;
			  case 'expirein' 	: $this->optionsStr .='&x='.$v;break;
			  case 'minify' 	: $this->optionsStr .='&m='.$v;break;
			  case 'compress'	: $this->optionsStr .='&c='.$v;break;
			  case 'lang'		: $this->optionsStr .='&g='.$v;break;
			  case 'syl'		: $this->optionsStr .='&syl='.$v;break;
			  case 'compresslevel':$this->optionsStr.='&cl='.$v;break;
			}
		}
	}
	
	function addCSS($css,$options=array(),$autowrite=true){
		$this->getoptionsquery($options);
		if(is_string($css)){ 			
				$h = '<link rel="stylesheet" type="text/css" href="'.cssreq.'/?l='. $css .$this->optionsStr.'" />';
				if($autowrite) echo $h; else $this->html.=$h;
		}
		if(is_array($css)){
			$listfiles = '';
			$debug   = array_key_exists('debug',$options)?$options[debug]:0;
			$combine = array_key_exists('combine',$options)?$options[combine]:1;
			$combine = $combine==2||(!$debug&&$combine>0);
			if($combine){
				foreach($css as $file){
					if(is_string($file)) $listfiles .= ','.$file;
					else if($options[debug])trigger_error('non string item');
				}
				$h =  '<link rel="stylesheet" type="text/css" href="'.cssreq.'/?l='.substr($listfiles,1) .$this->optionsStr.'" />';
				if($autowrite) echo $h; else $this->html.=$h;
			}else{
				foreach($css as $file){
					if(is_string($file)) $h =  '<link rel="stylesheet" type="text/css" href="'.cssreq.'/?l='. $file .$this->optionsStr.'" />';
					else if($options[debug])trigger_error('non string item');
				}
				if($autowrite) echo $h; else $this->html.=$h;
			}
		}
	}
	function addJS($js,$options=array(),$autowrite=true){
		$this->getoptionsquery($options);
		if(is_string($js)){ 
			$h = '<script type="text/javascript" language="javascript" src="'.jsreq.'/?l='.$js.$this->optionsStr.'"></script>';
			if($autowrite) echo $h; else $this->html.=$h;
		}
		if(is_array($js)){
			$listfiles = '';
			$debug   = array_key_exists('debug',$options)?$options[debug]:0;
			$combine = array_key_exists('combine',$options)?$options[combine]:1;
			$combine = $combine==2||(!$debug&&$combine>0);
			if($combine){
				foreach($js as $file){
					if(is_string($file)) $listfiles .= ','.$file;
					else if($options[debug])trigger_error('non string item');
				}
				$h = '<script type="text/javascript" language="javascript" src="'.jsreq.'/?l='.substr($listfiles,1).$this->optionsStr.'"></script>';
				if($autowrite) echo $h; else $this->html.=$h;
			}else{
				foreach($js as $file){
					if(is_string($file)) $h = '<script type="text/javascript" language="javascript" src="'.jsreq.'/?l='.$file.$this->optionsStr.'"></script>';
					else if($options[debug])trigger_error('non string item');
				}
				if($autowrite) echo $h; else $this->html.=$h;
			}
		}
	}	

	 public function __toString() {
        return $this->html;
    }

}

/* this class for internal use only */
class SM_Request{
	
	private $SSMdefaults,$SSMsymbolicLink;
	private $options,$content,$cachemtime,$templatemtime,$selfilepath,$file_,$req;	
	public function __construct(){
		 $this->SSMdefaults=$GLOBALS['SSMdefaults'];$this->SSMsymbolicLink=$GLOBALS['SSMsymbolicLink'];
		 $this->options=array();$this->content='';$this->cachemtime=0;$this->templatemtime=0;
	}
	public static function processRequest($reqType){
		$smr = new SM_Request;
		$smr->req = $reqType;
		if(!empty($reqType)){
			$smr->getOptions();
			if(strpos($_SERVER['REQUEST_URI'],"/{$reqType}/?")!==false){		
				$smr->getContent();
			}else{
				if(fileRedirect){
					$dir = ($reqType===cssreq)?csspath:jspath;
					$dir = substr($dir,strlen(__DIR__));
					$urlstr = str_replace("/{$reqType}/","{$dir}",$_SERVER['REQUEST_URI']);
					header("HTTP/1.1 302 Found");
					header("Location: {$urlstr}");
				}else{
					$file_= substr($_SERVER['REDIRECT_URL'],strpos($_SERVER['REDIRECT_URL'],$reqType)+strlen($reqType));
					$smr->options[minify]=0;
					$smr->options[autoappendExt]=0;
					$smr->options[fileslist] = (($reqType===cssreq)?csspath:jspath).$file_;
					$smr->getContent(false);				
					$ext=pathinfo($smr->selfilepath,PATHINFO_EXTENSION);
					if($ext==='css')$mimetype='text/css';
					else if($ext==='js')$mimetype='application/x-javascript; charset=UTF-8';
					else $mimetype=mime_content_type($smr->selfilepath);
					header("Content-Type: $mimetype");				
					echo $smr->content;
				}
			}
		}
	}
	
	function getLinkPath($path){
		$path = strtolower($path);
		while(strpos($path,'/')===0||strpos($path,'\\')===0)$path=substr($path,1);
		foreach ($this->SSMsymbolicLink as $link => $target) {
			   $link = strtolower($link);
			   if (0 === strpos($path, $link)){
					#replace $target with $link
					$path = $target.'/'. substr($path, strlen($link));
					$realPath = realpath($path);
					#if($realPath !== false ) $path = $realPath;
					return $path;
				}
			}
		return $path;
	}

	function getOptions(){		
		foreach($_GET as $k=>$v){
			$value  = empty($v) ? null : $v;
			switch($k){
			  case 'l'		:$this->options[fileslist] = $value; break;
			  case 'b'		:$this->options[combine] = $value; break;
			  case 'd'		:$this->options[debug] = $value; break;
			  case 'dext'	:$this->options[debugExt] = $value; break;
			  case 'rext'	:$this->options[releaseExt] = $value; break;
			  case 'x'		:$this->options[expirein] = $value; break;
			  case 'm'		:$this->options[minify] = $value; break;
			  case 'c'		:$this->options[compress] = $value; break;
			  case 'g'		:$this->options[lang] = $value; break;
			  case 'syl'	:$this->options[syl] = $value;break;
			  case 'cl'		:$this->options[compresslevel] = $value;break;
			}
		}
		$this->options=array_merge($this->SSMdefaults,$this->options);
	}

	function minifyCSS($css){
			$css = trim($css);
			$css = str_replace("\r\n", "\n", $css);
			$search = array("/\/\*[^!][\d\D]*?\*\/|\t+/","/\s+/", "/\}\s+/");
			$replace = array(null," ", "}\n");
			$css = preg_replace($search, $replace, $css);
			$search = array("/;[\s+]/","/[\s+];/","/\s+\{\\s+/", "/\\:\s+\\#/", "/,\s+/i", "/\\:\s+\\\'/i","/\\:\s+([0-9]+|[A-F]+)/i","/\{\\s+/","/;}/");
			$replace = array(";",";","{", ":#", ",", ":\'", ":$1","{","}");
			$css = preg_replace($search, $replace, $css);
			$css = str_replace("\n", null, $css);
			return $css;	
	}
	function minifyJS($js){
		if(class_exists ('JSMin')){
			$js=JSMin::minify($js);
			return $js;
		}
		return "/*JSMin not found*/\n$js";	
	}
	function getfilename($file){
			/*! you can modifiy if you want
			file.d/r ext.lang.ext
			file.d/r ext.ext
			file.lnag.ext
			file.ext*/
			$drext = $this->options[debug] ? $this->options[debugExt] : $this->options[releaseExt];
			$lang = $this->options[lang];
			$dir  = pathinfo($file,PATHINFO_DIRNAME);
			$base  = pathinfo($file,PATHINFO_FILENAME );
			$ext  = pathinfo($file,PATHINFO_EXTENSION);
			$lang = $lang ? '.'.$lang : '';$drext=$drext?'.'.$drext:'';
			return array ($dir.'/'.$base.$drext.$lang.'.'.$ext,$dir.'/'.$base.$drext.'.'.$ext,$dir.'/'.$base.$lang.'.'.$ext,$dir.'/'.$base.'.'.$ext);
	}
	function getContent($write=true){		
		$files = explode(',',$this->options[fileslist]);
		$path = ($this->req === cssreq) ? csspath : jspath;
		$this->content='';$this->cachemtime=0;$this->templatemtime=0;
		foreach($files as $fk=>$file){ 
			$this->selfilepath = null;$ofilename=$file;
			if($this->options[autoappendExt]){			
				if(($this->req === cssreq)&&strpos($file,'.css')===false)	$file.= '.css' ;
				if(($this->req === jsreq)&&strpos($file,'.js')===false)$file.= '.js' ;
			}
			switch ($this->options[syl]){
				case 0: #syl_Real_before_Symbolic					
				case 1: #syl_RealPath
					$filenames = $this->getfilename($path.$file);
					foreach($filenames as $f){if(file_exists($f)){$this->selfilepath=$f;break;}}break;
					break;
				case 2: #syl_SymbolicLinked
				case 3: #syl_Symbolic_before_Real
					$file = $this->getLinkPath($file);
					$filenames = $this->getfilename($file);
					foreach($filenames as $f){if(file_exists($f)){$this->selfilepath=$f;break;}}
					break;
			}
			if(empty($this->selfilepath)){
				switch ($this->options[syl]){
					case 0:			
						$file = $this->getLinkPath($file);
						$filenames = $this->getfilename($file);
						foreach($filenames as $f){if(file_exists($f)){$this->selfilepath=$f;break;}}					
					break;
					case 3:
						$filenames = $this->getfilename($path.$file);
						foreach($filenames as $f){if(file_exists($f)){$this->selfilepath=$f;break;}}break;
					break;
				}
			}
			if(empty($this->selfilepath)){	
				$this->content.="/*File Not Found. : {$ofilename}*/\r\n";
			}
			if($this->options[debug]){
				if(file_exists($this->selfilepath))$fcontent = file_get_contents($this->selfilepath);
				else $this->content.="/*File Not Found. : {$ofilename}*/";
				if($this->options[minify]==2) $fcontent = ($this->req === cssreq) ? $this->minifyCSS($fcontent) : $this->minifyJS($fcontent);
				$this->content .= $fcontent;
				unset($fcontent);
			}else{
				$this->templatemtime = filemtime($this->selfilepath);
				$f_k_ = str_replace(array('/'.'\\',':'),array('sl','bs','dd') ,$file);
				if(file_exists($this->selfilepath))$files[$f_k_] = $this->selfilepath;
				unset($files[$fk]);
			}		
		}
		if(!$this->options[debug]){
			$compress =	$this->options[compress];
			if($compress && ! ini_get('zlib.output_compression') && 'ob_gzhandler' != ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING'])){			
				if ( false !== strpos( strtolower($_SERVER['HTTP_ACCEPT_ENCODING']), 'gzip') && function_exists('gzencode') && $this->options[compress]!='deflate' )$compress='gzip';
				else if ( false !== strpos( strtolower($_SERVER['HTTP_ACCEPT_ENCODING']), 'deflate') && function_exists('gzdeflate') && $this->options[compress]!=='gzip' )$compress='deflate';
			}
			$cachename=str_replace(array('/','\\','$','.','=',',','&','gzip','deflate'),array('sl','bs','sd','dt','eq','cm','nd','1','1') ,$_SERVER['QUERY_STRING']);
			$cachepath = ($this->req === cssreq) ? cachepath.'/css/' : cachepath.'/js/';
			if(!empty($cachename)){$cachename = $cachepath.$cachename;}
			else {$cachename = $cachepath.$this->file_;}
			if (!is_dir(dirname($cachename)))mkdir(dirname($cachename),0,true);	
			$this->cachemtime = file_exists($cachepath.$cachename)? filemtime($cachepath.$cachename):0;
			if($this->cachemtime <= $this->templatemtime){
				foreach($files as $fn=>$file){
					if($this->options[minify]){				
						$fmtime = filemtime($file);
						$fcachemtime = file_exists("{$cachepath}/{$fn}")?filemtime("{$cachepath}/{$fn}"):0;
						if($fmtime>$fcachemtime){
							$fcontent = file_get_contents($file);
							$fcontent = ($this->req === cssreq) ? $this->minifyCSS($fcontent) : $this->minifyJS($fcontent);
							if (!is_dir(dirname("{$cachepath}/{$fn}")))mkdir(dirname("{$cachepath}/{$fn}"),0,true);
							file_put_contents("{$cachepath}/{$fn}",$fcontent);
							$this->content .= $fcontent;
							unset($fcontent);
						}else $this->content .= file_get_contents("{$cachepath}/{$fn}");		
					}else $this->content .= file_get_contents($file);
				}
				if($compress==='gzip') {
					header('Vary: Accept-Encoding');
					header('Content-Encoding: gzip');
					$this->content = gzencode($this->content,$this->options[compresslevel]);
				}
				else if($compress==='deflate') {
					header('Vary: Accept-Encoding');
					header('Content-Encoding: deflate');
					$this->content = gzdeflate($this->content,$this->options[compresslevel]);
				}
				file_put_contents($cachename.$compress,$this->content);
			}else{
				$this->content = file_get_contents($cachename.$compress);
			}
			header("Date: " . date("D, j M Y G:i:s ", $this->templatemtime) . 'GMT');				
			if($this->options[expirein]>0)
			{
			 header("Expires: " . gmdate("D, d M Y H:i:s", time() + $this->options[expirein]*3600*24) . " GMT");
			 header("Cache-Control: public, must-revalidate, max-age=".$this->options[expirein]*3600*24);
			}
			else header("Cache-Control: max-age=86400, must-revalidate"); #HTTP/1.1
			header("Pragma: cache");        #HTTP/1.0
			header('ETag: '. sha1($this->content));
			header('Content-Length: ' . strlen($this->content));
			header('X-Powered-By: SmartClientLoader 1.0'); #!dont remove this header
			if($write){
				#there is some debate over the ideal JS Content-Type, but this is the
				$contenttype = ($this->req === cssreq)?'text/css':'application/x-javascript; charset=UTF-8';
				header("Content-Type: $contenttype");
				echo $this->content;		
			}
		}else{
			header("Cache-Control: max-age=60, must-revalidate"); #HTTP/1.1
			header("Pragma: no-cache");        #HTTP/1.0
			if($write){
				#there is some debate over the ideal JS Content-Type, but this is the
				$contenttype = ($this->req === cssreq)?'text/css':'application/x-javascript; charset=UTF-8';		
				header("Content-Type: $contenttype");
				echo $this->content;
			}
		}	
	}
}
define('SCL','Smart Client Loader 1.0');
define('SCL_version',1.0);
?>
Return current item: PHP smart client loader