Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
sqlite3.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\db\driver;
015
016 /**
017 * SQLite3 Database Abstraction Layer
018 * Minimum Requirement: 3.6.15+
019 */
020 class sqlite3 extends \phpbb\db\driver\driver
021 {
022 /**
023 * @var string Stores errors during connection setup in case the driver is not available
024 */
025 protected $connect_error = '';
026
027 /**
028 * @var \SQLite3 The SQLite3 database object to operate against
029 */
030 protected $dbo = null;
031
032 /**
033 * {@inheritDoc}
034 */
035 public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
036 {
037 $this->persistency = false;
038 $this->user = $sqluser;
039 $this->server = $sqlserver . (($port) ? ':' . $port : '');
040 $this->dbname = $database;
041
042 if (!class_exists('SQLite3', false))
043 {
044 $this->connect_error = 'SQLite3 not found, is the extension installed?';
045 return $this->sql_error('');
046 }
047
048 try
049 {
050 $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
051 $this->dbo->busyTimeout(60000);
052 $this->db_connect_id = true;
053 }
054 catch (\Exception $e)
055 {
056 $this->connect_error = $e->getMessage();
057 return array('message' => $this->connect_error);
058 }
059
060 return true;
061 }
062
063 /**
064 * {@inheritDoc}
065 */
066 public function sql_server_info($raw = false, $use_cache = true)
067 {
068 global $cache;
069
070 if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false)
071 {
072 $version = \SQLite3::version();
073
074 $this->sql_server_version = $version['versionString'];
075
076 if (!empty($cache) && $use_cache)
077 {
078 $cache->put('sqlite_version', $this->sql_server_version);
079 }
080 }
081
082 return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version;
083 }
084
085 /**
086 * SQL Transaction
087 *
088 * @param string $status Should be one of the following strings:
089 * begin, commit, rollback
090 * @return bool Success/failure of the transaction query
091 */
092 protected function _sql_transaction($status = 'begin')
093 {
094 switch ($status)
095 {
096 case 'begin':
097 return $this->dbo->exec('BEGIN IMMEDIATE');
098 break;
099
100 case 'commit':
101 return $this->dbo->exec('COMMIT');
102 break;
103
104 case 'rollback':
105 return @$this->dbo->exec('ROLLBACK');
106 break;
107 }
108
109 return true;
110 }
111
112 /**
113 * {@inheritDoc}
114 */
115 public function sql_query($query = '', $cache_ttl = 0)
116 {
117 if ($query != '')
118 {
119 global $cache;
120
121 if ($this->debug_sql_explain)
122 {
123 $this->sql_report('start', $query);
124 }
125 else if ($this->debug_load_time)
126 {
127 $this->curtime = microtime(true);
128 }
129
130 $this->last_query_text = $query;
131 $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
132 $this->sql_add_num_queries($this->query_result);
133
134 if ($this->query_result === false)
135 {
136 if ($this->transaction === true && strpos($query, 'INSERT') === 0)
137 {
138 $query = preg_replace('/^INSERT INTO/', 'INSERT OR ROLLBACK INTO', $query);
139 }
140
141 try
142 {
143 $this->query_result = @$this->dbo->query($query);
144 }
145 catch (\Error $e)
146 {
147 // Do nothing as SQL driver will report the error
148 }
149
150 if ($this->query_result === false)
151 {
152 // Try to recover a lost database connection
153 if ($this->dbo && !@$this->dbo->lastErrorMsg())
154 {
155 if ($this->sql_connect($this->server, $this->user, '', $this->dbname))
156 {
157 $this->query_result = @$this->dbo->query($query);
158 }
159 }
160
161 if ($this->query_result === false)
162 {
163 $this->sql_error($query);
164 }
165 }
166
167 if ($this->debug_sql_explain)
168 {
169 $this->sql_report('stop', $query);
170 }
171 else if ($this->debug_load_time)
172 {
173 $this->sql_time += microtime(true) - $this->curtime;
174 }
175
176 if (!$this->query_result)
177 {
178 return false;
179 }
180
181 if ($cache && $cache_ttl)
182 {
183 $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
184 }
185 }
186 else if ($this->debug_sql_explain)
187 {
188 $this->sql_report('fromcache', $query);
189 }
190 }
191 else
192 {
193 return false;
194 }
195
196 return $this->query_result;
197 }
198
199 /**
200 * Build LIMIT query
201 *
202 * @param string $query The SQL query to execute
203 * @param int $total The number of rows to select
204 * @param int $offset
205 * @param int $cache_ttl Either 0 to avoid caching or
206 * the time in seconds which the result shall be kept in cache
207 * @return mixed Buffered, seekable result handle, false on error
208 */
209 protected function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
210 {
211 $this->query_result = false;
212
213 // if $total is set to 0 we do not want to limit the number of rows
214 if ($total == 0)
215 {
216 $total = -1;
217 }
218
219 $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
220
221 return $this->sql_query($query, $cache_ttl);
222 }
223
224 /**
225 * {@inheritDoc}
226 */
227 public function sql_affectedrows()
228 {
229 return ($this->db_connect_id) ? $this->dbo->changes() : false;
230 }
231
232 /**
233 * {@inheritDoc}
234 */
235 public function sql_fetchrow($query_id = false)
236 {
237 global $cache;
238
239 if ($query_id === false)
240 {
241 /** @var \SQLite3Result $query_id */
242 $query_id = $this->query_result;
243 }
244
245 $safe_query_id = $this->clean_query_id($query_id);
246 if ($cache && $cache->sql_exists($safe_query_id))
247 {
248 return $cache->sql_fetchrow($safe_query_id);
249 }
250
251 return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false;
252 }
253
254 /**
255 * {@inheritdoc}
256 */
257 public function sql_last_inserted_id()
258 {
259 return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false;
260 }
261
262 /**
263 * {@inheritDoc}
264 */
265 public function sql_freeresult($query_id = false)
266 {
267 global $cache;
268
269 if ($query_id === false)
270 {
271 $query_id = $this->query_result;
272 }
273
274 $safe_query_id = $this->clean_query_id($query_id);
275 if ($cache && $cache->sql_exists($safe_query_id))
276 {
277 return $cache->sql_freeresult($safe_query_id);
278 }
279
280 if ($query_id)
281 {
282 return @$query_id->finalize();
283 }
284 }
285
286 /**
287 * {@inheritDoc}
288 */
289 public function sql_escape($msg)
290 {
291 return \SQLite3::escapeString($msg);
292 }
293
294 /**
295 * {@inheritDoc}
296 *
297 * For SQLite an underscore is an unknown character.
298 */
299 public function sql_like_expression($expression)
300 {
301 // Unlike LIKE, GLOB is unfortunately case sensitive.
302 // We only catch * and ? here, not the character map possible on file globbing.
303 $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
304
305 $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
306 $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
307
308 return 'GLOB \'' . $this->sql_escape($expression) . '\'';
309 }
310
311 /**
312 * {@inheritDoc}
313 *
314 * For SQLite an underscore is an unknown character.
315 */
316 public function sql_not_like_expression($expression)
317 {
318 // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive
319 // We only catch * and ? here, not the character map possible on file globbing.
320 $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
321
322 $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
323 $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
324
325 return 'NOT GLOB \'' . $this->sql_escape($expression) . '\'';
326 }
327
328 /**
329 * return sql error array
330 *
331 * @return array
332 */
333 protected function _sql_error()
334 {
335 if (class_exists('SQLite3', false) && isset($this->dbo))
336 {
337 $error = array(
338 'message' => $this->dbo->lastErrorMsg(),
339 'code' => $this->dbo->lastErrorCode(),
340 );
341 }
342 else
343 {
344 $error = array(
345 'message' => $this->connect_error,
346 'code' => '',
347 );
348 }
349
350 return $error;
351 }
352
353 /**
354 * Build db-specific query data
355 *
356 * @param string $stage Available stages: FROM, WHERE
357 * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses
358 *
359 * @return string The db-specific query fragment
360 */
361 protected function _sql_custom_build($stage, $data)
362 {
363 return $data;
364 }
365
366 /**
367 * Close sql connection
368 *
369 * @return bool False if failure
370 */
371 protected function _sql_close()
372 {
373 return $this->dbo->close();
374 }
375
376 /**
377 * Build db-specific report
378 *
379 * @param string $mode Available modes: display, start, stop,
380 * add_select_row, fromcache, record_fromcache
381 * @param string $query The Query that should be explained
382 * @return mixed Either a full HTML page, boolean or null
383 */
384 protected function _sql_report($mode, $query = '')
385 {
386 switch ($mode)
387 {
388 case 'start':
389
390 $explain_query = $query;
391 if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
392 {
393 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
394 }
395 else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
396 {
397 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
398 }
399
400 if (preg_match('/^SELECT/', $explain_query))
401 {
402 $html_table = false;
403
404 if ($result = @$this->dbo->query("EXPLAIN QUERY PLAN $explain_query"))
405 {
406 while ($row = $result->fetchArray(SQLITE3_ASSOC))
407 {
408 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
409 }
410 }
411
412 if ($html_table)
413 {
414 $this->html_hold .= '</table>';
415 }
416 }
417
418 break;
419
420 case 'fromcache':
421 $endtime = explode(' ', microtime());
422 $endtime = $endtime[0] + $endtime[1];
423
424 $result = $this->dbo->query($query);
425 if ($result)
426 {
427 while ($void = $result->fetchArray(SQLITE3_ASSOC))
428 {
429 // Take the time spent on parsing rows into account
430 }
431 }
432
433 $splittime = explode(' ', microtime());
434 $splittime = $splittime[0] + $splittime[1];
435
436 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
437
438 break;
439 }
440 }
441
442 /**
443 * {@inheritDoc}
444 */
445 function sql_quote($msg)
446 {
447 return '\'' . $msg . '\'';
448 }
449 }
450