phpBB
Statistics
| Revision:

root / branches / phpBB-3_0_0 / phpBB / includes / template.php

History | View | Annotate | Download (18.4 kB)

1
<?php
2
/**
3
*
4
* @package phpBB3
5
* @version $Id: template.php 11124 2011-04-26 20:00:09Z git-gate $
6
* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
7
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8
*
9
*/
10
11
/**
12
* @ignore
13
*/
14
if (!defined('IN_PHPBB'))
15
{
16
        exit;
17
}
18
19
/**
20
* Base Template class.
21
* @package phpBB3
22
*/
23
class template
24
{
25
        /** variable that holds all the data we'll be substituting into
26
        * the compiled templates. Takes form:
27
        * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value
28
        * if it's a root-level variable, it'll be like this:
29
        * --> $this->_tpldata[.][0][varname] == value
30
        */
31
        var $_tpldata = array('.' => array(0 => array()));
32
        var $_rootref;
33
34
        // Root dir and hash of filenames for each template handle.
35
        var $root = '';
36
        var $cachepath = '';
37
        var $files = array();
38
        var $filename = array();
39
        var $files_inherit = array();
40
        var $files_template = array();
41
        var $inherit_root = '';
42
        var $orig_tpl_storedb;
43
        var $orig_tpl_inherits_id;
44
45
        // this will hash handle names to the compiled/uncompiled code for that handle.
46
        var $compiled_code = array();
47
48
        /**
49
        * Set template location
50
        * @access public
51
        */
52
        function set_template()
53
        {
54
                global $phpbb_root_path, $user;
55
56
                if (file_exists($phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'))
57
                {
58
                        $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template';
59
                        $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_';
60
61
                        if ($this->orig_tpl_storedb === null)
62
                        {
63
                                $this->orig_tpl_storedb = $user->theme['template_storedb'];
64
                        }
65
66
                        if ($this->orig_tpl_inherits_id === null)
67
                        {
68
                                $this->orig_tpl_inherits_id = $user->theme['template_inherits_id'];
69
                        }
70
71
                        $user->theme['template_storedb'] = $this->orig_tpl_storedb;
72
                        $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id;
73
74
                        if ($user->theme['template_inherits_id'])
75
                        {
76
                                $this->inherit_root = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template';
77
                        }
78
                }
79
                else
80
                {
81
                        trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR);
82
                }
83
84
                $this->_rootref = &$this->_tpldata['.'][0];
85
86
                return true;
87
        }
88
89
        /**
90
        * Set custom template location (able to use directory outside of phpBB)
91
        * @access public
92
        */
93
        function set_custom_template($template_path, $template_name, $fallback_template_path = false)
94
        {
95
                global $phpbb_root_path, $user;
96
97
                // Make sure $template_path has no ending slash
98
                if (substr($template_path, -1) == '/')
99
                {
100
                        $template_path = substr($template_path, 0, -1);
101
                }
102
103
                $this->root = $template_path;
104
                $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_';
105
106
                if ($fallback_template_path !== false)
107
                {
108
                        if (substr($fallback_template_path, -1) == '/')
109
                        {
110
                                $fallback_template_path = substr($fallback_template_path, 0, -1);
111
                        }
112
113
                        $this->inherit_root = $fallback_template_path;
114
                        $this->orig_tpl_inherits_id = true;
115
                }
116
                else
117
                {
118
                        $this->orig_tpl_inherits_id = false;
119
                }
120
121
                // the database does not store the path or name of a custom template
122
                // so there is no way we can properly store custom templates there
123
                $this->orig_tpl_storedb = false;
124
125
                $this->_rootref = &$this->_tpldata['.'][0];
126
127
                return true;
128
        }
129
130
        /**
131
        * Sets the template filenames for handles. $filename_array
132
        * should be a hash of handle => filename pairs.
133
        * @access public
134
        */
135
        function set_filenames($filename_array)
136
        {
137
                if (!is_array($filename_array))
138
                {
139
                        return false;
140
                }
141
                foreach ($filename_array as $handle => $filename)
142
                {
143
                        if (empty($filename))
144
                        {
145
                                trigger_error("template->set_filenames: Empty filename specified for $handle", E_USER_ERROR);
146
                        }
147
148
                        $this->filename[$handle] = $filename;
149
                        $this->files[$handle] = $this->root . '/' . $filename;
150
151
                        if ($this->inherit_root)
152
                        {
153
                                $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename;
154
                        }
155
                }
156
157
                return true;
158
        }
159
160
        /**
161
        * Destroy template data set
162
        * @access public
163
        */
164
        function destroy()
165
        {
166
                $this->_tpldata = array('.' => array(0 => array()));
167
                $this->_rootref = &$this->_tpldata['.'][0];
168
        }
169
170
        /**
171
        * Reset/empty complete block
172
        * @access public
173
        */
174
        function destroy_block_vars($blockname)
175
        {
176
                if (strpos($blockname, '.') !== false)
177
                {
178
                        // Nested block.
179
                        $blocks = explode('.', $blockname);
180
                        $blockcount = sizeof($blocks) - 1;
181
182
                        $str = &$this->_tpldata;
183
                        for ($i = 0; $i < $blockcount; $i++)
184
                        {
185
                                $str = &$str[$blocks[$i]];
186
                                $str = &$str[sizeof($str) - 1];
187
                        }
188
189
                        unset($str[$blocks[$blockcount]]);
190
                }
191
                else
192
                {
193
                        // Top-level block.
194
                        unset($this->_tpldata[$blockname]);
195
                }
196
197
                return true;
198
        }
199
200
        /**
201
        * Display handle
202
        * @access public
203
        */
204
        function display($handle, $include_once = true)
205
        {
206
                global $user, $phpbb_hook;
207
208
                if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this))
209
                {
210
                        if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
211
                        {
212
                                return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
213
                        }
214
                }
215
216
                if (defined('IN_ERROR_HANDLER'))
217
                {
218
                        if ((E_NOTICE & error_reporting()) == E_NOTICE)
219
                        {
220
                                error_reporting(error_reporting() ^ E_NOTICE);
221
                        }
222
                }
223
224
                if ($filename = $this->_tpl_load($handle))
225
                {
226
                        ($include_once) ? include_once($filename) : include($filename);
227
                }
228
                else
229
                {
230
                        eval(' ?>' . $this->compiled_code[$handle] . '<?php ');
231
                }
232
233
                return true;
234
        }
235
236
        /**
237
        * Display the handle and assign the output to a template variable or return the compiled result.
238
        * @access public
239
        */
240
        function assign_display($handle, $template_var = '', $return_content = true, $include_once = false)
241
        {
242
                ob_start();
243
                $this->display($handle, $include_once);
244
                $contents = ob_get_clean();
245
246
                if ($return_content)
247
                {
248
                        return $contents;
249
                }
250
251
                $this->assign_var($template_var, $contents);
252
253
                return true;
254
        }
255
256
        /**
257
        * Load a compiled template if possible, if not, recompile it
258
        * @access private
259
        */
260
        function _tpl_load(&$handle)
261
        {
262
                global $user, $phpEx, $config;
263
264
                if (!isset($this->filename[$handle]))
265
                {
266
                        trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR);
267
                }
268
269
                // reload these settings to have the values they had when this object was initialised
270
                // using set_template or set_custom_template, they might otherwise have been overwritten
271
                // by other template class instances in between.
272
                $user->theme['template_storedb'] = $this->orig_tpl_storedb;
273
                $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id;
274
275
                $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx;
276
                $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0;
277
278
                $recompile = false;
279
                if (!file_exists($filename) || @filesize($filename) === 0 || defined('DEBUG_EXTRA'))
280
                {
281
                        $recompile = true;
282
                }
283
                else if ($config['load_tplcompile'])
284
                {
285
                        // No way around it: we need to check inheritance here
286
                        if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle]))
287
                        {
288
                                $this->files[$handle] = $this->files_inherit[$handle];
289
                                $this->files_template[$handle] = $user->theme['template_inherits_id'];
290
                        }
291
                        $recompile = (@filemtime($filename) < filemtime($this->files[$handle])) ? true : false;
292
                }
293
294
                // Recompile page if the original template is newer, otherwise load the compiled version
295
                if (!$recompile)
296
                {
297
                        return $filename;
298
                }
299
300
                global $db, $phpbb_root_path;
301
302
                if (!class_exists('template_compile'))
303
                {
304
                        include($phpbb_root_path . 'includes/functions_template.' . $phpEx);
305
                }
306
307
                // Inheritance - we point to another template file for this one. Equality is also used for store_db
308
                if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle]))
309
                {
310
                        $this->files[$handle] = $this->files_inherit[$handle];
311
                        $this->files_template[$handle] = $user->theme['template_inherits_id'];
312
                }
313
314
                $compile = new template_compile($this);
315
316
                // If we don't have a file assigned to this handle, die.
317
                if (!isset($this->files[$handle]))
318
                {
319
                        trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR);
320
                }
321
322
                // Just compile if no user object is present (happens within the installer)
323
                if (!$user)
324
                {
325
                        $compile->_tpl_load_file($handle);
326
                        return false;
327
                }
328
329
                if (isset($user->theme['template_storedb']) && $user->theme['template_storedb'])
330
                {
331
                        $rows = array();
332
                        $ids = array();
333
                        // Inheritance
334
                        if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'])
335
                        {
336
                                $ids[] = $user->theme['template_inherits_id'];
337
                        }
338
                        $ids[] = $user->theme['template_id'];
339
340
                        foreach ($ids as $id)
341
                        {
342
                                $sql = 'SELECT *
343
                                FROM ' . STYLES_TEMPLATE_DATA_TABLE . '
344
                                WHERE template_id = ' . $id . "
345
                                        AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "'
346
                                                OR template_included " . $db->sql_like_expression($db->any_char . $this->filename[$handle] . ':' . $db->any_char) . ')';
347
348
                                $result = $db->sql_query($sql);
349
                                while ($row = $db->sql_fetchrow($result))
350
                                {
351
                                        $rows[$row['template_filename']] = $row;
352
                                }
353
                                $db->sql_freeresult($result);
354
                        }
355
356
                        if (sizeof($rows))
357
                        {
358
                                foreach ($rows as $row)
359
                                {
360
                                        $file = $this->root . '/' . $row['template_filename'];
361
                                        $force_reload = false;
362
                                        if ($row['template_id'] != $user->theme['template_id'])
363
                                        {
364
                                                // make sure that we are not overlooking a file not in the db yet
365
                                                if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file))
366
                                                {
367
                                                        $file = $this->inherit_root . '/' . $row['template_filename'];
368
                                                        $this->files[$row['template_filename']] = $file;
369
                                                        $this->files_inherit[$row['template_filename']] = $file;
370
                                                        $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
371
                                                }
372
                                                else if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'])
373
                                                {
374
                                                        // Ok, we have a situation. There is a file in the subtemplate, but nothing in the DB. We have to fix that.
375
                                                        $force_reload = true;
376
                                                        $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
377
                                                }
378
                                        }
379
                                        else
380
                                        {
381
                                                $this->files_template[$row['template_filename']] = $user->theme['template_id'];
382
                                        }
383
384
                                        if ($force_reload || $row['template_mtime'] < filemtime($file))
385
                                        {
386
                                                if ($row['template_filename'] == $this->filename[$handle])
387
                                                {
388
                                                        $compile->_tpl_load_file($handle, true);
389
                                                }
390
                                                else
391
                                                {
392
                                                        $this->files[$row['template_filename']] = $file;
393
                                                        $this->filename[$row['template_filename']] = $row['template_filename'];
394
                                                        $compile->_tpl_load_file($row['template_filename'], true);
395
                                                        unset($this->compiled_code[$row['template_filename']]);
396
                                                        unset($this->files[$row['template_filename']]);
397
                                                        unset($this->filename[$row['template_filename']]);
398
                                                }
399
                                        }
400
401
                                        if ($row['template_filename'] == $this->filename[$handle])
402
                                        {
403
                                                $this->compiled_code[$handle] = $compile->compile(trim($row['template_data']));
404
                                                $compile->compile_write($handle, $this->compiled_code[$handle]);
405
                                        }
406
                                        else
407
                                        {
408
                                                // Only bother compiling if it doesn't already exist
409
                                                if (!file_exists($this->cachepath . str_replace('/', '.', $row['template_filename']) . '.' . $phpEx))
410
                                                {
411
                                                        $this->filename[$row['template_filename']] = $row['template_filename'];
412
                                                        $compile->compile_write($row['template_filename'], $compile->compile(trim($row['template_data'])));
413
                                                        unset($this->filename[$row['template_filename']]);
414
                                                }
415
                                        }
416
                                }
