Merge branch 'master' of http://git.roojs.com:8081/Pman.Core
[Pman.Core] / Asset.php
1 <?php
2  
3  /**
4   * Generic cached assset server... -- No security om this.. should only return compressed CSS/JS
5   *
6   * Does a few tricks with headers to improve caching...
7   *
8   *
9   * Also includes code to generate assets...
10   *
11   * methods outputJavascriptDir / outputCssDir generate links to 
12   *    BASEURL/Asset/css/xxxx.yyy.zzz
13   *    BASEURL/Asset/js/xxxx.yyy.zzz
14   *
15   *   then
16   *   we deliver the file from
17   *       SESSION-DIR/{$www-user}-{$ff->project}-$ff->version}-{js|css}-compile/{filename}/PATH';
18   *
19   *   
20   */
21  
22 require_once 'Pman.php';
23
24 class Pman_Core_Asset extends Pman {
25      
26     var $types = array(
27         'css' => 'text/css',
28         'js' => 'text/javascript',
29         'map' => 'application/json'
30     );
31     
32     function getAuth()
33     {
34         return true;
35     }
36     
37     
38     function get($s='', $opts = Array())
39     {
40         $this->sessionState(0);
41         
42         $bits = explode('/', $s);
43         
44         if (empty($bits[0]) || empty($bits[1])  || !isset($this->types[$bits[0]])) {
45             $this->jerr("invalid url");
46         }
47        
48         $ext = $bits[0];
49         if (preg_match('/\.map$/',$_SERVER['REQUEST_URI'])) {
50             $ext = 'map';
51         }
52        
53         $s = str_replace('/', '-', $bits[1]);
54         
55         
56         $ui = posix_getpwuid(posix_geteuid());
57         $ff = HTML_FlexyFramework::get();
58         
59         $compile = self::getCompileDir($bits[0], '', false);
60         
61         $fn = $compile . '/'. $s .'.'. $ext;
62         
63         if (!file_exists($fn)) {
64             header('Content-Type: '. $this->types[$ext]);
65         
66             echo "// compiled file not found = $fn";
67             exit;
68         }
69         
70         $supportsGzip = !empty($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false;
71
72         
73         $last_modified_time = filemtime($fn);
74         
75         
76         if (
77             (
78                 isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
79                 strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time
80             )
81             ||
82             (
83                  isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
84                 trim($_SERVER['HTTP_IF_NONE_MATCH']) == md5($fn)
85             )) { 
86             header("HTTP/1.1 304 Not Modified");
87             exit;
88         }
89         
90         header('Content-Type: '. $this->types[$bits[0]]);
91         
92         
93         header("Pragma: public");
94         
95         header('Cache-Control: max-age=2592000, public');
96         header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 2592000));
97         header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', $last_modified_time));
98         header('Etag: '. md5($fn)); 
99         
100          if ( $supportsGzip ) {
101             $content = gzencode( file_get_contents($fn) , 9);
102             
103             header('Content-Encoding: gzip');
104             header('Vary: Accept-Encoding');
105             header('Content-Length: '. strlen($content));
106             
107             echo $content;
108             
109         } else {
110             
111             
112             $fh = fopen($fn,'r');
113             fpassthru($fh);
114             fclose($fh);
115              
116         }
117         
118         
119         
120         exit;
121         
122     }
123     
124     function post($s='') {
125         if(!empty($_REQUEST['_clear_cache'])) {
126             $this->clearCompiledFilesCache();
127         }
128         
129         die('invalid');
130     }
131      
132     static function getCompileDir($type, $module = '', $is_mkdir = true)
133     {
134         $ff = HTML_FlexyFramework::get();
135         
136         $ui = posix_getpwuid(posix_geteuid());
137         
138         $compile_dir = session_save_path() . "/";
139         
140         if (empty($module)) {
141             $module = $ff->project . (isset($ff->appNameShort) ?  '_' . $ff->appNameShort : '');
142         }
143         
144         
145         switch($type) {
146             case 'js':
147             case 'css':
148             case 'scss':
149                 $compile_dir .= implode("-", array(
150                     $ui['name'],
151                     $module,
152                     $ff->version,
153                     "{$type}compile"
154                 ));
155                 break;
156             // template config?
157             default:
158                 return false;
159         }
160         
161         
162         if (file_exists($compile_dir)) {
163             return $compile_dir;
164         }
165         
166         if(!$is_mkdir) {
167             return false;
168         }
169         
170         if(mkdir($compile_dir, 0700, true)) {
171             return $compile_dir;
172         }
173         
174         return false;
175     }
176     
177     function clearCompiledFilesCache()
178     {
179         $au = $this->getAuthUser();
180         if (!$au && !in_array($_SERVER['REMOTE_ADDR'] , array('127.0.0.1','::1'))) {
181             $this->jerr("Cache can only be cleared by authenticated users");
182         }
183         
184         require_once 'System.php';
185         $ff = HTML_FlexyFramework::get();
186         
187         $mods = $this->modulesList();
188         $mods[] = $ff->project; // Pman - this was the old format...
189         $mods[] = ''; // Pman + appshortname..
190         
191         foreach ($mods as $module) {
192             $compile_dir = $this->getCompileDir('js', $module, false);
193         
194             if(!empty($compile_dir)) {
195                 System::rm(array('-r', $compile_dir));
196             }
197             $compile_dir = $this->getCompileDir('css', $module, false);
198         
199             if(!empty($compile_dir)) {
200                 System::rm(array('-r', $compile_dir));
201             }
202         }
203          
204         $this->jok('DONE');
205     }
206 }