This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Elgg; |
||
3 | use Elgg\Database\Config; |
||
0 ignored issues
–
show
|
|||
4 | |||
5 | /** |
||
6 | * An object representing a single Elgg database. |
||
7 | * |
||
8 | * WARNING: THIS API IS IN FLUX. PLUGIN AUTHORS SHOULD NOT USE. See lib/database.php instead. |
||
9 | * |
||
10 | * @access private |
||
11 | * |
||
12 | * @package Elgg.Core |
||
13 | * @subpackage Database |
||
14 | */ |
||
15 | class Database { |
||
16 | |||
17 | /** @var string $tablePrefix Prefix for database tables */ |
||
18 | private $tablePrefix; |
||
19 | |||
20 | /** @var resource[] $dbLinks Database connection resources */ |
||
21 | private $dbLinks = array(); |
||
22 | |||
23 | /** @var int $queryCount The number of queries made */ |
||
24 | private $queryCount = 0; |
||
25 | |||
26 | /** |
||
27 | * Query cache for select queries. |
||
28 | * |
||
29 | * Queries and their results are stored in this cache as: |
||
30 | * <code> |
||
31 | * $DB_QUERY_CACHE[query hash] => array(result1, result2, ... resultN) |
||
32 | * </code> |
||
33 | * @see \Elgg\Database::getResults() for details on the hash. |
||
34 | * |
||
35 | * @var \Elgg\Cache\LRUCache $queryCache The cache |
||
36 | */ |
||
37 | private $queryCache = null; |
||
38 | |||
39 | /** |
||
40 | * @var int $queryCacheSize The number of queries to cache |
||
41 | */ |
||
42 | private $queryCacheSize = 50; |
||
43 | |||
44 | /** |
||
45 | * Queries are saved to an array and executed using |
||
46 | * a function registered by register_shutdown_function(). |
||
47 | * |
||
48 | * Queries are saved as an array in the format: |
||
49 | * <code> |
||
50 | * $this->delayedQueries[] = array( |
||
51 | * 'q' => string $query, |
||
52 | * 'l' => string $query_type, |
||
53 | * 'h' => string $handler // a callback function |
||
54 | * ); |
||
55 | * </code> |
||
56 | * |
||
57 | * @var array $delayedQueries Queries to be run during shutdown |
||
58 | */ |
||
59 | private $delayedQueries = array(); |
||
60 | |||
61 | /** @var bool $installed Is the database installed? */ |
||
62 | private $installed = false; |
||
63 | |||
64 | /** @var \Elgg\Database\Config $config Database configuration */ |
||
65 | private $config; |
||
66 | |||
67 | /** @var \Elgg\Logger $logger The logger */ |
||
68 | private $logger; |
||
69 | |||
70 | /** |
||
71 | * Constructor |
||
72 | * |
||
73 | * @param \Elgg\Database\Config $config Database configuration |
||
74 | * @param \Elgg\Logger $logger The logger |
||
75 | */ |
||
76 | 7 | public function __construct(\Elgg\Database\Config $config, \Elgg\Logger $logger) { |
|
77 | |||
78 | 7 | $this->logger = $logger; |
|
79 | 7 | $this->config = $config; |
|
80 | |||
81 | 7 | $this->tablePrefix = $config->getTablePrefix(); |
|
82 | |||
83 | 7 | $this->enableQueryCache(); |
|
84 | 7 | } |
|
85 | |||
86 | /** |
||
87 | * Gets (if required, also creates) a database link resource. |
||
88 | * |
||
89 | * The database link resources are created by |
||
90 | * {@link \Elgg\Database::setupConnections()}, which is called if no links exist. |
||
91 | * |
||
92 | * @param string $type The type of link we want: "read", "write" or "readwrite". |
||
93 | * |
||
94 | * @return resource Database link |
||
95 | * @throws \DatabaseException |
||
96 | * @todo make protected once we get rid of get_db_link() |
||
97 | */ |
||
98 | public function getLink($type) { |
||
99 | if (isset($this->dbLinks[$type])) { |
||
100 | return $this->dbLinks[$type]; |
||
101 | } else if (isset($this->dbLinks['readwrite'])) { |
||
102 | return $this->dbLinks['readwrite']; |
||
103 | } else { |
||
104 | $this->setupConnections(); |
||
105 | return $this->getLink($type); |
||
106 | } |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Establish database connections |
||
111 | * |
||
112 | * If the configuration has been set up for multiple read/write databases, set those |
||
113 | * links up separately; otherwise just create the one database link. |
||
114 | * |
||
115 | * @return void |
||
116 | * @throws \DatabaseException |
||
117 | */ |
||
118 | public function setupConnections() { |
||
119 | if ($this->config->isDatabaseSplit()) { |
||
120 | $this->establishLink('read'); |
||
121 | $this->establishLink('write'); |
||
122 | } else { |
||
123 | $this->establishLink('readwrite'); |
||
124 | } |
||
125 | } |
||
126 | |||
127 | |||
128 | /** |
||
129 | * Establish a connection to the database server |
||
130 | * |
||
131 | * Connect to the database server and use the Elgg database for a particular database link |
||
132 | * |
||
133 | * @param string $dblinkname The type of database connection. Used to identify the |
||
134 | * resource: "read", "write", or "readwrite". |
||
135 | * |
||
136 | * @return void |
||
137 | * @throws \DatabaseException |
||
138 | */ |
||
139 | public function establishLink($dblinkname = "readwrite") { |
||
140 | |||
141 | $conf = $this->config->getConnectionConfig($dblinkname); |
||
142 | |||
143 | // Connect to database |
||
144 | $this->dbLinks[$dblinkname] = mysql_connect($conf['host'], $conf['user'], $conf['password'], true); |
||
145 | if (!$this->dbLinks[$dblinkname]) { |
||
146 | $msg = "Elgg couldn't connect to the database using the given credentials. Check the settings file."; |
||
147 | throw new \DatabaseException($msg); |
||
148 | } |
||
149 | |||
150 | if (!mysql_select_db($conf['database'], $this->dbLinks[$dblinkname])) { |
||
151 | $msg = "Elgg couldn't select the database '{$conf['database']}'. Please check that the database is created and you have access to it."; |
||
152 | throw new \DatabaseException($msg); |
||
153 | } |
||
154 | |||
155 | // Set DB for UTF8 |
||
156 | mysql_query("SET NAMES utf8", $this->dbLinks[$dblinkname]); |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Retrieve rows from the database. |
||
161 | * |
||
162 | * Queries are executed with {@link \Elgg\Database::executeQuery()} and results |
||
163 | * are retrieved with {@link mysql_fetch_object()}. If a callback |
||
164 | * function $callback is defined, each row will be passed as a single |
||
165 | * argument to $callback. If no callback function is defined, the |
||
166 | * entire result set is returned as an array. |
||
167 | * |
||
168 | * @param mixed $query The query being passed. |
||
169 | * @param string $callback Optionally, the name of a function to call back to on each row |
||
170 | * |
||
171 | * @return array An array of database result objects or callback function results. If the query |
||
172 | * returned nothing, an empty array. |
||
173 | * @throws \DatabaseException |
||
174 | */ |
||
175 | public function getData($query, $callback = '') { |
||
176 | return $this->getResults($query, $callback, false); |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Retrieve a single row from the database. |
||
181 | * |
||
182 | * Similar to {@link \Elgg\Database::getData()} but returns only the first row |
||
183 | * matched. If a callback function $callback is specified, the row will be passed |
||
184 | * as the only argument to $callback. |
||
185 | * |
||
186 | * @param mixed $query The query to execute. |
||
187 | * @param string $callback A callback function |
||
188 | * |
||
189 | * @return mixed A single database result object or the result of the callback function. |
||
190 | * @throws \DatabaseException |
||
191 | */ |
||
192 | public function getDataRow($query, $callback = '') { |
||
193 | return $this->getResults($query, $callback, true); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Insert a row into the database. |
||
198 | * |
||
199 | * @note Altering the DB invalidates all queries in the query cache. |
||
200 | * |
||
201 | * @param mixed $query The query to execute. |
||
202 | * |
||
203 | * @return int|false The database id of the inserted row if a AUTO_INCREMENT field is |
||
204 | * defined, 0 if not, and false on failure. |
||
205 | * @throws \DatabaseException |
||
206 | */ |
||
207 | View Code Duplication | public function insertData($query) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
208 | |||
209 | $this->logger->log("DB query $query", \Elgg\Logger::INFO); |
||
210 | |||
211 | $dblink = $this->getLink('write'); |
||
212 | |||
213 | $this->invalidateQueryCache(); |
||
214 | |||
215 | if ($this->executeQuery("$query", $dblink)) { |
||
216 | return mysql_insert_id($dblink); |
||
217 | } |
||
218 | |||
219 | return false; |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Update the database. |
||
224 | * |
||
225 | * @note Altering the DB invalidates all queries in the query cache. |
||
226 | * |
||
227 | * @param string $query The query to run. |
||
228 | * @param bool $getNumRows Return the number of rows affected (default: false) |
||
229 | * |
||
230 | * @return bool|int |
||
231 | * @throws \DatabaseException |
||
232 | */ |
||
233 | public function updateData($query, $getNumRows = false) { |
||
234 | |||
235 | $this->logger->log("DB query $query", \Elgg\Logger::INFO); |
||
236 | |||
237 | $dblink = $this->getLink('write'); |
||
238 | |||
239 | $this->invalidateQueryCache(); |
||
240 | |||
241 | if ($this->executeQuery("$query", $dblink)) { |
||
242 | if ($getNumRows) { |
||
243 | return mysql_affected_rows($dblink); |
||
244 | } else { |
||
245 | return true; |
||
246 | } |
||
247 | } |
||
248 | |||
249 | return false; |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * Delete data from the database |
||
254 | * |
||
255 | * @note Altering the DB invalidates all queries in query cache. |
||
256 | * |
||
257 | * @param string $query The SQL query to run |
||
258 | * |
||
259 | * @return int|false The number of affected rows or false on failure |
||
260 | * @throws \DatabaseException |
||
261 | */ |
||
262 | View Code Duplication | public function deleteData($query) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
263 | |||
264 | $this->logger->log("DB query $query", \Elgg\Logger::INFO); |
||
265 | |||
266 | $dblink = $this->getLink('write'); |
||
267 | |||
268 | $this->invalidateQueryCache(); |
||
269 | |||
270 | if ($this->executeQuery("$query", $dblink)) { |
||
271 | return mysql_affected_rows($dblink); |
||
272 | } |
||
273 | |||
274 | return false; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Get a string that uniquely identifies a callback during the current request. |
||
279 | * |
||
280 | * This is used to cache queries whose results were transformed by the callback. If the callback involves |
||
281 | * object method calls of the same class, different instances will return different values. |
||
282 | * |
||
283 | * @param callable $callback The callable value to fingerprint |
||
284 | * |
||
285 | * @return string A string that is unique for each callable passed in |
||
286 | * @since 1.9.4 |
||
287 | * @access private |
||
288 | * @todo Make this protected once we can setAccessible(true) via reflection |
||
289 | */ |
||
290 | 1 | public function fingerprintCallback($callback) { |
|
291 | 1 | if (is_string($callback)) { |
|
292 | 1 | return $callback; |
|
293 | } |
||
294 | 1 | if (is_object($callback)) { |
|
295 | 1 | return spl_object_hash($callback) . "::__invoke"; |
|
296 | } |
||
297 | 1 | if (is_array($callback)) { |
|
298 | 1 | if (is_string($callback[0])) { |
|
299 | 1 | return "{$callback[0]}::{$callback[1]}"; |
|
300 | } |
||
301 | 1 | return spl_object_hash($callback[0]) . "::{$callback[1]}"; |
|
302 | } |
||
303 | // this should not happen |
||
304 | return ""; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Handles queries that return results, running the results through a |
||
309 | * an optional callback function. This is for R queries (from CRUD). |
||
310 | * |
||
311 | * @param string $query The select query to execute |
||
312 | * @param string $callback An optional callback function to run on each row |
||
313 | * @param bool $single Return only a single result? |
||
314 | * |
||
315 | * @return array An array of database result objects or callback function results. If the query |
||
316 | * returned nothing, an empty array. |
||
317 | * @throws \DatabaseException |
||
318 | */ |
||
319 | protected function getResults($query, $callback = null, $single = false) { |
||
320 | |||
321 | // Since we want to cache results of running the callback, we need to |
||
322 | // need to namespace the query with the callback and single result request. |
||
323 | // https://github.com/elgg/elgg/issues/4049 |
||
324 | $query_id = (int)$single . $query . '|'; |
||
325 | if ($callback) { |
||
0 ignored issues
–
show
The expression
$callback of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
326 | $is_callable = is_callable($callback); |
||
327 | if ($is_callable) { |
||
328 | $query_id .= $this->fingerprintCallback($callback); |
||
329 | } else { |
||
330 | // TODO do something about invalid callbacks |
||
331 | $callback = null; |
||
332 | } |
||
333 | } else { |
||
334 | $is_callable = false; |
||
335 | } |
||
336 | // MD5 yields smaller mem usage for cache and cleaner logs |
||
337 | $hash = md5($query_id); |
||
338 | |||
339 | // Is cached? |
||
340 | View Code Duplication | if ($this->queryCache) { |
|
341 | if (isset($this->queryCache[$hash])) { |
||
342 | $this->logger->log("DB query $query results returned from cache (hash: $hash)", \Elgg\Logger::INFO); |
||
343 | return $this->queryCache[$hash]; |
||
344 | } |
||
345 | } |
||
346 | |||
347 | $dblink = $this->getLink('read'); |
||
348 | $return = array(); |
||
349 | |||
350 | if ($result = $this->executeQuery("$query", $dblink)) { |
||
351 | while ($row = mysql_fetch_object($result)) { |
||
352 | if ($is_callable) { |
||
353 | $row = call_user_func($callback, $row); |
||
354 | } |
||
355 | |||
356 | if ($single) { |
||
357 | $return = $row; |
||
358 | break; |
||
359 | } else { |
||
360 | $return[] = $row; |
||
361 | } |
||
362 | } |
||
363 | } |
||
364 | |||
365 | if (empty($return)) { |
||
366 | $this->logger->log("DB query $query returned no results.", \Elgg\Logger::INFO); |
||
367 | } |
||
368 | |||
369 | // Cache result |
||
370 | View Code Duplication | if ($this->queryCache) { |
|
371 | $this->queryCache[$hash] = $return; |
||
372 | $this->logger->log("DB query $query results cached (hash: $hash)", \Elgg\Logger::INFO); |
||
373 | } |
||
374 | |||
375 | return $return; |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Execute a query. |
||
380 | * |
||
381 | * $query is executed via {@link mysql_query()}. If there is an SQL error, |
||
382 | * a {@link DatabaseException} is thrown. |
||
383 | * |
||
384 | * @param string $query The query |
||
385 | * @param resource $dblink The DB link |
||
386 | * |
||
387 | * @return resource|bool The result of mysql_query() |
||
388 | * @throws \DatabaseException |
||
389 | * @todo should this be public? |
||
390 | */ |
||
391 | public function executeQuery($query, $dblink) { |
||
392 | |||
393 | if ($query == null) { |
||
394 | throw new \DatabaseException("Query cannot be null"); |
||
395 | } |
||
396 | |||
397 | if (!is_resource($dblink)) { |
||
398 | throw new \DatabaseException("Connection to database was lost."); |
||
399 | } |
||
400 | |||
401 | $this->queryCount++; |
||
402 | |||
403 | $result = mysql_query($query, $dblink); |
||
404 | |||
405 | if (mysql_errno($dblink)) { |
||
406 | throw new \DatabaseException(mysql_error($dblink) . "\n\n QUERY: $query"); |
||
407 | } |
||
408 | |||
409 | return $result; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Runs a full database script from disk. |
||
414 | * |
||
415 | * The file specified should be a standard SQL file as created by |
||
416 | * mysqldump or similar. Statements must be terminated with ; |
||
417 | * and a newline character (\n or \r\n). |
||
418 | * |
||
419 | * The special string 'prefix_' is replaced with the database prefix |
||
420 | * as defined in {@link $this->tablePrefix}. |
||
421 | * |
||
422 | * @warning Only single line comments are supported. A comment |
||
423 | * must start with '-- ' or '# ', where the comment sign is at the |
||
424 | * very beginning of each line. |
||
425 | * |
||
426 | * @warning Errors do not halt execution of the script. If a line |
||
427 | * generates an error, the error message is saved and the |
||
428 | * next line is executed. After the file is run, any errors |
||
429 | * are displayed as a {@link DatabaseException} |
||
430 | * |
||
431 | * @param string $scriptlocation The full path to the script |
||
432 | * |
||
433 | * @return void |
||
434 | * @throws \DatabaseException |
||
435 | */ |
||
436 | 5 | public function runSqlScript($scriptlocation) { |
|
437 | 5 | $script = file_get_contents($scriptlocation); |
|
438 | 5 | if ($script) { |
|
439 | |||
440 | 5 | $errors = array(); |
|
441 | |||
442 | // Remove MySQL '-- ' and '# ' style comments |
||
443 | 5 | $script = preg_replace('/^(?:--|#) .*$/m', '', $script); |
|
444 | |||
445 | // Statements must end with ; and a newline |
||
446 | 5 | $sql_statements = preg_split('/;[\n\r]+/', "$script\n"); |
|
447 | |||
448 | 5 | foreach ($sql_statements as $statement) { |
|
449 | 5 | $statement = trim($statement); |
|
450 | 5 | $statement = str_replace("prefix_", $this->tablePrefix, $statement); |
|
451 | 5 | if (!empty($statement)) { |
|
452 | try { |
||
453 | 5 | $this->updateData($statement); |
|
454 | 5 | } catch (\DatabaseException $e) { |
|
455 | $errors[] = $e->getMessage(); |
||
456 | } |
||
457 | 5 | } |
|
458 | 5 | } |
|
459 | 5 | if (!empty($errors)) { |
|
460 | $errortxt = ""; |
||
461 | foreach ($errors as $error) { |
||
462 | $errortxt .= " {$error};"; |
||
463 | } |
||
464 | |||
465 | $msg = "There were a number of issues: " . $errortxt; |
||
466 | throw new \DatabaseException($msg); |
||
467 | } |
||
468 | 5 | } else { |
|
469 | $msg = "Elgg couldn't find the requested database script at " . $scriptlocation . "."; |
||
470 | throw new \DatabaseException($msg); |
||
471 | } |
||
472 | 5 | } |
|
473 | |||
474 | /** |
||
475 | * Queue a query for execution upon shutdown. |
||
476 | * |
||
477 | * You can specify a handler function if you care about the result. This function will accept |
||
478 | * the raw result from {@link mysql_query()}. |
||
479 | * |
||
480 | * @param string $query The query to execute |
||
481 | * @param string $type The query type ('read' or 'write') |
||
482 | * @param string $handler A callback function to pass the results array to |
||
483 | * |
||
484 | * @return boolean Whether registering was successful. |
||
485 | * @todo deprecate passing resource for $type as that should not be part of public API |
||
486 | */ |
||
487 | public function registerDelayedQuery($query, $type, $handler = "") { |
||
488 | |||
489 | if (!is_resource($type) && $type != 'read' && $type != 'write') { |
||
490 | return false; |
||
491 | } |
||
492 | |||
493 | // Construct delayed query |
||
494 | $delayed_query = array(); |
||
495 | $delayed_query['q'] = $query; |
||
496 | $delayed_query['l'] = $type; |
||
497 | $delayed_query['h'] = $handler; |
||
498 | |||
499 | $this->delayedQueries[] = $delayed_query; |
||
500 | |||
501 | return true; |
||
502 | } |
||
503 | |||
504 | |||
505 | /** |
||
506 | * Trigger all queries that were registered as "delayed" queries. This is |
||
507 | * called by the system automatically on shutdown. |
||
508 | * |
||
509 | * @return void |
||
510 | * @access private |
||
511 | * @todo make protected once this class is part of public API |
||
512 | */ |
||
513 | public function executeDelayedQueries() { |
||
514 | |||
515 | foreach ($this->delayedQueries as $query_details) { |
||
516 | try { |
||
517 | $link = $query_details['l']; |
||
518 | |||
519 | if ($link == 'read' || $link == 'write') { |
||
520 | $link = $this->getLink($link); |
||
521 | } elseif (!is_resource($link)) { |
||
522 | $msg = "Link for delayed query not valid resource or db_link type. Query: {$query_details['q']}"; |
||
523 | $this->logger->log($msg, \Elgg\Logger::WARNING); |
||
524 | } |
||
525 | |||
526 | $result = $this->executeQuery($query_details['q'], $link); |
||
527 | |||
528 | if ((isset($query_details['h'])) && (is_callable($query_details['h']))) { |
||
529 | $query_details['h']($result); |
||
530 | } |
||
531 | } catch (\DatabaseException $e) { |
||
532 | // Suppress all exceptions since page already sent to requestor |
||
533 | $this->logger->log($e, \Elgg\Logger::ERROR); |
||
534 | } |
||
535 | } |
||
536 | } |
||
537 | |||
538 | /** |
||
539 | * Enable the query cache |
||
540 | * |
||
541 | * This does not take precedence over the \Elgg\Database\Config setting. |
||
542 | * |
||
543 | * @return void |
||
544 | */ |
||
545 | 7 | public function enableQueryCache() { |
|
546 | 7 | if ($this->config->isQueryCacheEnabled() && $this->queryCache === null) { |
|
547 | // @todo if we keep this cache, expose the size as a config parameter |
||
548 | 7 | $this->queryCache = new \Elgg\Cache\LRUCache($this->queryCacheSize); |
|
549 | 7 | } |
|
550 | 7 | } |
|
551 | |||
552 | /** |
||
553 | * Disable the query cache |
||
554 | * |
||
555 | * This is useful for special scripts that pull large amounts of data back |
||
556 | * in single queries. |
||
557 | * |
||
558 | * @return void |
||
559 | */ |
||
560 | public function disableQueryCache() { |
||
561 | $this->queryCache = null; |
||
562 | } |
||
563 | |||
564 | /** |
||
565 | * Invalidate the query cache |
||
566 | * |
||
567 | * @return void |
||
568 | */ |
||
569 | protected function invalidateQueryCache() { |
||
570 | if ($this->queryCache) { |
||
571 | $this->queryCache->clear(); |
||
572 | $this->logger->log("Query cache invalidated", \Elgg\Logger::INFO); |
||
573 | } |
||
574 | } |
||
575 | |||
576 | /** |
||
577 | * Test that the Elgg database is installed |
||
578 | * |
||
579 | * @return void |
||
580 | * @throws \InstallationException |
||
581 | */ |
||
582 | public function assertInstalled() { |
||
583 | |||
584 | if ($this->installed) { |
||
585 | return; |
||
586 | } |
||
587 | |||
588 | try { |
||
589 | $dblink = $this->getLink('read'); |
||
590 | mysql_query("SELECT value FROM {$this->tablePrefix}datalists WHERE name = 'installed'", $dblink); |
||
591 | if (mysql_errno($dblink) > 0) { |
||
592 | throw new \DatabaseException(); |
||
593 | } |
||
594 | } catch (\DatabaseException $e) { |
||
595 | throw new \InstallationException("Unable to handle this request. This site is not configured or the database is down."); |
||
596 | } |
||
597 | |||
598 | $this->installed = true; |
||
599 | } |
||
600 | |||
601 | /** |
||
602 | * Get the number of queries made to the database |
||
603 | * |
||
604 | * @return int |
||
605 | */ |
||
606 | public function getQueryCount() { |
||
607 | return $this->queryCount; |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Get the prefix for Elgg's tables |
||
612 | * |
||
613 | * @return string |
||
614 | */ |
||
615 | 1 | public function getTablePrefix() { |
|
616 | 1 | return $this->tablePrefix; |
|
617 | } |
||
618 | |||
619 | /** |
||
620 | * Sanitizes an integer value for use in a query |
||
621 | * |
||
622 | * @param int $value Value to sanitize |
||
623 | * @param bool $signed Whether negative values are allowed (default: true) |
||
624 | * @return int |
||
625 | */ |
||
626 | 3 | public function sanitizeInt($value, $signed = true) { |
|
627 | 3 | $value = (int) $value; |
|
628 | |||
629 | 3 | if ($signed === false) { |
|
630 | if ($value < 0) { |
||
631 | $value = 0; |
||
632 | } |
||
633 | } |
||
634 | |||
635 | 3 | return $value; |
|
636 | } |
||
637 | |||
638 | /** |
||
639 | * Sanitizes a string for use in a query |
||
640 | * |
||
641 | * @param string $value Value to escape |
||
642 | * @return string |
||
643 | */ |
||
644 | public function sanitizeString($value) { |
||
645 | |||
646 | // use resource if established, but don't open a connection to do it. |
||
647 | if (isset($this->dbLinks['read'])) { |
||
648 | return mysql_real_escape_string($value, $this->dbLinks['read']); |
||
649 | } |
||
650 | |||
651 | return mysql_real_escape_string($value); |
||
652 | } |
||
653 | |||
654 | /** |
||
655 | * Get the server version number |
||
656 | * |
||
657 | * @param string $type Connection type (Config constants, e.g. Config::READ_WRITE) |
||
658 | * |
||
659 | * @return string |
||
660 | */ |
||
661 | public function getServerVersion($type) { |
||
662 | return mysql_get_server_info($this->getLink($type)); |
||
663 | } |
||
664 | } |
||
665 | |||
666 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: