diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/DbView.php | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/DbView.php')
| -rw-r--r-- | lib/classes/DbView.php | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/lib/classes/DbView.php b/lib/classes/DbView.php new file mode 100644 index 0000000..0215f8e --- /dev/null +++ b/lib/classes/DbView.php @@ -0,0 +1,378 @@ +<?php +# Lifter002: TODO +# Lifter007: TODO +# Lifter003: TODO +# Lifter010: TODO +// +---------------------------------------------------------------------------+ +// This file is part of Stud.IP +// DbView.php +// Class to provide simple Views and Prepared Statements +// Mainly for MySql, may work with other DBs (not tested) +// Copyright (c) 2002 André Noack <andre.noack@gmx.net> +// +---------------------------------------------------------------------------+ +// 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 any later version. +// +---------------------------------------------------------------------------+ +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +---------------------------------------------------------------------------+ + + +/** + * Class to provide simple Views and Prepared Statements + * + * Only tested with MySql, needs MySql >= 3.23 + * Uses DB abstraction layer of PHPLib + * + * @access public + * @author André Noack <andre.noack@gmx.net> + * @package DBTools + */ +class DbView +{ + /** + * the processed list of queries + * + * + * @access private + * @var array $query_list + */ + private $query_list = []; + /** + * list of parameters + * + * + * @access public + * @var array $params + */ + public $params = []; + + /** + * Database Object + * + * + * @access private + * @var object $db + */ + private $db; + /** + * Database Object Type + * + * Use your subclass of db_mysql here, or pass existing object to constuctor + * + * @access private + * @var string $db_class_name + * @see DbView() + */ + private $db_class_name = "DB_Seminar"; + /** + * Temp Table Type + * + * MyISAM is always safe, HEAP may provide better performance + * + * @access private + * @var string $temp_table_type + */ + private $temp_table_type = "MyISAM"; + /** + * Primary Key used in Temp Table + * + * If none is set in your view, an auto_increment row is used + * + * @access private + * @var string $pk + * @see get_temp_table() + */ + private $pk = ""; + /** + * delete the params array after each query execution + * + * + * @access public + * @var boolean $auto_free_params + */ + public $auto_free_params = true; + /** + * turn on/off debugging + * + * + * @access public + * @var boolean $debug + */ + public $debug = false; + + static protected $dbviewfiles = []; + + static protected $dbviews = []; + + public static function addView($view) + { + $view = mb_strtolower($view); + if (!isset(self::$dbviewfiles[$view])) { + self::$dbviewfiles[$view] = 0; + } + } + + /** + * Convenience method that combines addView() and returns an instance. + * + * @param String $view Required view (at least this will be present in the + * returned instance) + * @param mixed $db classname of db abstraction or existing db object + * + * @return DbView Instance of self with at least the required view loaded + */ + public static function getView($view, $db = '') + { + self::addView($view); + + return new self($db); + } + + /** + * Constructor + * + * Pass nothing to use a new instance of db_class_name, the classname for a new instance, or existing instance + * + * @access public + * + * @param mixed $db classname of used db abstraction or existing db object + */ + public function __construct($db = "") + { + if (is_object($db)) { + $this->db = $db; + } else if ($db != "") { + $this->db = new $db; + $this->db_class_name = $db; + } else { + $this->db = new $this->db_class_name; + } + $this->init_views(); + } + + public function init_views() + { + foreach (self::$dbviewfiles as $view => $status) { + if ($status === 0) { + $views = include 'lib/dbviews/' . $view . '.view.php'; + self::$dbviews += $views; + + self::$dbviewfiles[$view] = 1; + } + } + } + + public function __get($view) + { + if (isset(self::$dbviews[$view])) { + return self::$dbviews[$view]; + } else { + return null; + } + } + + /** + * print error message and exit script + * + * @access private + * + * @param string $msg the message to print + */ + public function halt($msg) + { + echo "<hr>$msg<hr>"; + if ($this->debug) { + echo "<pre>"; + print_r($this); + echo "</pre>"; + } + die; + } + + public function get_query() + { + $parsed_query = $this->get_parsed_query(func_get_args()); + $this->db->query($parsed_query); + return $this->db; + } + + public function get_parsed_query($query_list) + { + $parsed_query = ""; + $this->query_list = []; + (is_array($query_list)) ? $this->query_list = $query_list : $this->query_list[] = $query_list; + if (count($this->query_list) == 1) { + $spl = explode(":", $this->query_list[0]); + if ($spl[0] == "view") { + $this->query_list = $this->get_view(trim($spl[1])); + } + } + $this->parse_query($this->query_list); + if (is_array($this->query_list)) { + $parsed_query = $this->query_list[0]; + } else { + $parsed_query = $this->query_list; + } + + return $parsed_query; + } + + + public function parse_query(&$query) + { + if (is_array($query)) { + for ($i = (count($query) - 1); $i > 0; --$i) { + $spl = explode(":", $query[$i]); + if ($spl[0] == "view") { + $query[$i] = $this->get_view(trim($spl[1]), $spl[2]); + } + $query[$i] = $this->parse_query($query[$i]); + $repl_query = (is_array($query[$i])) ? $query[$i][0] : $query[$i]; + for ($j = 0; $j < $i; ++$j) { + $spl = mb_stristr($query[$j], "where"); + if (!$spl) + $spl = mb_stristr($query[$j], "having"); + if ($spl) { + $pos = mb_strpos($spl, "{" . $i . "}"); + if (!$pos === false) + $repl_query = $this->get_temp_values($repl_query); + } + if (!$spl OR $pos === false) { + $pos = mb_strpos($query[$j], "{" . $i . "}"); + if (!$pos === false) + $repl_query = $this->get_temp_table($repl_query); + } + $query[$j] = str_replace("{" . $i . "}", $repl_query, $query[$j]); + } + } + } + + return $query; + } + + + public function get_temp_table($sub_query) + { + $id = self::get_uniqid(); + $pk = $this->pk ? "PRIMARY KEY($this->pk)" : "auto_" . $id . " INT NOT NULL AUTO_INCREMENT PRIMARY KEY"; + $query = "CREATE TEMPORARY TABLE temp_$id ($pk) ENGINE=$this->temp_table_type $sub_query"; + $this->db->query($query); + + return " temp_" . $id . " "; + } + + + public function get_temp_values($sub_query) + { + $this->db->query($sub_query); + if (!$this->db->num_rows()) + $this->halt("Sub Query: <b>$sub_query</b> returns nothing!"); + else { + while ($this->db->next_record()) { + $result[] = $this->db->Record[0]; + } + $value_list = $this->get_value_list($result); + } + + return $value_list; + } + + public static function get_uniqid() + { + mt_srand((double)microtime() * 1000000); + + return md5(uniqid(mt_rand(), 1)); + } + + public function get_value_list($list) + { + $value_list = false; + if (count($list) == 1) + $value_list = "'$list[0]'"; + else + $value_list = "'" . join("','", $list) . "'"; + + return $value_list; + } + + public function get_view($name) + { + if (!empty(self::$dbviews[$name]["pk"])) { + $this->pk = self::$dbviews[$name]["pk"]; + } + if (!empty(self::$dbviews[$name]["temp_table_type"])) { + $this->temp_table_type = self::$dbviews[$name]["temp_table_type"]; + } + if (!$query_list = self::$dbviews[$name]["query"]) + $this->halt("View not found: $name"); + (is_array($query_list)) ? $query = $query_list[0] : $query = $query_list; + $tokens = preg_split("/[\?§\&]/u", $query); + if (count($tokens) > 1) { + $types = []; + $token = 0; + foreach (preg_split('//u', $query, null, PREG_SPLIT_NO_EMPTY) as $i => $c) { + switch ($c) { + case '?': + $types[$token++] = 1; + break; + case '§': + $types[$token++] = 2; + break; + case '&': + $types[$token++] = 3; + break; + } + } + if (count($this->params) != count($types)) + $this->halt("Wrong parameter count in view: $name"); + $query = ""; + for ($i = 0; $i < count($this->params); ++$i) { + $query .= $tokens[$i]; + if (is_null($this->params[$i])) { + $query .= 'NULL'; + } else { + switch ($types[$i]) { + case 1: + $query .= "'" . $this->params[$i] . "'"; + break; + case 2: + $query .= $this->params[$i]; + break; + case 3: + $query .= (is_array($this->params[$i])) ? "'" . join("','", $this->params[$i]) . "'" : "'" . $this->params[$i] . "'"; + break; + } + } + } + $query .= $tokens[$i]; + if ($this->auto_free_params) + $this->params = []; + } + (is_array($query_list)) ? $query_list[0] = $query : $query_list = $query; + return $query_list; + } + + public function Get_union() + { + $queries = func_get_args(); + $view = new DbView(); + $union_table = $view->get_temp_table($view->get_parsed_query($queries[0])); + if ($queries[1]) { + for ($i = 1; $i < count($queries); ++$i) { + $view->db->query("REPLACE INTO $union_table " . $view->get_parsed_query($queries[$i])); + } + } + + return $union_table; + } +} + +?> |