417
                        }
418
                        else
419
                        {
420
                                $file = $this->root . '/' . $row['template_filename'];
421
422
                                if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file))
423
                                {
424
                                        $file = $this->inherit_root . '/' . $row['template_filename'];
425
                                        $this->files[$row['template_filename']] = $file;
426
                                        $this->files_inherit[$row['template_filename']] = $file;
427
                                        $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id'];
428
                                }
429
                                // Try to load from filesystem and instruct to insert into the styles table...
430
                                $compile->_tpl_load_file($handle, true);
431
                                return false;
432
                        }
433
434
                        return false;
435
                }
436
437
                $compile->_tpl_load_file($handle);
438
                return false;
439
        }
440
441
        /**
442
        * Assign key variable pairs from an array
443
        * @access public
444
        */
445
        function assign_vars($vararray)
446
        {
447
                foreach ($vararray as $key => $val)
448
                {
449
                        $this->_rootref[$key] = $val;
450
                }
451
452
                return true;
453
        }
454
455
        /**
456
        * Assign a single variable to a single key
457
        * @access public
458
        */
459
        function assign_var($varname, $varval)
460
        {
461
                $this->_rootref[$varname] = $varval;
462
463
                return true;
464
        }
465
466
        /**
467
        * Assign key variable pairs from an array to a specified block
468
        * @access public
469
        */
470
        function assign_block_vars($blockname, $vararray)
471
        {
472
                if (strpos($blockname, '.') !== false)
473
                {
474
                        // Nested block.
475
                        $blocks = explode('.', $blockname);
476
                        $blockcount = sizeof($blocks) - 1;
477
478
                        $str = &$this->_tpldata;
479
                        for ($i = 0; $i < $blockcount; $i++)
480
                        {
481
                                $str = &$str[$blocks[$i]];
482
                                $str = &$str[sizeof($str) - 1];
483
                        }
484
485
                        $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0;
486
                        $vararray['S_ROW_COUNT'] = $s_row_count;
487
488
                        // Assign S_FIRST_ROW
489
                        if (!$s_row_count)
490
                        {
491
                                $vararray['S_FIRST_ROW'] = true;
492
                        }
493
494
                        // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
495
                        // This is much more clever than going through the complete template data on display (phew)
496
                        $vararray['S_LAST_ROW'] = true;
497
                        if ($s_row_count > 0)
498
                        {
499
                                unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']);
500
                        }
501
502
                        // Now we add the block that we're actually assigning to.
503
                        // We're adding a new iteration to this block with the given
504
                        // variable assignments.
505
                        $str[$blocks[$blockcount]][] = $vararray;
506
                }
507
                else
508
                {
509
                        // Top-level block.
510
                        $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0;
511
                        $vararray['S_ROW_COUNT'] = $s_row_count;
512
513
                        // Assign S_FIRST_ROW
514
                        if (!$s_row_count)
515
                        {
516
                                $vararray['S_FIRST_ROW'] = true;
517
                        }
518
519
                        // We always assign S_LAST_ROW and remove the entry before
520
                        $vararray['S_LAST_ROW'] = true;
521
                        if ($s_row_count > 0)
522
                        {
523
                                unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']);
524
                        }
525
526
                        // Add a new iteration to this block with the variable assignments we were given.
527
                        $this->_tpldata[$blockname][] = $vararray;
528
                }
529
530
                return true;
531
        }
532
533
        /**
534
        * Change already assigned key variable pair (one-dimensional - single loop entry)
535
        *
536
        * An example of how to use this function:
537
        * {@example alter_block_array.php}
538
        *
539
        * @param        string        $blockname        the blockname, for example 'loop'
540
        * @param        array        $vararray        the var array to insert/add or merge
541
        * @param        mixed        $key                Key to search for
542
        *
543
        * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
544
        *
545
        * int: Position [the position to change or insert at directly given]
546
        *
547
        * If key is false the position is set to 0
548
        * If key is true the position is set to the last entry
549
        *
550
        * @param        string        $mode                Mode to execute (valid modes are 'insert' and 'change')
551
        *
552
        *        If insert, the vararray is inserted at the given position (position counting from zero).
553
        *        If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value).
554
        *
555
        * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
556
        * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
557
        *
558
        * @return bool false on error, true on success
559
        * @access public
560
        */
