Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 115
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
mysql_extractor
0.00% covered (danger)
0.00%
0 / 115
0.00% covered (danger)
0.00%
0 / 6
1640
0.00% covered (danger)
0.00%
0 / 1
 write_start
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 write_table
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
 write_data
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 write_data_mysqli
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 new_write_table
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 old_write_table
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
210
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\db\extractor;
15
16use phpbb\db\extractor\exception\extractor_not_initialized_exception;
17
18class mysql_extractor extends base_extractor
19{
20    /**
21    * {@inheritdoc}
22    */
23    public function write_start($table_prefix)
24    {
25        if (!$this->is_initialized)
26        {
27            throw new extractor_not_initialized_exception();
28        }
29
30        $sql_data = "#\n";
31        $sql_data .= "# phpBB Backup Script\n";
32        $sql_data .= "# Dump of tables for $table_prefix\n";
33        $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
34        $sql_data .= "#\n";
35        $this->flush($sql_data);
36    }
37
38    /**
39    * {@inheritdoc}
40    */
41    public function write_table($table_name)
42    {
43        static $new_extract;
44
45        if (!$this->is_initialized)
46        {
47            throw new extractor_not_initialized_exception();
48        }
49
50        if ($new_extract === null)
51        {
52            if ($this->db->get_sql_layer() === 'mysqli' || version_compare($this->db->sql_server_info(true), '3.23.20', '>='))
53            {
54                $new_extract = true;
55            }
56            else
57            {
58                $new_extract = false;
59            }
60        }
61
62        if ($new_extract)
63        {
64            $this->new_write_table($table_name);
65        }
66        else
67        {
68            $this->old_write_table($table_name);
69        }
70    }
71
72    /**
73    * {@inheritdoc}
74    */
75    public function write_data($table_name)
76    {
77        if (!$this->is_initialized)
78        {
79            throw new extractor_not_initialized_exception();
80        }
81
82        $this->write_data_mysqli($table_name);
83    }
84
85    /**
86    * Extracts data from database table (for MySQLi driver)
87    *
88    * @param    string    $table_name    name of the database table
89    * @return void
90    * @throws extractor_not_initialized_exception when calling this function before init_extractor()
91    */
92    protected function write_data_mysqli($table_name)
93    {
94        if (!$this->is_initialized)
95        {
96            throw new extractor_not_initialized_exception();
97        }
98
99        $sql = "SELECT *
100            FROM $table_name";
101        $result = mysqli_query($this->db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT);
102        if ($result != false)
103        {
104            $fields_cnt = mysqli_num_fields($result);
105
106            // Get field information
107            $field = mysqli_fetch_fields($result);
108            $field_set = array();
109
110            for ($j = 0; $j < $fields_cnt; $j++)
111            {
112                $field_set[] = $field[$j]->name;
113            }
114
115            $search            = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
116            $replace        = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
117            $fields            = implode(', ', $field_set);
118            $sql_data        = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
119            $first_set        = true;
120            $query_len        = 0;
121            $max_len        = get_usable_memory();
122
123            while ($row = mysqli_fetch_row($result))
124            {
125                $values    = array();
126                if ($first_set)
127                {
128                    $query = $sql_data . '(';
129                }
130                else
131                {
132                    $query  .= ',(';
133                }
134
135                for ($j = 0; $j < $fields_cnt; $j++)
136                {
137                    if (!isset($row[$j]) || is_null($row[$j]))
138                    {
139                        $values[$j] = 'NULL';
140                    }
141                    else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
142                    {
143                        $values[$j] = $row[$j];
144                    }
145                    else
146                    {
147                        $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
148                    }
149                }
150                $query .= implode(', ', $values) . ')';
151
152                $query_len += strlen($query);
153                if ($query_len > $max_len)
154                {
155                    $this->flush($query . ";\n\n");
156                    $query = '';
157                    $query_len = 0;
158                    $first_set = true;
159                }
160                else
161                {
162                    $first_set = false;
163                }
164            }
165            mysqli_free_result($result);
166
167            // check to make sure we have nothing left to flush
168            if (!$first_set && $query)
169            {
170                $this->flush($query . ";\n\n");
171            }
172        }
173    }
174
175    /**
176    * Extracts database table structure (for MySQLi or MySQL 3.23.20+)
177    *
178    * @param    string    $table_name    name of the database table
179    * @return void
180    * @throws extractor_not_initialized_exception when calling this function before init_extractor()
181    */
182    protected function new_write_table($table_name)
183    {
184        if (!$this->is_initialized)
185        {
186            throw new extractor_not_initialized_exception();
187        }
188
189        $sql = 'SHOW CREATE TABLE ' . $table_name;
190        $result = $this->db->sql_query($sql);
191        $row = $this->db->sql_fetchrow($result);
192
193        $sql_data = '# Table: ' . $table_name . "\n";
194        $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
195        $this->flush($sql_data . $row['Create Table'] . ";\n\n");
196
197        $this->db->sql_freeresult($result);
198    }
199
200    /**
201    * Extracts database table structure (for MySQL versions older than 3.23.20)
202    *
203    * @param    string    $table_name    name of the database table
204    * @return void
205    * @throws extractor_not_initialized_exception when calling this function before init_extractor()
206    */
207    protected function old_write_table($table_name)
208    {
209        if (!$this->is_initialized)
210        {
211            throw new extractor_not_initialized_exception();
212        }
213
214        $sql_data = '# Table: ' . $table_name . "\n";
215        $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
216        $sql_data .= "CREATE TABLE $table_name(\n";
217        $rows = array();
218
219        $sql = "SHOW FIELDS
220            FROM $table_name";
221        $result = $this->db->sql_query($sql);
222
223        while ($row = $this->db->sql_fetchrow($result))
224        {
225            $line = '   ' . $row['Field'] . ' ' . $row['Type'];
226
227            if (!is_null($row['Default']))
228            {
229                $line .= " DEFAULT '{$row['Default']}'";
230            }
231
232            if ($row['Null'] != 'YES')
233            {
234                $line .= ' NOT NULL';
235            }
236
237            if ($row['Extra'] != '')
238            {
239                $line .= ' ' . $row['Extra'];
240            }
241
242            $rows[] = $line;
243        }
244        $this->db->sql_freeresult($result);
245
246        $sql = "SHOW KEYS
247            FROM $table_name";
248
249        $result = $this->db->sql_query($sql);
250
251        $index = array();
252        while ($row = $this->db->sql_fetchrow($result))
253        {
254            $kname = $row['Key_name'];
255
256            if ($kname != 'PRIMARY')
257            {
258                if ($row['Non_unique'] == 0)
259                {
260                    $kname = "UNIQUE|$kname";
261                }
262            }
263
264            if ($row['Sub_part'])
265            {
266                $row['Column_name'] .= '(' . $row['Sub_part'] . ')';
267            }
268            $index[$kname][] = $row['Column_name'];
269        }
270        $this->db->sql_freeresult($result);
271
272        foreach ($index as $key => $columns)
273        {
274            $line = '   ';
275
276            if ($key == 'PRIMARY')
277            {
278                $line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')';
279            }
280            else if (strpos($key, 'UNIQUE') === 0)
281            {
282                $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')';
283            }
284            else if (strpos($key, 'FULLTEXT') === 0)
285            {
286                $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')';
287            }
288            else
289            {
290                $line .= "KEY $key (" . implode(', ', $columns) . ')';
291            }
292
293            $rows[] = $line;
294        }
295
296        $sql_data .= implode(",\n", $rows);
297        $sql_data .= "\n);\n\n";
298
299        $this->flush($sql_data);
300    }
301}