aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/StudipPDO.class.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/classes/StudipPDO.class.php')
-rw-r--r--lib/classes/StudipPDO.class.php413
1 files changed, 0 insertions, 413 deletions
diff --git a/lib/classes/StudipPDO.class.php b/lib/classes/StudipPDO.class.php
deleted file mode 100644
index e77a37f..0000000
--- a/lib/classes/StudipPDO.class.php
+++ /dev/null
@@ -1,413 +0,0 @@
-<?php
-/**
- * StudipPDO.class.php - Stud.IP PDO class
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * @author Elmar Ludwig
- * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category Stud.IP
- */
-
-/**
- * This is a special variant of the standard PDO class that does
- * not allow multiple statement execution.
- */
-class StudipPDO extends PDO
-{
- const PARAM_ARRAY = 100;
- const PARAM_COLUMN = 101;
-
- // Counter for the queries sent to the database
- public $query_count = 0;
- public $queries = [];
-
- /**
- * Verifies that the given SQL query only contains a single statement.
- *
- * @param string SQL statement to check
- * @throws PDOException when the query contains multiple statements
- */
- protected function verify($statement)
- {
- if (mb_strpos($statement, ';') !== false) {
- if (preg_match('/;\s*\S/', self::replaceStrings($statement))) {
- throw new PDOException('multiple statement execution not allowed');
- }
- }
-
- // Count executed queries (this is placed here since this is the only
- // method that is executed on every call to the database)
- $this->query_count += 1;
-
- if (!empty($GLOBALS['DEBUG_ALL_DB_QUERIES'])) {
- $trace = debug_backtrace();
-
- $classes = [];
- if (isset($trace[2]['class']) && $trace[2]['class'] === 'SimpleORMap') {
- $classes[] = 'sorm';
- }
- if (isset($trace[1]) && $trace[1]['function'] === 'prepare') {
- $classes[] = 'prepared';
- }
-
- $this->queries[] = [
- 'query' => implode("\n", array_filter(array_map('trim', explode("\n", $statement)))),
- 'classes' => implode(' ', $classes),
- 'trace' => $GLOBALS['DEBUG_ALL_DB_QUERIES_WITH_TRACE']
- ? array_slice($trace, 2)
- : null,
- ];
- }
- }
-
- /**
- * Replaces all string literals in the statement with placeholders.
- *
- * @param string SQL statement
- * @return string modified SQL statement
- */
- protected static function replaceStrings($statement)
- {
- $count = mb_substr_count($statement, '"') + mb_substr_count($statement, "'") + mb_substr_count($statement, '\\');
-
- // use fast preg_replace() variant if possible
- if ($count < 1000) {
- $result = preg_replace('/"(""|\\\\.|[^\\\\"]+)*"|\'(\'\'|\\\\.|[^\\\\\']+)*\'/s', '?', $statement);
- }
-
- if (!isset($result)) {
- // split string into parts at quotes and backslash
- $parts = preg_split('/([\\\\"\'])/', $statement, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
- $result = '';
- $quote_chr = null;
-
- for ($part = current($parts); $part !== false; $part = next($parts)) {
- // inside quotes, "" is ", '' is ' and \x is x
- if ($quote_chr !== NULL) {
- if ($part === $quote_chr) {
- $part = next($parts);
-
- if ($part !== $quote_chr) {
- // backtrack and terminate string
- prev($parts);
- $result .= '?';
- $quote_chr = NULL;
- }
- } else if ($part === '\\') {
- // skip next part
- next($parts);
- }
- } else if ($part === "'" || $part === '"') {
- $quote_chr = $part;
- $saved_pos = key($parts);
- } else {
- $result .= $part;
- }
- }
-
- if ($quote_chr !== NULL) {
- // unterminated quote: copy to end of string
- $result .= implode(array_slice($parts, $saved_pos));
- }
- }
-
- return $result;
- }
-
- /**
- * Quotes the given value in a form appropriate for the type.
- * If no explicit type is given, the value's PHP type is used.
- *
- * @param mixed $value PHP value to quote
- * @param ?int $type parameter type (e.g. PDO::PARAM_STR)
- * @return string|false quoted SQL string
- *
- * @todo Add string|false return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function quote($value, $type = null)
- {
- if (!isset($type)) {
- if (is_null($value)) {
- $type = PDO::PARAM_NULL;
- } else if (is_bool($value)) {
- $type = PDO::PARAM_BOOL;
- } else if (is_int($value)) {
- $type = PDO::PARAM_INT;
- } else if (is_array($value)) {
- $type = StudipPDO::PARAM_ARRAY;
- } else {
- $type = PDO::PARAM_STR;
- }
- }
-
- switch ($type) {
- case PDO::PARAM_NULL:
- return 'NULL';
- case PDO::PARAM_BOOL:
- return $value ? '1' : '0';
- case PDO::PARAM_INT:
- return (int) $value;
- case StudipPDO::PARAM_ARRAY:
- return is_array($value) && count($value) ? join(',', array_map([$this, 'quote'], $value)) : 'NULL';
- case StudipPDO::PARAM_COLUMN:
- return preg_replace('/\\W/', '', $value);
- default:
- return parent::quote($value);
- }
- }
-
- /**
- * Executes an SQL statement and returns the number of affected rows.
- *
- * @param string SQL statement
- * @return int|false number of affected rows
- *
- * @todo Add mixed return type when Stud.IP requires PHP8 minimal
- */
- #[ReturnTypeWillChange]
- public function exec($statement)
- {
- $this->verify($statement);
- return parent::exec($statement);
- }
-
- /**
- * Executes an SQL statement, returning a result set as a statement object.
- *
- * @param string $statement SQL statement
- * @param int $fetch_mode fetch mode (optional)
- * @param mixed ...$fetch_args fetch mode parameters (see PDOStatement::setFetchMode)
- * @return object PDOStatement object
- */
- #[ReturnTypeWillChange]
- public function query($statement, $fetch_mode = NULL, ...$fetch_args)
- {
- $this->verify($statement);
-
- if (isset($fetch_mode)) {
- $stmt = parent::query($statement, $fetch_mode, ...$fetch_args);
- } else {
- $stmt = parent::query($statement);
- }
-
- $studip_stmt = new StudipPDOStatement($this, $statement, []);
- $studip_stmt->setStatement($stmt);
- return $studip_stmt;
- }
-
- /**
- * Prepares a statement for execution and returns a statement object.
- *
- * @param string $statement SQL statement
- * @param array $driver_options
- *
- * @return StudipPDOStatement
- */
- #[ReturnTypeWillChange]
- public function prepare($statement, $driver_options = [])
- {
- $this->verify($statement);
- return new StudipPDOStatement($this, $statement, $driver_options);
- }
-
- /**
- * This method is intended only for use by the StudipPDOStatement class.
- *
- * @param string SQL statement
- * @return object PDOStatement object
- */
- public function prepareStatement($statement, $driver_options = [])
- {
- return parent::prepare($statement, $driver_options);
- }
-
- /**
- * Executes sql statement with given parameters,
- * returns number of affected rows, use only for INSERT,UPDATE etc
- *
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @return integer number of affected rows
- */
- public function execute($statement, $input_parameters = null)
- {
- $st = $this->prepare($statement);
- $ok = $st->execute($input_parameters);
- if ($ok === true) {
- return $st->rowCount();
- }
- return 0;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch results
- * as sequential array, each row as associative array
- * optionally apply given callable on each row, with current row and key as parameter
- *
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param callable $callable callable to be applied to each of the rows
- * @return array result set as array of assoc arrays
- */
- public function fetchAll($statement, $input_parameters = null, $callable = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- if (is_callable($callable)) {
- $data = [];
- $st->setFetchMode(PDO::FETCH_ASSOC);
- foreach ($st as $key => $row) {
- $data[$key] = call_user_func($callable, $row, $key);
- }
- } else {
- $data = $st->fetchAll(PDO::FETCH_ASSOC);
- }
- return $data;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch only
- * the values from first column as sequential array
- * optionally apply given callable on each row, with current value and key as parameter
- *
- * @see StudipPDOStatement::fetchFirst()
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param callable $callable callable to be applied to each of the rows
- * @return array result set
- */
- public function fetchFirst($statement, $input_parameters = null, $callable = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- $data = $st->fetchFirst();
- if (is_callable($callable)) {
- foreach ($data as $key => $row) {
- $data[$key] = call_user_func($callable, $row, $key);
- }
- }
- return $data;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch results
- * as associative array, first columns value is used as a key, the others are grouped
- * optionally apply given callable on each grouped row, with current row and key as parameter
- * if no callable is given, 'current' is used, to return the first entry of the grouped row
- *
- * @see StudipPDOStatement::fetchGrouped()
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param callable $callable callable to be applied to each of the rows
- * @return array result set
- */
- public function fetchGrouped($statement, $input_parameters = null, $callable = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- $data = $st->fetchGrouped(PDO::FETCH_ASSOC, is_null($callable) ? 'current' : null);
- if (is_callable($callable)) {
- foreach ($data as $key => $row) {
- $data[$key] = call_user_func($callable, $row, $key);
- }
- }
- return $data;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch results
- * as associative array, first columns value is used as a key, the other one is grouped
- * use only when selecting 2 columns
- * optionally apply given callable on each grouped row, with current row and key as parameter
- *
- * @see StudipPDOStatement::fetchGroupedPairs()
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param callable $callable callable to be applied to each of the rows
- * @return array result set
- */
- public function fetchGroupedPairs($statement, $input_parameters = null, $callable = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- $data = $st->fetchGroupedPairs();
- if (is_callable($callable)) {
- foreach ($data as $key => $row) {
- $data[$key] = call_user_func($callable, $row, $key);
- }
- }
- return $data;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch results
- * as associative array, first columns value is used as a key, the other one as the value
- * use only when selecting 2 columns
- * optionally apply given callable on each grouped row, with current row and key as parameter
- *
- * @see StudipPDOStatement::fetchGroupedPairs()
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param callable $callable callable to be applied to each of the rows
- * @return array result set
- */
- public function fetchPairs($statement, $input_parameters = null, $callable = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- $data = $st->fetchPairs();
- if (is_callable($callable)) {
- foreach ($data as $key => $row) {
- $data[$key] = call_user_func($callable, $row, $key);
- }
- }
- return $data;
- }
-
- /**
- * Executes sql statement with given parameters, and fetch only the first row
- * as associative array
- *
- * @see StudipPDOStatement::fetchOne()
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @return array first row of result set
- */
- public function fetchOne($statement, $input_parameters = null)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- return $st->fetchOne();
- }
-
- /**
- * Executes sql statement with given parameters, and fetch only the value of one column
- * third param denotes the column, zero indexed
- *
- * @param string $statement SQL statement to execute
- * @param array $input_parameters parameters for statement
- * @param integer $column number of column to fetch
- * @return string value of chosen column
- */
- public function fetchColumn($statement, $input_parameters = null, $column = 0)
- {
- $st = $this->prepare($statement);
- $st->execute($input_parameters);
- return $st->fetchColumn($column);
- }
-
- /**
- * Determine if the connected database is a MariaDB database.
- *
- * @return bool
- */
- public function isMariaDB(): bool
- {
- return stripos($this->getAttribute(\PDO::ATTR_SERVER_VERSION), 'MariaDB') !== false;
- }
-}