561
        function alter_block_array($blockname, $vararray, $key = false, $mode = 'insert')
562
        {
563
                if (strpos($blockname, '.') !== false)
564
                {
565
                        // Nested blocks are not supported
566
                        return false;
567
                }
568
569
                // Change key to zero (change first position) if false and to last position if true
570
                if ($key === false || $key === true)
571
                {
572
                        $key = ($key === false) ? 0 : sizeof($this->_tpldata[$blockname]);
573
                }
574
575
                // Get correct position if array given
576
                if (is_array($key))
577
                {
578
                        // Search array to get correct position
579
                        list($search_key, $search_value) = @each($key);
580
581
                        $key = NULL;
582
                        foreach ($this->_tpldata[$blockname] as $i => $val_ary)
583
                        {
584
                                if ($val_ary[$search_key] === $search_value)
585
                                {
586
                                        $key = $i;
587
                                        break;
588
                                }
589
                        }
590
591
                        // key/value pair not found
592
                        if ($key === NULL)
593
                        {
594
                                return false;
595
                        }
596
                }
597
598
                // Insert Block
599
                if ($mode == 'insert')
600
                {
601
                        // Make sure we are not exceeding the last iteration
602
                        if ($key >= sizeof($this->_tpldata[$blockname]))
603
                        {
604
                                $key = sizeof($this->_tpldata[$blockname]);
605
                                unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']);
606
                                $vararray['S_LAST_ROW'] = true;
607
                        }
608
                        else if ($key === 0)
609
                        {
610
                                unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']);
611
                                $vararray['S_FIRST_ROW'] = true;
612
                        }
613
614
                        // Re-position template blocks
615
                        for ($i = sizeof($this->_tpldata[$blockname]); $i > $key; $i--)
616
                        {
617
                                $this->_tpldata[$blockname][$i] = $this->_tpldata[$blockname][$i-1];
618
                                $this->_tpldata[$blockname][$i]['S_ROW_COUNT'] = $i;
619
                        }
620
621
                        // Insert vararray at given position
622
                        $vararray['S_ROW_COUNT'] = $key;
623
                        $this->_tpldata[$blockname][$key] = $vararray;
624
625
                        return true;
626
                }
627
628
                // Which block to change?
629
                if ($mode == 'change')
630
                {
631
                        if ($key == sizeof($this->_tpldata[$blockname]))
632
                        {
633
                                $key--;
634
                        }
635
636
                        $this->_tpldata[$blockname][$key] = array_merge($this->_tpldata[$blockname][$key], $vararray);
637
                        return true;
638
                }
639
640
                return false;
641
        }
642
643
        /**
644
        * Include a separate template
645
        * @access private
646
        */
647
        function _tpl_include($filename, $include = true)
648
        {
649
                $handle = $filename;
650
                $this->filename[$handle] = $filename;
651
                $this->files[$handle] = $this->root . '/' . $filename;
652
                if ($this->inherit_root)
653
                {
654
                        $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename;
655
                }
656
657
                $filename = $this->_tpl_load($handle);
658
659
                if ($include)
660
                {
661
                        global $user;
662
663
                        if ($filename)
664
                        {
665
                                include($filename);
666
                                return;
667
                        }
668
                        eval(' ?>' . $this->compiled_code[$handle] . '<?php ');
669
                }
670
        }
671
672
        /**
673
        * Include a php-file
674
        * @access private
675
        */
676
        function _php_include($filename)
677
        {
678
                global $phpbb_root_path;
679
680
                $file = $phpbb_root_path . $filename;
681
682
                if (!file_exists($file))
683
                {
684
                        // trigger_error cannot be used here, as the output already started
685
                        echo 'template->_php_include(): File ' . htmlspecialchars($file) . ' does not exist or is empty';
686
                        return;
687
                }
688
                include($file);
689
        }
690
}
691
692
?>