1 | <?php |
---|
2 | /** |
---|
3 | * t29v6 new Hostinfo and Hosthook system. |
---|
4 | * |
---|
5 | * Local host.php files in the webroot can hook into t29* php |
---|
6 | * and js classes without interfering the code. This can be usually |
---|
7 | * be used for extra svn information. |
---|
8 | * Hostinfos can also be appended in this file and therefore be |
---|
9 | * managed centrally. |
---|
10 | * |
---|
11 | * webroot/host.php muss have a t29LocalHost extends t29Host class. |
---|
12 | * |
---|
13 | **/ |
---|
14 | |
---|
15 | abstract class t29Host { |
---|
16 | const webroot_host_file = '/host.php'; # relative to webroot |
---|
17 | const webroot_local_host_classname = 't29LocalHost'; |
---|
18 | const env_hidesuffix_name = "T29URLHIDESUFFIX"; |
---|
19 | |
---|
20 | /// $hostname: An identifier like a FQDN. Is only used to identify the t29Host instance and not |
---|
21 | /// for constructing any URL. |
---|
22 | /// This value must be overwritten in child classes! |
---|
23 | public $hostname = "undefined"; |
---|
24 | |
---|
25 | /// $document_root := realpath($_SERVER['DOCUMENT_ROOT']), performed by setup(). |
---|
26 | /// Can be used to identify the unix file path to the webserver docroot of the |
---|
27 | /// webhost. Independent of the t29 system. |
---|
28 | public $document_root; |
---|
29 | |
---|
30 | /// $webroot: The unix file path to the t29 web installation, actually the parent directory |
---|
31 | /// of the lib/ directory. Is widely used by many files and also computed by themselves. |
---|
32 | public $webroot; |
---|
33 | /// $lib := realpath(__FILE__), just for convenience. $lib = "$webroot/lib" always holds. |
---|
34 | public $lib; |
---|
35 | |
---|
36 | /// $web_prefix: The URL path to the webroot. Example: |
---|
37 | /// http://example.com/path/to/t29/de/page.php |
---|
38 | /// ^^^^^^^^^^^^ |
---|
39 | /// This part is the web prefix, if /de/page.php is the script_filename. |
---|
40 | /// This value is computed by setup(). |
---|
41 | public $web_prefix = ""; |
---|
42 | |
---|
43 | /// $has_web_prefix := !empty($web_prefix). If this host is installed in root or not |
---|
44 | public $has_web_prefix = false; |
---|
45 | |
---|
46 | /// $script_filename: The t29-internal identifying url path, like "/de/page.php" or "/en". |
---|
47 | /// While $_SERVER['SCRIPT_FILENAME'] still contains the $web_prefix, this |
---|
48 | /// string is sanitized. |
---|
49 | /// This value is computed by setup(). |
---|
50 | public $script_filename; |
---|
51 | |
---|
52 | /// $slash_filename: Cross-platform $script_filename, always starting with a "/". |
---|
53 | public $slash_filename; |
---|
54 | |
---|
55 | /// $ressources: CSS and JavaScript file paths ("Assets"), as used by the RessourceLoader, |
---|
56 | /// the loader.php and technikum29.php entry points and the Template. |
---|
57 | private function ressources_array($webroot='') { |
---|
58 | // this is implemented as method, because of |
---|
59 | // 1. "$webbroot/..." like strings. This isn't a good idea anyway (e.g. in ressourceloader: $module_dir_rel2webroot |
---|
60 | // 2. Closures: function($conf){...} doesn't work as class attribute. |
---|
61 | // This is rather dirty, but anyway the supposed way to access these data is the public get_ressources(). |
---|
62 | $ressources = array( |
---|
63 | 'cache_file' => array('compressed.js', 'style.css'), |
---|
64 | 'module_dir' => array("$webroot/shared/js-v6/modules", "$webroot/shared/css-v6/modules"), |
---|
65 | 'page_dir' => array("$webroot/shared/js-v6/pagescripts", "$webroot/shared/css-v6/pagestyles"), |
---|
66 | 'glob_pattern' => array('*.js', '*.css'), |
---|
67 | 'content_types' => array('application/javascript', 'text/css'), |
---|
68 | 'class' => array('t29JavaScriptRessourceLoader', 't29StyleSheetRessourceLoader'), |
---|
69 | 'modules' => function($conf){ return glob($conf['module_dir'] . '/' . $conf['glob_pattern']); }, |
---|
70 | ); |
---|
71 | return $ressources; |
---|
72 | } |
---|
73 | |
---|
74 | /// $ressources_types: The Ressources array above consists of numeric arrays. This array |
---|
75 | /// maps those positions (numeric keys) to $conf array positions. |
---|
76 | /// Use get_ressources() to resolve this mapping. |
---|
77 | private $ressources_types = array('js', 'css'); |
---|
78 | |
---|
79 | public function get_ressources($type, $webroot, $debug_flag=false) { |
---|
80 | $typepos = array_search($type, $this->ressources_types); |
---|
81 | if($typepos === FALSE) return null; |
---|
82 | $conf = array_map(function($val) use($typepos) |
---|
83 | { return is_array($val) ? $val[$typepos] : $val; }, |
---|
84 | $this->ressources_array($webroot)); |
---|
85 | $conf['type'] = $type; |
---|
86 | // callback functions need the $conf we built. |
---|
87 | $conf['modules'] = call_user_func($conf['modules'], $conf); |
---|
88 | $conf['debug'] = $debug_flag; // skip cache and just concat everything |
---|
89 | return $conf; |
---|
90 | } |
---|
91 | |
---|
92 | /** |
---|
93 | * A special helper class, used by t29Template and technikum29.php entry point. |
---|
94 | * The general (clean) way would be querying get_ressources(). |
---|
95 | * There is also t29RessourceLoader::get_page_specific_urls() which basically does |
---|
96 | * the same, just using the global conf array. |
---|
97 | **/ |
---|
98 | public function ressources_get_pagestyle($seiten_id) { |
---|
99 | $ressources = $this->ressources_array(); |
---|
100 | // We address the css property directly with the [1] index. Bad! |
---|
101 | return $ressources['page_dir'][1] . '/' . $seiten_id . '.css'; |
---|
102 | } |
---|
103 | |
---|
104 | /// Singleton fun for detect() |
---|
105 | private static $instance; |
---|
106 | private static function new_singleton($classname) { |
---|
107 | if(!isset(self::$instance)) |
---|
108 | self::$instance = new $classname; |
---|
109 | return self::$instance; |
---|
110 | } |
---|
111 | |
---|
112 | /** |
---|
113 | * Factory for creating a t29Host instance automatically |
---|
114 | * from the current host. This method will decide which |
---|
115 | * subclass has to be taken. |
---|
116 | * This function als implements the Singleton pattern, so |
---|
117 | * you can call it frequently. |
---|
118 | **/ |
---|
119 | static function detect() { |
---|
120 | $instance = null; |
---|
121 | |
---|
122 | // check if local host file exists |
---|
123 | $hostfile = dirname(__FILE__) . '/../' . self::webroot_host_file; |
---|
124 | if(file_exists($hostfile)) { |
---|
125 | include $hostfile; |
---|
126 | if(class_exists(self::webroot_local_host_classname)) { |
---|
127 | $x = self::webroot_local_host_classname; |
---|
128 | $host = self::new_singleton($x); |
---|
129 | $host->setup(); |
---|
130 | return $host; |
---|
131 | } else { |
---|
132 | print "Warning: Hostfile $hostfile does not contain class ".self::webroot_local_host_classname."\n"; |
---|
133 | } |
---|
134 | } |
---|
135 | |
---|
136 | // Quick and Dirty: Load hostname specific instances |
---|
137 | switch($_SERVER['SERVER_NAME']) { |
---|
138 | case 'heribert': |
---|
139 | case 'localhost': |
---|
140 | $localhost = self::new_singleton('t29HeribertHost'); |
---|
141 | $localhost->setup(); |
---|
142 | return $localhost; |
---|
143 | |
---|
144 | // Hat sich wegen Caching als nicht sinnvolle Loesung herausgestellt |
---|
145 | //case strpos($_SERVER['SERVER_NAME'], 'design') !== false: |
---|
146 | // /* Hostnames like foobar.design.technikum29.de */ |
---|
147 | // $localhost = self::new_singleton('t29DesignHost'); |
---|
148 | // $localhost->setup(); |
---|
149 | // return $localhost; |
---|
150 | } |
---|
151 | |
---|
152 | $publichost = self::new_singleton('t29PublicHost'); |
---|
153 | $publichost->setup(); |
---|
154 | return $publichost; |
---|
155 | } |
---|
156 | |
---|
157 | /** |
---|
158 | * "Factory" for creating an instance of $className as a singleton. |
---|
159 | * You should really use detect() for auto-detection instead of |
---|
160 | * forcing a host. |
---|
161 | * Only useful for explicitely calling t29ExternalHost by $external call. |
---|
162 | **/ |
---|
163 | static function create($className) { |
---|
164 | return self::new_singleton($className)->setup(); |
---|
165 | } |
---|
166 | |
---|
167 | /** |
---|
168 | * A constructing method which is always called by the t29Host::detect() factory. |
---|
169 | * It does some general stuff. |
---|
170 | * Of course you can always write your own setup() class - it's just your __constructor. |
---|
171 | * The constructor will of course be called before the setup() method. |
---|
172 | * |
---|
173 | * This method detects two things: |
---|
174 | * 1. if this host does Clean URLs (Suffix rewriting) |
---|
175 | * 2. if this host is *not* installed in its own virtualhost (i.e. on docroot). |
---|
176 | * |
---|
177 | * Note: |
---|
178 | * This is only public as it must be able to be overwritten by subclasses. |
---|
179 | * This should be a constructor! |
---|
180 | * |
---|
181 | * @returns $this for chaining |
---|
182 | **/ |
---|
183 | public function setup() { |
---|
184 | $this->is_rewriting_host = isset($_SERVER[self::env_hidesuffix_name]); |
---|
185 | |
---|
186 | $this->lib = dirname(__FILE__); |
---|
187 | $this->webroot = realpath($this->lib . '/../'); # file path to root of t29 web installation |
---|
188 | |
---|
189 | /* |
---|
190 | calculate the web_prefix. This is kind of a detection. |
---|
191 | |
---|
192 | Examples for an installation in Document root: |
---|
193 | $lib = /var/www/technikum29.de/lib |
---|
194 | $webroot = /var/www/technikum29.de |
---|
195 | $_SERVER["DOCUMENT_ROOT"] = /var/www/technikum29.de |
---|
196 | $this->document_root = /var/www/technikum29.de |
---|
197 | $_SERVER["SCRIPT_FILENAME"] = /var/www/technikum29-www/de/index.php |
---|
198 | $this->script_filename = /de/index.php |
---|
199 | $_SERVER["REQUEST_URI"] = /de |
---|
200 | $_SERVER["SCRIPT_NAME"] = /de/index.php |
---|
201 | $web_prefix = "" |
---|
202 | |
---|
203 | Example for an installation in an arbitrary directory below Document Root: |
---|
204 | $lib = /var/www/arbitrary/lib |
---|
205 | $webroot = /var/www/arbitrary |
---|
206 | $_SERVER['DOCUMENT_ROOT'] = /var/www |
---|
207 | $this->document_root = /var/www/arbitrary |
---|
208 | $_SERVER['SCRIPT_FILENAME'] = /var/www/arbitrary/de/index.php |
---|
209 | $this->script_filename = /arbitrary/de/index.php |
---|
210 | $_SERVER['REQUEST_URI'] = /arbitrary/de |
---|
211 | $_SERVER['SCRIPT_NAME'] = /arbitrary/de/index.php |
---|
212 | $web_prefix = "/arbitrary" |
---|
213 | |
---|
214 | Example for an installation in mod_userdirs homedir out of Docroot: |
---|
215 | $lib = /home/sven/public_html/foo/lib |
---|
216 | $webroot = /home/sven/public_html/foo |
---|
217 | $_SERVER['DOCUMENT_ROOT'] = /var/www (mind that!) |
---|
218 | $this->document_root = /home/sven/public_html/foo |
---|
219 | $_SERVER['SCRIPT_FILENAME'] = /~sven/foo/en/index.php |
---|
220 | $this->script_filename = /~sven/foo/en/index.php |
---|
221 | $_SERVER['REQUEST_URI'] = /~sven/foo/en/ |
---|
222 | $_SERVER['SCRIPT_NAME'] = /~sven/foo/en/index.php |
---|
223 | $web_prefix = "/~sven/foo" |
---|
224 | */ |
---|
225 | |
---|
226 | // this algorithm is good for detecting paths below the document root. |
---|
227 | // it is not suitable for paths out of the document root |
---|
228 | $this->document_root = realpath($_SERVER['DOCUMENT_ROOT']); |
---|
229 | if($this->webroot == $this->document_root) { |
---|
230 | // we are installed in document root |
---|
231 | $this->web_prefix = ""; |
---|
232 | } else { |
---|
233 | // we are installed in some arbitary directory |
---|
234 | $this->web_prefix = substr($this->webroot, strlen($this->document_root)); |
---|
235 | } |
---|
236 | |
---|
237 | // TODO: Somehow autodetect paths out of the document root |
---|
238 | |
---|
239 | $this->has_web_prefix = !empty($this->web_prefix); |
---|
240 | |
---|
241 | //print "Web prefix:<pre>"; |
---|
242 | //var_dump($this); exit; |
---|
243 | |
---|
244 | $this->script_filename = substr(realpath($_SERVER['SCRIPT_FILENAME']), strlen($this->document_root)); # e.g.: "/de/page.php" |
---|
245 | |
---|
246 | // Windows realpath() converts Unix Paths ($_SERVER) to Windows Paths (like \en\index.php). |
---|
247 | // We want to use unix paths ($_SERVER like) internally, so do this dummy conversion back, if neccessary |
---|
248 | $this->script_filename = str_replace('\\', '/', $this->script_filename); |
---|
249 | |
---|
250 | # Bug when DOCUMENT_ROOT ends with trailing slash: make sure $file begins with /: |
---|
251 | $this->slash_filename = $this->script_filename; |
---|
252 | if($this->slash_filename{0} != '/') $this->slash_filename = '/'.$this->slash_filename; |
---|
253 | |
---|
254 | //phpinfo(); exit; |
---|
255 | return $this; // Chaining |
---|
256 | } |
---|
257 | |
---|
258 | function check_url_rewrite() { |
---|
259 | if($this->is_rewriting_host) { |
---|
260 | $path = $_SERVER['REQUEST_URI']; |
---|
261 | $newpath = $this->rewrite_link($path); |
---|
262 | if($path != $newpath) { |
---|
263 | header('HTTP/1.1 301 Moved Permanently'); |
---|
264 | header('Location: '.$newpath); |
---|
265 | return $newpath; |
---|
266 | } |
---|
267 | } |
---|
268 | return null; |
---|
269 | } |
---|
270 | |
---|
271 | public function __toString() { |
---|
272 | return 't29v6/'.$this->hostname; |
---|
273 | } |
---|
274 | |
---|
275 | /** |
---|
276 | * Rewrite Links so they match for this host. |
---|
277 | * This method acts like a pipeline: |
---|
278 | * $new_link = rewrite_link($old_link); |
---|
279 | * It can perform two conversions: |
---|
280 | * |
---|
281 | * 1. Rewriting/Clean URL system: Will strip file suffixes, if appropriate. |
---|
282 | * This will be done whenever this is a rewriting host and this is the |
---|
283 | * main purpose for this function. |
---|
284 | * |
---|
285 | * 2. Prefixing the correct web prefix. This is *only* be done when |
---|
286 | * $also_rewrite_prefix = true. The reaseon is that prefix rewriting is |
---|
287 | * generally done by a global page rewrite after generation of the whole |
---|
288 | * page on a whole-page-level. This is less error prone. |
---|
289 | * Anyway you can use this function if you think you need. blubblubb |
---|
290 | * |
---|
291 | * |
---|
292 | **/ |
---|
293 | function rewrite_link($link_target, $also_rewrite_prefix=false) { |
---|
294 | // rewrite link if neccessary. This function will be called hundreds of times |
---|
295 | // while rendering a page, rewriting all links found. |
---|
296 | |
---|
297 | // pending: prefix setzen. |
---|
298 | if($this->has_web_prefix && $also_rewrite_prefix) { |
---|
299 | $link_target = $this->web_prefix . $link_target; |
---|
300 | } |
---|
301 | |
---|
302 | if($this->is_rewriting_host) { |
---|
303 | $new_target = preg_replace('/\.(?:php|shtml?)([#?].+)?$/i', '\\1', $link_target); |
---|
304 | return $new_target; |
---|
305 | } else { |
---|
306 | // just the identity function |
---|
307 | return $link_target; |
---|
308 | } |
---|
309 | |
---|
310 | } |
---|
311 | |
---|
312 | function get_shorthand_link_returner() { |
---|
313 | $t = $this; |
---|
314 | return function($link_target)use($t) { return $t->rewrite_link($link_target); }; |
---|
315 | } |
---|
316 | |
---|
317 | abstract function fillup_template_conf(&$template_conf); |
---|
318 | } |
---|
319 | |
---|
320 | class t29PublicHost extends t29Host { |
---|
321 | /** |
---|
322 | * This is actually the default public host which should be loaded |
---|
323 | * at www.technikum29.de. |
---|
324 | **/ |
---|
325 | public $hostname = "public"; |
---|
326 | function fillup_template_conf(&$template_conf) {} |
---|
327 | } |
---|
328 | |
---|
329 | class t29DesignHost extends t29Host { |
---|
330 | /** |
---|
331 | * A host like "foobar.design.technikum29.de". This allows CSS to detect |
---|
332 | * the body class "host-foobar-design". |
---|
333 | **/ |
---|
334 | public $hostname = 'design'; |
---|
335 | public $designname = 'undefined'; |
---|
336 | |
---|
337 | function fillup_template_conf(&$template_conf) { |
---|
338 | if(preg_match('/^([^.]+)\.design/i', $_SERVER['SERVER_NAME'], $matches)) |
---|
339 | $this->designname = strtolower($matches[1]).'-design'; |
---|
340 | |
---|
341 | $template_conf['body_classes_append'][] = $this->designname; |
---|
342 | } |
---|
343 | } |
---|
344 | |
---|
345 | /** |
---|
346 | * Host auf heriberts Rechner; dort wird ein weiterer Metatag mit id eingefuehrt, |
---|
347 | * mit dem seine Firefox Editthispage-Extension die Seite bearbeiten kann. |
---|
348 | **/ |
---|
349 | class t29HeribertHost extends t29Host { |
---|
350 | public $hostname = "heribert"; |
---|
351 | |
---|
352 | function fillup_template_conf(&$template_conf) { |
---|
353 | $template_conf['header_prepend'][] = |
---|
354 | '<meta name="t29.localfile" content="'.$_SERVER['SCRIPT_FILENAME'].'" id="localFileSource">'; |
---|
355 | } |
---|
356 | } |
---|
357 | |
---|
358 | /** |
---|
359 | * Ein "external" Host, der Links mit voller URL angeben muss, etwa bei der |
---|
360 | * Einbindung von CSS/JS, aber auch von Links. |
---|
361 | * Genutzt fuer $external-Einbindung von technikum29.php |
---|
362 | **/ |
---|
363 | class t29ExternalHost extends t29Host { |
---|
364 | public $hostname = "external"; |
---|
365 | public $target_host = 'http://www.technikum29.de'; |
---|
366 | |
---|
367 | function rewrite_link($link_target, $also_rewrite_prefix=false) { |
---|
368 | $link_target = parent::rewrite_link($link_target, $also_rewrite_prefix); |
---|
369 | |
---|
370 | if($also_rewrite_prefix) { |
---|
371 | // check if link has host part |
---|
372 | if(!preg_match('#^http:#i', $link_target)) { |
---|
373 | $sep = ($link_target{0} == '/') ? '' : '/'; |
---|
374 | $link_target = $this->target_host . $sep . $link_target; |
---|
375 | } |
---|
376 | } |
---|
377 | |
---|
378 | return $link_target; |
---|
379 | } |
---|
380 | |
---|
381 | function fillup_template_conf(&$template_conf) { |
---|
382 | $template_conf['header_prepend'][] = |
---|
383 | '<meta name="t29.host.from" content="'.$_SERVER['SERVER_NAME'].'">'; |
---|
384 | } |
---|
385 | } |
---|