source: github/program/include/rcube_html_page.php @ a98ee35

HEADcourier-fixdev-browser-capabilitiespdorelease-0.7release-0.8
Last change on this file since a98ee35 was a98ee35, checked in by alecpl <alec@…>, 21 months ago
  • Microoptimization: use substr_replace() for injecting a string into string
  • Property mode set to 100644
File size: 9.3 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/include/rcube_html_page.php                                   |
6 |                                                                       |
7 | This file is part of the Roundcube PHP suite                          |
8 | Copyright (C) 2005-2011 The Roundcube Dev Team                       |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | CONTENTS:                                                             |
12 |   Class to build XHTML page output                                    |
13 |                                                                       |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16 +-----------------------------------------------------------------------+
17
18 $Id$
19
20*/
21
22/**
23 * Class for HTML page creation
24 *
25 * @package HTML
26 */
27class rcube_html_page
28{
29    protected $scripts_path = '';
30    protected $script_files = array();
31    protected $css_files = array();
32    protected $scripts = array();
33    protected $charset = RCMAIL_CHARSET;
34
35    protected $script_tag_file = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
36    protected $script_tag  =  "<script type=\"text/javascript\">\n/* <![CDATA[ */\n%s\n/* ]]> */\n</script>\n";
37    protected $link_css_file = "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n";
38    protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
39
40    protected $title = '';
41    protected $header = '';
42    protected $footer = '';
43    protected $body = '';
44    protected $base_path = '';
45
46
47    /** Constructor */
48    public function __construct() {}
49
50    /**
51     * Link an external script file
52     *
53     * @param string File URL
54     * @param string Target position [head|foot]
55     */
56    public function include_script($file, $position='head')
57    {
58        static $sa_files = array();
59       
60        if (!preg_match('|^https?://|i', $file) && $file[0] != '/')
61            $file = $this->scripts_path . $file . (($fs = @filemtime($this->scripts_path . $file)) ? '?s='.$fs : '');
62
63        if (in_array($file, $sa_files)) {
64            return;
65        }
66
67        $sa_files[] = $file;
68
69        if (!is_array($this->script_files[$position])) {
70            $this->script_files[$position] = array();
71        }
72        $this->script_files[$position][] = $file;
73    }
74
75    /**
76     * Add inline javascript code
77     *
78     * @param string JS code snippet
79     * @param string Target position [head|head_top|foot]
80     */
81    public function add_script($script, $position='head')
82    {
83        if (!isset($this->scripts[$position])) {
84            $this->scripts[$position] = "\n".rtrim($script);
85        } else {
86            $this->scripts[$position] .= "\n".rtrim($script);
87        }
88    }
89
90    /**
91     * Link an external css file
92     *
93     * @param string File URL
94     */
95    public function include_css($file)
96    {
97        $this->css_files[] = $file;
98    }
99
100    /**
101     * Add HTML code to the page header
102     *
103     * @param string $str HTML code
104     */
105    public function add_header($str)
106    {
107        $this->header .= "\n".$str;
108    }
109
110    /**
111     * Add HTML code to the page footer
112     * To be added right befor </body>
113     *
114     * @param string $str HTML code
115     */
116    public function add_footer($str)
117    {
118        $this->footer .= "\n".$str;
119    }
120
121    /**
122     * Setter for page title
123     *
124     * @param string $t Page title
125     */
126    public function set_title($t)
127    {
128        $this->title = $t;
129    }
130
131    /**
132     * Setter for output charset.
133     * To be specified in a meta tag and sent as http-header
134     *
135     * @param string $charset Charset
136     */
137    public function set_charset($charset)
138    {
139        $this->charset = $charset;
140    }
141
142    /**
143     * Getter for output charset
144     *
145     * @return string Output charset
146     */
147    public function get_charset()
148    {
149        return $this->charset;
150    }
151
152    /**
153     * Reset all saved properties
154     */
155    public function reset()
156    {
157        $this->script_files = array();
158        $this->scripts      = array();
159        $this->title        = '';
160        $this->header       = '';
161        $this->footer       = '';
162        $this->body         = '';
163    }
164
165    /**
166     * Process template and write to stdOut
167     *
168     * @param string HTML template
169     * @param string Base for absolute paths
170     */
171    public function write($templ='', $base_path='')
172    {
173        $output = empty($templ) ? $this->default_template : trim($templ);
174
175        // set default page title
176        if (empty($this->title)) {
177            $this->title = 'Roundcube Mail';
178        }
179
180        // replace specialchars in content
181        $page_title  = Q($this->title, 'show', FALSE);
182        $page_header = '';
183        $page_footer = '';
184
185        // include meta tag with charset
186        if (!empty($this->charset)) {
187            if (!headers_sent()) {
188                header('Content-Type: text/html; charset=' . $this->charset);
189            }
190            $page_header = '<meta http-equiv="content-type"';
191            $page_header.= ' content="text/html; charset=';
192            $page_header.= $this->charset . '" />'."\n";
193        }
194
195        // definition of the code to be placed in the document header and footer
196        if (is_array($this->script_files['head'])) {
197            foreach ($this->script_files['head'] as $file) {
198                $page_header .= sprintf($this->script_tag_file, $file);
199            }
200        }
201
202        $head_script = $this->scripts['head_top'] . $this->scripts['head'];
203        if (!empty($head_script)) {
204            $page_header .= sprintf($this->script_tag, $head_script);
205        }
206
207        if (!empty($this->header)) {
208            $page_header .= $this->header;
209        }
210
211        // put docready commands into page footer
212        if (!empty($this->scripts['docready'])) {
213            $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
214        }
215
216        if (is_array($this->script_files['foot'])) {
217            foreach ($this->script_files['foot'] as $file) {
218                $page_footer .= sprintf($this->script_tag_file, $file);
219            }
220        }
221
222        if (!empty($this->footer)) {
223            $page_footer .= $this->footer . "\n";
224        }
225
226        if (!empty($this->scripts['foot'])) {
227            $page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
228        }
229
230        // find page header
231        if ($hpos = stripos($output, '</head>')) {
232            $page_header .= "\n";
233        }
234        else {
235            if (!is_numeric($hpos)) {
236                $hpos = stripos($output, '<body');
237            }
238            if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
239                while ($output[$hpos] != '>') {
240                    $hpos++;
241                }
242                $hpos++;
243            }
244            $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
245        }
246
247        // add page hader
248        if ($hpos) {
249            $output = substr_replace($output, $page_header, $hpos, 0);
250        }
251        else {
252            $output = $page_header . $output;
253        }
254
255        // add page footer
256        if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
257            $output = substr_replace($output, $page_footer."\n", $fpos, 0);
258        }
259        else {
260            $output .= "\n".$page_footer;
261        }
262
263        // add css files in head, before scripts, for speed up with parallel downloads
264        if (!empty($this->css_files) && 
265            (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
266        ) {
267            $css = '';
268            foreach ($this->css_files as $file) {
269                $css .= sprintf($this->link_css_file, $file);
270            }
271            $output = substr_replace($output, $css, $pos, 0);
272        }
273
274        $this->base_path = $base_path;
275
276        // correct absolute paths in images and other tags
277        // add timestamp to .js and .css filename
278        $output = preg_replace_callback(
279            '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
280            array($this, 'file_callback'), $output);
281        $output = str_replace('$__skin_path', $base_path, $output);
282
283        // trigger hook with final HTML content to be sent
284        $hook = rcmail::get_instance()->plugins->exec_hook("send_page", array('content' => $output));
285        if (!$hook['abort']) {
286            if ($this->charset != RCMAIL_CHARSET)
287                echo rcube_charset_convert($hook['content'], RCMAIL_CHARSET, $this->charset);
288            else
289                echo $hook['content'];
290        }
291    }
292
293    /**
294     * Callback function for preg_replace_callback in write()
295     *
296     * @return string Parsed string
297     */
298    private function file_callback($matches)
299    {
300            $file = $matches[3];
301
302        // correct absolute paths
303            if ($file[0] == '/')
304                $file = $this->base_path . $file;
305
306        // add file modification timestamp
307            if (preg_match('/\.(js|css)$/', $file))
308            $file .= '?s=' . @filemtime($file);
309
310            return sprintf("%s=%s%s%s", $matches[1], $matches[2], $file, $matches[4]);
311    }
312}
313
Note: See TracBrowser for help on using the repository browser.