Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.88% covered (success)
96.88%
62 / 64
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
data_access
96.88% covered (success)
96.88%
62 / 64
77.78% covered (warning)
77.78%
7 / 9
19
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 get_bbcodes
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_smilies
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 get_styles
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_styles_templates
96.97% covered (success)
96.97%
32 / 33
0.00% covered (danger)
0.00%
0 / 1
6
 resolve_style_filename
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 get_censored_words
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 decode_rowset
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 fetch_decoded_rowset
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\textformatter;
15
16/**
17* Data access layer that fetchs BBCodes, smilies and censored words from the database.
18* To be extended to include insert/update/delete operations.
19*
20* Also used to get templates.
21*/
22class data_access
23{
24    /**
25    * @var string Name of the BBCodes table
26    */
27    protected $bbcodes_table;
28
29    /**
30    * @var \phpbb\db\driver\driver_interface
31    */
32    protected $db;
33
34    /**
35    * @var string Name of the smilies table
36    */
37    protected $smilies_table;
38
39    /**
40    * @var string Name of the styles table
41    */
42    protected $styles_table;
43
44    /**
45    * @var string Path to the styles dir
46    */
47    protected $styles_path;
48
49    /**
50    * @var string Name of the words table
51    */
52    protected $words_table;
53
54    /**
55    * Constructor
56    *
57    * @param \phpbb\db\driver\driver_interface $db Database connection
58    * @param string $bbcodes_table Name of the BBCodes table
59    * @param string $smilies_table Name of the smilies table
60    * @param string $styles_table  Name of the styles table
61    * @param string $words_table   Name of the words table
62    * @param string $styles_path   Path to the styles dir
63    */
64    public function __construct(\phpbb\db\driver\driver_interface $db, $bbcodes_table, $smilies_table, $styles_table, $words_table, $styles_path)
65    {
66        $this->db = $db;
67
68        $this->bbcodes_table = $bbcodes_table;
69        $this->smilies_table = $smilies_table;
70        $this->styles_table  = $styles_table;
71        $this->words_table   = $words_table;
72
73        $this->styles_path = $styles_path;
74    }
75
76    /**
77    * Return the list of custom BBCodes
78    *
79    * @return array
80    */
81    public function get_bbcodes()
82    {
83        $sql = 'SELECT bbcode_match, bbcode_tpl FROM ' . $this->bbcodes_table;
84
85        return $this->fetch_decoded_rowset($sql, ['bbcode_match']);
86    }
87
88    /**
89    * Return the list of smilies
90    *
91    * @return array
92    */
93    public function get_smilies()
94    {
95        // NOTE: smilies that are displayed on the posting page are processed first because they're
96        //       typically the most used smilies and it ends up producing a slightly more efficient
97        //       renderer
98        $sql = 'SELECT code, emotion, smiley_url, smiley_width, smiley_height
99            FROM ' . $this->smilies_table . '
100            ORDER BY display_on_posting DESC';
101
102        return $this->fetch_decoded_rowset($sql, ['code', 'emotion', 'smiley_url']);
103    }
104
105    /**
106    * Return the list of installed styles
107    *
108    * @return array
109    */
110    protected function get_styles()
111    {
112        $sql = 'SELECT style_id, style_path, style_parent_id, bbcode_bitfield FROM ' . $this->styles_table;
113
114        return $this->fetch_decoded_rowset($sql);
115    }
116
117    /**
118    * Return the bbcode.html template for every installed style
119    *
120    * @return array 2D array. style_id as keys, each element is an array with a "template" element that contains the style's bbcode.html and a "bbcodes" element that contains the name of each BBCode that is to be stylised
121    */
122    public function get_styles_templates()
123    {
124        $templates = array();
125
126        $bbcode_ids = array(
127            'quote' => 0,
128            'b'     => 1,
129            'i'     => 2,
130            'url'   => 3,
131            'img'   => 4,
132            'size'  => 5,
133            'color' => 6,
134            'u'     => 7,
135            'code'  => 8,
136            'list'  => 9,
137            '*'     => 9,
138            'email' => 10,
139            'attachment' => 12,
140        );
141
142        $styles = array();
143        foreach ($this->get_styles() as $row)
144        {
145            $styles[$row['style_id']] = $row;
146        }
147
148        foreach ($styles as $style_id => $style)
149        {
150            $bbcodes = array();
151
152            // Collect the name of the BBCodes whose bit is set in the style's bbcode_bitfield
153            $template_bitfield = new \bitfield($style['bbcode_bitfield']);
154            foreach ($bbcode_ids as $bbcode_name => $bit)
155            {
156                if ($template_bitfield->get($bit))
157                {
158                    $bbcodes[] = $bbcode_name;
159                }
160            }
161
162            $filename = $this->resolve_style_filename($styles, $style);
163            if ($filename === false)
164            {
165                // Ignore this style, it will use the default templates
166                continue;
167            }
168
169            $templates[$style_id] = array(
170                'bbcodes'  => $bbcodes,
171                'template' => file_get_contents($filename),
172            );
173        }
174
175        return $templates;
176    }
177
178    /**
179    * Resolve inheritance for given style and return the path to their bbcode.html file
180    *
181    * @param  array       $styles Associative array of [style_id => style] containing all styles
182    * @param  array       $style  Style for which we resolve
183    * @return string|bool         Path to this style's bbcode.html, or FALSE
184    */
185    protected function resolve_style_filename(array $styles, array $style)
186    {
187        // Look for a bbcode.html in this style's dir
188        $filename = $this->styles_path . $style['style_path'] . '/template/bbcode.html';
189        if (file_exists($filename))
190        {
191            return $filename;
192        }
193
194        // Resolve using this style's parent
195        $parent_id = $style['style_parent_id'];
196        if ($parent_id && !empty($styles[$parent_id]))
197        {
198            return $this->resolve_style_filename($styles, $styles[$parent_id]);
199        }
200
201        return false;
202    }
203
204    /**
205    * Return the list of censored words
206    *
207    * @return array
208    */
209    public function get_censored_words()
210    {
211        $sql = 'SELECT word, replacement FROM ' . $this->words_table;
212
213        return $this->fetch_decoded_rowset($sql, ['word', 'replacement']);
214    }
215
216    /**
217    * Decode HTML special chars in given rowset
218    *
219    * @param  array $rows    Original rowset
220    * @param  array $columns List of columns to decode
221    * @return array          Decoded rowset
222    */
223    protected function decode_rowset(array $rows, array $columns)
224    {
225        foreach ($rows as &$row)
226        {
227            foreach ($columns as $column)
228            {
229                $row[$column] = html_entity_decode($row[$column], ENT_COMPAT);
230            }
231        }
232
233        return $rows;
234    }
235
236    /**
237    * Fetch all rows for given query and decode plain text columns
238    *
239    * @param  string $sql     SELECT query
240    * @param  array  $columns List of columns to decode
241    * @return array
242    */
243    protected function fetch_decoded_rowset($sql, array $columns = [])
244    {
245        $result = $this->db->sql_query($sql);
246        $rows = $this->db->sql_fetchrowset($result);
247        $this->db->sql_freeresult($result);
248
249        return $this->decode_rowset($rows, $columns);
250    }
251}