<?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);
?>