source: trunk/web/punbb/include/dblayer/sqlite.php @ 10

Last change on this file since 10 was 6, checked in by dj3c1t, 13 years ago

mise a jour du trunk

File size: 16.0 KB
RevLine 
[6]1<?php
2
3/**
4 * Copyright (C) 2008-2011 FluxBB
5 * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
6 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
7 */
8
9// Make sure we have built in support for SQLite
10if (!function_exists('sqlite_open'))
11        exit('This PHP environment doesn\'t have SQLite support built in. SQLite support is required if you want to use a SQLite database to run this forum. Consult the PHP documentation for further assistance.');
12
13
14class DBLayer
15{
16        var $prefix;
17        var $link_id;
18        var $query_result;
19        var $in_transaction = 0;
20
21        var $saved_queries = array();
22        var $num_queries = 0;
23
24        var $error_no = false;
25        var $error_msg = 'Unknown';
26
27        var $datatype_transformations = array(
28                '%^SERIAL$%'                                                                                                                    =>      'INTEGER',
29                '%^(TINY|SMALL|MEDIUM|BIG)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'    =>      'INTEGER',
30                '%^(TINY|MEDIUM|LONG)?TEXT$%i'                                                                                  =>      'TEXT'
31        );
32
33
34        function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
35        {
36                // Prepend $db_name with the path to the forum root directory
37                $db_name = PUN_ROOT.$db_name;
38
39                $this->prefix = $db_prefix;
40
41                if (!file_exists($db_name))
42                {
43                        @touch($db_name);
44                        @chmod($db_name, 0666);
45                        if (!file_exists($db_name))
46                                error('Unable to create new database \''.$db_name.'\'. Permission denied', __FILE__, __LINE__);
47                }
48
49                if (!is_readable($db_name))
50                        error('Unable to open database \''.$db_name.'\' for reading. Permission denied', __FILE__, __LINE__);
51
52                if (!is_writable($db_name))
53                        error('Unable to open database \''.$db_name.'\' for writing. Permission denied', __FILE__, __LINE__);
54
55                if ($p_connect)
56                        $this->link_id = @sqlite_popen($db_name, 0666, $sqlite_error);
57                else
58                        $this->link_id = @sqlite_open($db_name, 0666, $sqlite_error);
59
60                if (!$this->link_id)
61                        error('Unable to open database \''.$db_name.'\'. SQLite reported: '.$sqlite_error, __FILE__, __LINE__);
62                else
63                        return $this->link_id;
64        }
65
66
67        function start_transaction()
68        {
69                ++$this->in_transaction;
70
71                return (@sqlite_query($this->link_id, 'BEGIN')) ? true : false;
72        }
73
74
75        function end_transaction()
76        {
77                --$this->in_transaction;
78
79                if (@sqlite_query($this->link_id, 'COMMIT'))
80                        return true;
81                else
82                {
83                        @sqlite_query($this->link_id, 'ROLLBACK');
84                        return false;
85                }
86        }
87
88
89        function query($sql, $unbuffered = false)
90        {
91                if (defined('PUN_SHOW_QUERIES'))
92                        $q_start = get_microtime();
93
94                if ($unbuffered)
95                        $this->query_result = @sqlite_unbuffered_query($this->link_id, $sql);
96                else
97                        $this->query_result = @sqlite_query($this->link_id, $sql);
98
99                if ($this->query_result)
100                {
101                        if (defined('PUN_SHOW_QUERIES'))
102                                $this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
103
104                        ++$this->num_queries;
105
106                        return $this->query_result;
107                }
108                else
109                {
110                        if (defined('PUN_SHOW_QUERIES'))
111                                $this->saved_queries[] = array($sql, 0);
112
113                        $this->error_no = @sqlite_last_error($this->link_id);
114                        $this->error_msg = @sqlite_error_string($this->error_no);
115
116                        if ($this->in_transaction)
117                                @sqlite_query($this->link_id, 'ROLLBACK');
118
119                        --$this->in_transaction;
120
121                        return false;
122                }
123        }
124
125
126        function result($query_id = 0, $row = 0, $col = 0)
127        {
128                if ($query_id)
129                {
130                        if ($row !== 0 && @sqlite_seek($query_id, $row) === false)
131                                return false;
132
133                        $cur_row = @sqlite_current($query_id);
134                        if ($cur_row === false)
135                                return false;
136
137                        return $cur_row[$col];
138                }
139                else
140                        return false;
141        }
142
143
144        function fetch_assoc($query_id = 0)
145        {
146                if ($query_id)
147                {
148                        $cur_row = @sqlite_fetch_array($query_id, SQLITE_ASSOC);
149                        if ($cur_row)
150                        {
151                                // Horrible hack to get rid of table names and table aliases from the array keys
152                                foreach ($cur_row as $key => $value)
153                                {
154                                        $dot_spot = strpos($key, '.');
155                                        if ($dot_spot !== false)
156                                        {
157                                                unset($cur_row[$key]);
158                                                $key = substr($key, $dot_spot+1);
159                                                $cur_row[$key] = $value;
160                                        }
161                                }
162                        }
163
164                        return $cur_row;
165                }
166                else
167                        return false;
168        }
169
170
171        function fetch_row($query_id = 0)
172        {
173                return ($query_id) ? @sqlite_fetch_array($query_id, SQLITE_NUM) : false;
174        }
175
176
177        function num_rows($query_id = 0)
178        {
179                return ($query_id) ? @sqlite_num_rows($query_id) : false;
180        }
181
182
183        function affected_rows()
184        {
185                return ($this->link_id) ? @sqlite_changes($this->link_id) : false;
186        }
187
188
189        function insert_id()
190        {
191                return ($this->link_id) ? @sqlite_last_insert_rowid($this->link_id) : false;
192        }
193
194
195        function get_num_queries()
196        {
197                return $this->num_queries;
198        }
199
200
201        function get_saved_queries()
202        {
203                return $this->saved_queries;
204        }
205
206
207        function free_result($query_id = false)
208        {
209                return true;
210        }
211
212
213        function escape($str)
214        {
215                return is_array($str) ? '' : sqlite_escape_string($str);
216        }
217
218
219        function error()
220        {
221                $result['error_sql'] = @current(@end($this->saved_queries));
222                $result['error_no'] = $this->error_no;
223                $result['error_msg'] = $this->error_msg;
224
225                return $result;
226        }
227
228
229        function close()
230        {
231                if ($this->link_id)
232                {
233                        if ($this->in_transaction)
234                        {
235                                if (defined('PUN_SHOW_QUERIES'))
236                                        $this->saved_queries[] = array('COMMIT', 0);
237
238                                @sqlite_query($this->link_id, 'COMMIT');
239                        }
240
241                        return @sqlite_close($this->link_id);
242                }
243                else
244                        return false;
245        }
246
247
248        function get_names()
249        {
250                return '';
251        }
252
253
254        function set_names($names)
255        {
256                return true;
257        }
258
259
260        function get_version()
261        {
262                return array(
263                        'name'          => 'SQLite',
264                        'version'       => sqlite_libversion()
265                );
266        }
267
268
269        function table_exists($table_name, $no_prefix = false)
270        {
271                $result = $this->query('SELECT 1 FROM sqlite_master WHERE name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND type=\'table\'');
272                return $this->num_rows($result) > 0;
273        }
274
275
276        function field_exists($table_name, $field_name, $no_prefix = false)
277        {
278                $result = $this->query('SELECT sql FROM sqlite_master WHERE name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND type=\'table\'');
279                if (!$this->num_rows($result))
280                        return false;
281
282                return preg_match('%[\r\n]'.preg_quote($field_name, '%').' %', $this->result($result));
283        }
284
285
286        function index_exists($table_name, $index_name, $no_prefix = false)
287        {
288                $result = $this->query('SELECT 1 FROM sqlite_master WHERE tbl_name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_'.$this->escape($index_name).'\' AND type=\'index\'');
289                return $this->num_rows($result) > 0;
290        }
291
292
293        function create_table($table_name, $schema, $no_prefix = false)
294        {
295                if ($this->table_exists($table_name, $no_prefix))
296                        return true;
297
298                $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
299
300                // Go through every schema element and add it to the query
301                foreach ($schema['FIELDS'] as $field_name => $field_data)
302                {
303                        $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
304
305                        $query .= $field_name.' '.$field_data['datatype'];
306
307                        if (!$field_data['allow_null'])
308                                $query .= ' NOT NULL';
309
310                        if (isset($field_data['default']))
311                                $query .= ' DEFAULT '.$field_data['default'];
312
313                        $query .= ",\n";
314                }
315
316                // If we have a primary key, add it
317                if (isset($schema['PRIMARY KEY']))
318                        $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
319
320                // Add unique keys
321                if (isset($schema['UNIQUE KEYS']))
322                {
323                        foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
324                                $query .= 'UNIQUE ('.implode(',', $key_fields).'),'."\n";
325                }
326
327                // We remove the last two characters (a newline and a comma) and add on the ending
328                $query = substr($query, 0, strlen($query) - 2)."\n".')';
329
330                $result = $this->query($query) ? true : false;
331
332                // Add indexes
333                if (isset($schema['INDEXES']))
334                {
335                        foreach ($schema['INDEXES'] as $index_name => $index_fields)
336                                $result &= $this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
337                }
338
339                return $result;
340        }
341
342
343        function drop_table($table_name, $no_prefix = false)
344        {
345                if (!$this->table_exists($table_name, $no_prefix))
346                        return true;
347
348                return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
349        }
350
351
352        function rename_table($old_name, $new_name, $no_prefix = false)
353        {
354                // If there new table exists and the old one doesn't, then we're happy
355                if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
356                        return true;
357
358                $table = $this->get_table_info($old_name, $no_prefix);
359
360                // Create new table
361                $newtable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($old_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($new_name).' (', $table['sql']);
362                $result = $this->query($newtable) ? true : false;
363
364                // Recreate indexes
365                if (!empty($table['indices']))
366                {
367                        foreach ($table['indices'] as $cur_index)
368                                $result &= $this->query($cur_index) ? true : false;
369                }
370
371                // Copy content across
372                $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($new_name).' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($old_name)) ? true : false;
373
374                // Drop old table
375                $result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
376
377                return $result;
378        }
379
380
381        function get_table_info($table_name, $no_prefix = false)
382        {
383                // Grab table info
384                $result = $this->query('SELECT sql FROM sqlite_master WHERE tbl_name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' ORDER BY type DESC') or error('Unable to fetch table information', __FILE__, __LINE__, $this->error());
385                $num_rows = $this->num_rows($result);
386
387                if ($num_rows == 0)
388                        return;
389
390                $table = array();
391                $table['indices'] = array();
392                while ($cur_index = $this->fetch_assoc($result))
393                {
394                        if (empty($cur_index['sql']))
395                                continue;
396
397                        if (!isset($table['sql']))
398                                $table['sql'] = $cur_index['sql'];
399                        else
400                                $table['indices'][] = $cur_index['sql'];
401                }
402
403                // Work out the columns in the table currently
404                $table_lines = explode("\n", $table['sql']);
405                $table['columns'] = array();
406                foreach ($table_lines as $table_line)
407                {
408                        $table_line = trim($table_line, " \t\n\r,"); // trim spaces, tabs, newlines, and commas
409                        if (substr($table_line, 0, 12) == 'CREATE TABLE')
410                                continue;
411                        else if (substr($table_line, 0, 11) == 'PRIMARY KEY')
412                                $table['primary_key'] = $table_line;
413                        else if (substr($table_line, 0, 6) == 'UNIQUE')
414                                $table['unique'] = $table_line;
415                        else if (substr($table_line, 0, strpos($table_line, ' ')) != '')
416                                $table['columns'][substr($table_line, 0, strpos($table_line, ' '))] = trim(substr($table_line, strpos($table_line, ' ')));
417                }
418
419                return $table;
420        }
421
422
423        function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = 0, $no_prefix = false)
424        {
425                if ($this->field_exists($table_name, $field_name, $no_prefix))
426                        return true;
427
428                $table = $this->get_table_info($table_name, $no_prefix);
429
430                // Create temp table
431                $now = time();
432                $tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
433                $result = $this->query($tmptable) ? true : false;
434                $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
435
436                // Create new table sql
437                $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
438                $query = $field_type;
439                if (!$allow_null)
440                        $query .= ' NOT NULL';
441                if ($default_value === null || $default_value === '')
442                        $default_value = '\'\'';
443
444                $query .= ' DEFAULT '.$default_value;
445
446                $old_columns = array_keys($table['columns']);
447                array_insert($table['columns'], $after_field, $query, $field_name);
448
449                $new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
450
451                foreach ($table['columns'] as $cur_column => $column_details)
452                        $new_table .= "\n".$cur_column.' '.$column_details.',';
453
454                if (isset($table['unique']))
455                        $new_table .= "\n".$table['unique'].',';
456
457                if (isset($table['primary_key']))
458                        $new_table .= "\n".$table['primary_key'].',';
459
460                $new_table = trim($new_table, ',')."\n".');';
461
462                // Drop old table
463                $result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
464
465                // Create new table
466                $result &= $this->query($new_table) ? true : false;
467
468                // Recreate indexes
469                if (!empty($table['indices']))
470                {
471                        foreach ($table['indices'] as $cur_index)
472                                $result &= $this->query($cur_index) ? true : false;
473                }
474
475                // Copy content back
476                $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' ('.implode(', ', $old_columns).') SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
477
478                // Drop temp table
479                $result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
480
481                return $result;
482        }
483
484
485        function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = 0, $no_prefix = false)
486        {
487                // Unneeded for SQLite
488                return true;
489        }
490
491
492        function drop_field($table_name, $field_name, $no_prefix = false)
493        {
494                if (!$this->field_exists($table_name, $field_name, $no_prefix))
495                        return true;
496
497                $table = $this->get_table_info($table_name, $no_prefix);
498
499                // Create temp table
500                $now = time();
501                $tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
502                $result = $this->query($tmptable) ? true : false;
503                $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
504
505                // Work out the columns we need to keep and the sql for the new table
506                unset($table['columns'][$field_name]);
507                $new_columns = array_keys($table['columns']);
508
509                $new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
510
511                foreach ($table['columns'] as $cur_column => $column_details)
512                        $new_table .= "\n".$cur_column.' '.$column_details.',';
513
514                if (isset($table['unique']))
515                        $new_table .= "\n".$table['unique'].',';
516
517                if (isset($table['primary_key']))
518                        $new_table .= "\n".$table['primary_key'].',';
519
520                $new_table = trim($new_table, ',')."\n".');';
521
522                // Drop old table
523                $result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
524
525                // Create new table
526                $result &= $this->query($new_table) ? true : false;
527
528                // Recreate indexes
529                if (!empty($table['indices']))
530                {
531                        foreach ($table['indices'] as $cur_index)
532                                if (!preg_match('%\('.preg_quote($field_name, '%').'\)%', $cur_index))
533                                        $result &= $this->query($cur_index) ? true : false;
534                }
535
536                // Copy content back
537                $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' SELECT '.implode(', ', $new_columns).' FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
538
539                // Drop temp table
540                $result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
541
542                return $result;
543        }
544
545
546        function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
547        {
548                if ($this->index_exists($table_name, $index_name, $no_prefix))
549                        return true;
550
551                return $this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') ? true : false;
552        }
553
554
555        function drop_index($table_name, $index_name, $no_prefix = false)
556        {
557                if (!$this->index_exists($table_name, $index_name, $no_prefix))
558                        return true;
559
560                return $this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
561        }
562
563        function truncate_table($table_name, $no_prefix = false)
564        {
565                return $this->query('DELETE FROM '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
566        }
567}
Note: See TracBrowser for help on using the repository browser.