source: t29-www/lib/host.php @ 946

Last change on this file since 946 was 938, checked in by sven, 8 years ago

Hostbasiertes (serverseitiges) Designtestsystem wieder ausgeschaltet (der serverseitige Cache, der nichts von den verschiedenen Hosts auf gleicher Codebasis weiß, hat einen Strich durch die Rechnung gemacht) und stattdessen ein Javascript-basiertes Designtestsystem zusammengefriemelt.

File size: 14.5 KB
Line 
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
15abstract 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
320class 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
329class 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 **/
349class 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 **/
363class 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}
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License