uawdijnntqw1x1x1
IP : 216.73.216.23
Hostname : web17.us.cloudlogin.co
Kernel : Linux web17.us.cloudlogin.co 5.10.238-xeon-hst #1 SMP Thu Jun 5 12:15:42 UTC 2025 x86_64
Disable Function : None :)
OS : Linux
PATH:
/
home
/
www
/
hallgroupsolutions.com
/
.
/
c9428
/
db.tar
/
/
driver/oracle.php000077700000045647151514672100010046 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * Oracle Database Abstraction Layer */ class oracle extends \phpbb\db\driver\driver { var $last_query_text = ''; var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $this->persistency = $persistency; $this->user = $sqluser; $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; $connect = $database; // support for "easy connect naming" if ($sqlserver !== '' && $sqlserver !== '/') { if (substr($sqlserver, -1, 1) == '/') { $sqlserver == substr($sqlserver, 0, -1); } $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; } if ($new_link) { if (!function_exists('ocinlogon')) { $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); } else if ($this->persistency) { if (!function_exists('ociplogon')) { $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); } else { if (!function_exists('ocilogon')) { $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { /** * force $use_cache false. I didn't research why the caching code below is commented out * but I assume its because the Oracle extension provides a direct method to access it * without a query. */ $use_cache = false; /* global $cache; if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false) { $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\''); @ociexecute($result, OCI_DEFAULT); @ocicommit($this->db_connect_id); $row = array(); @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS); @ocifreestatement($result); $this->sql_server_version = trim($row['BANNER']); $cache->put('oracle_version', $this->sql_server_version); } */ $this->sql_server_version = @ociserverversion($this->db_connect_id); return $this->sql_server_version; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return true; break; case 'commit': return @ocicommit($this->db_connect_id); break; case 'rollback': return @ocirollback($this->db_connect_id); break; } return true; } /** * Oracle specific code to handle the fact that it does not compare columns properly * @access private */ function _rewrite_col_compare($args) { if (sizeof($args) == 4) { if ($args[2] == '=') { return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))'; } else if ($args[2] == '<>') { // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))'; } } else { return $this->_rewrite_where($args[0]); } } /** * Oracle specific code to handle it's lack of sanity * @access private */ function _rewrite_where($where_clause) { preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); $out = ''; foreach ($result as $val) { if (!isset($val[5])) { if ($val[4] !== "''") { $out .= $val[0]; } else { $out .= ' ' . $val[1] . ' ' . $val[2]; if ($val[3] == '=') { $out .= ' is NULL'; } else if ($val[3] == '<>') { $out .= ' is NOT NULL'; } } } else { $in_clause = array(); $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); $extra = false; preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); $i = 0; foreach ($sub_vals[0] as $sub_val) { // two things: // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison // 2) This fixes the 1000 list limit that Oracle has (ORA-01795) if ($sub_val !== "''") { $in_clause[(int) $i++/1000][] = $sub_val; } else { $extra = true; } } if (!$extra && $i < 1000) { $out .= $val[0]; } else { $out .= ' ' . $val[1] . '('; $in_array = array(); // constuct each IN() clause foreach ($in_clause as $in_values) { $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')'; } // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway) $out .= implode(' OR ', $in_array); // handle the empty string case if ($extra) { $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL'; } $out .= ')'; unset($in_array, $in_clause); } } } return $out; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->last_query_text = $query; $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { $in_transaction = false; if (!$this->transaction) { $this->sql_transaction('begin'); } else { $in_transaction = true; } $array = array(); // We overcome Oracle's 4000 char limit by binding vars if (strlen($query) > 4000) { if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs)) { if (strlen($regs[3]) > 4000) { $cols = explode(', ', $regs[2]); preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); /* The code inside this comment block breaks clob handling, but does allow the database restore script to work. If you want to allow no posts longer than 4KB and/or need the db restore script, uncomment this. if (sizeof($cols) !== sizeof($vals)) { // Try to replace some common data we know is from our restore script or from other sources $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]); $_vals = explode(', ', $regs[3]); $vals = array(); $is_in_val = false; $i = 0; $string = ''; foreach ($_vals as $value) { if (strpos($value, "'") === false && !$is_in_val) { $vals[$i++] = $value; continue; } if (substr($value, -1) === "'") { $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value; $string = ''; $is_in_val = false; if ($vals[$i][0] !== "'") { $vals[$i] = "''" . $vals[$i]; } $i++; continue; } else { $string .= (($is_in_val) ? ', ' : '') . $value; $is_in_val = true; } } if ($string) { // New value if cols != value $vals[(sizeof($cols) !== sizeof($vals)) ? $i : $i - 1] .= $string; } $vals = array(0 => $vals); } */ $inserts = $vals[0]; unset($vals); foreach ($inserts as $key => $value) { if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 { $inserts[$key] = ':' . strtoupper($cols[$key]); $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1)); } } $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; } } else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) { if (strlen($data[0][2]) > 4000) { $update = $data[0][1]; $where = $data[0][3]; preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); unset($data); $cols = array(); foreach ($temp as $value) { if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2 { $cols[] = $value[1] . '=:' . strtoupper($value[1]); $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1)); } else { $cols[] = $value[1] . '=' . $value[2]; } } $query = $update . implode(', ', $cols) . ' ' . $where; unset($cols); } } } switch (substr($query, 0, 6)) { case 'DELETE': if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) { $query = $regs[1] . $this->_rewrite_where($regs[2]); unset($regs); } break; case 'UPDATE': if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) { $query = $regs[1] . $this->_rewrite_where($regs[2]); unset($regs); } break; case 'SELECT': $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); break; } $this->query_result = @ociparse($this->db_connect_id, $query); foreach ($array as $key => $value) { @ocibindbyname($this->query_result, $key, $array[$key], -1); } $success = @ociexecute($this->query_result, OCI_DEFAULT); if (!$success) { $this->sql_error($query); $this->query_result = false; } else { if (!$in_transaction) { $this->sql_transaction('commit'); } } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset; return $this->sql_query($query, $cache_ttl); } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->query_result) ? @ocirowcount($this->query_result) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } if ($query_id !== false) { $row = array(); $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); if (!$result || !$row) { return false; } $result_row = array(); foreach ($row as $key => $value) { // Oracle treats empty strings as null if (is_null($value)) { $value = ''; } // OCI->CLOB? if (is_object($value)) { $value = $value->load(); } $result_row[strtolower($key)] = $value; } return $result_row; } return false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } if ($query_id === false) { return false; } // Reset internal pointer @ociexecute($query_id, OCI_DEFAULT); // We do not fetch the row for rownum == 0 because then the next resultset would be the second row for ($i = 0; $i < $rownum; $i++) { if (!$this->sql_fetchrow($query_id)) { return false; } } return true; } /** * {@inheritDoc} */ function sql_nextid() { $query_id = $this->query_result; if ($query_id !== false && $this->last_query_text != '') { if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) { $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; $stmt = @ociparse($this->db_connect_id, $query); @ociexecute($stmt, OCI_DEFAULT); $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); @ocifreestatement($stmt); if ($temp_result) { return $temp_array['CURRVAL']; } else { return false; } } } return false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @ocifreestatement($query_id); } return false; } /** * {@inheritDoc} */ function sql_escape($msg) { return str_replace(array("'", "\0"), array("''", ''), $msg); } /** * Build LIKE expression * @access private */ function _sql_like_expression($expression) { return $expression . " ESCAPE '\\'"; } /** * Build NOT LIKE expression * @access private */ function _sql_not_like_expression($expression) { return $expression . " ESCAPE '\\'"; } function _sql_custom_build($stage, $data) { return $data; } function _sql_bit_and($column_name, $bit, $compare = '') { return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); } function _sql_bit_or($column_name, $bit, $compare = '') { return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); } /** * return sql error array * @access private */ function _sql_error() { if (function_exists('ocierror')) { $error = @ocierror(); $error = (!$error) ? @ocierror($this->query_result) : $error; $error = (!$error) ? @ocierror($this->db_connect_id) : $error; if ($error) { $this->last_error_result = $error; } else { $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); } } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Close sql connection * @access private */ function _sql_close() { return @ocilogoff($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': $html_table = false; // Grab a plan table, any will do $sql = "SELECT table_name FROM USER_TABLES WHERE table_name LIKE '%PLAN_TABLE%'"; $stmt = ociparse($this->db_connect_id, $sql); ociexecute($stmt); $result = array(); if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS)) { $table = $result['TABLE_NAME']; // This is the statement_id that will allow us to track the plan $statement_id = substr(md5($query), 0, 30); // Remove any stale plans $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); ociexecute($stmt2); ocifreestatement($stmt2); // Explain the plan $sql = "EXPLAIN PLAN SET STATEMENT_ID = '$statement_id' FOR $query"; $stmt2 = ociparse($this->db_connect_id, $sql); ociexecute($stmt2); ocifreestatement($stmt2); // Get the data from the plan $sql = "SELECT operation, options, object_name, object_type, cardinality, cost FROM plan_table START WITH id = 0 AND statement_id = '$statement_id' CONNECT BY PRIOR id = parent_id AND statement_id = '$statement_id'"; $stmt2 = ociparse($this->db_connect_id, $sql); ociexecute($stmt2); $row = array(); while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } ocifreestatement($stmt2); // Remove the plan we just made, we delete them on request anyway $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); ociexecute($stmt2); ocifreestatement($stmt2); } ocifreestatement($stmt); if ($html_table) { $this->html_hold .= '</table>'; } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @ociparse($this->db_connect_id, $query); $success = @ociexecute($result, OCI_DEFAULT); $row = array(); while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS)) { // Take the time spent on parsing rows into account } @ocifreestatement($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/mssql.php000077700000023457151514672100007733 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * MSSQL Database Abstraction Layer * Minimum Requirement is MSSQL 2000+ */ class mssql extends \phpbb\db\driver\driver { var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { if (!function_exists('mssql_connect')) { $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?'; return $this->sql_error(''); } $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); @ini_set('mssql.charset', 'UTF-8'); @ini_set('mssql.textlimit', 2147483647); @ini_set('mssql.textsize', 2147483647); $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mssql_connect($this->server, $this->user, $sqlpassword, $new_link); if ($this->db_connect_id && $this->dbname != '') { if (!@mssql_select_db($this->dbname, $this->db_connect_id)) { @mssql_close($this->db_connect_id); return false; } } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false) { $result_id = @mssql_query("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id); $row = false; if ($result_id) { $row = @mssql_fetch_assoc($result_id); @mssql_free_result($result_id); } $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; if (!empty($cache) && $use_cache) { $cache->put('mssql_version', $this->sql_server_version); } } if ($raw) { return $this->sql_server_version; } return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL'; } /** * {@inheritDoc} */ public function sql_concatenate($expr1, $expr2) { return $expr1 . ' + ' . $expr2; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id); break; case 'commit': return @mssql_query('COMMIT TRANSACTION', $this->db_connect_id); break; case 'rollback': return @mssql_query('ROLLBACK TRANSACTION', $this->db_connect_id); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) if ($total) { // We need to grab the total number of rows + the offset number of rows to get the correct result if (strpos($query, 'SELECT DISTINCT') === 0) { $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); } else { $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); } } $result = $this->sql_query($query, $cache_ttl); // Seek by $offset rows if ($offset) { $this->sql_rowseek($offset, $result); } return $result; } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } if ($query_id === false) { return false; } $row = @mssql_fetch_assoc($query_id); // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug if ($row) { foreach ($row as $key => $value) { $row[$key] = ($value === ' ' || $value === null) ? '' : $value; } } return $row; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false; } /** * {@inheritDoc} */ function sql_nextid() { $result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id); if ($result_id) { if ($row = @mssql_fetch_assoc($result_id)) { @mssql_free_result($result_id); return $row['computed']; } @mssql_free_result($result_id); } return false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @mssql_free_result($query_id); } return false; } /** * {@inheritDoc} */ function sql_escape($msg) { return str_replace(array("'", "\0"), array("''", ''), $msg); } /** * {@inheritDoc} */ function sql_lower_text($column_name) { return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; } /** * Build LIKE expression * @access private */ function _sql_like_expression($expression) { return $expression . " ESCAPE '\\'"; } /** * Build NOT LIKE expression * @access private */ function _sql_not_like_expression($expression) { return $expression . " ESCAPE '\\'"; } /** * return sql error array * @access private */ function _sql_error() { if (function_exists('mssql_get_last_message')) { $error = array( 'message' => @mssql_get_last_message(), 'code' => '', ); // Get error code number $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); if ($result_id) { $row = @mssql_fetch_assoc($result_id); $error['code'] = $row['code']; @mssql_free_result($result_id); } // Get full error message if possible $sql = 'SELECT CAST(description as varchar(255)) as message FROM master.dbo.sysmessages WHERE error = ' . $error['code']; $result_id = @mssql_query($sql); if ($result_id) { $row = @mssql_fetch_assoc($result_id); if (!empty($row['message'])) { $error['message'] .= '<br />' . $row['message']; } @mssql_free_result($result_id); } } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Build db-specific query data * @access private */ function _sql_custom_build($stage, $data) { return $data; } /** * Close sql connection * @access private */ function _sql_close() { return @mssql_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': $html_table = false; @mssql_query('SET SHOWPLAN_TEXT ON;', $this->db_connect_id); if ($result = @mssql_query($query, $this->db_connect_id)) { @mssql_next_result($result); while ($row = @mssql_fetch_row($result)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id); @mssql_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @mssql_query($query, $this->db_connect_id); while ($void = @mssql_fetch_assoc($result)) { // Take the time spent on parsing rows into account } @mssql_free_result($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/sqlite3.php000077700000021651151514672100010152 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * SQLite3 Database Abstraction Layer * Minimum Requirement: 3.6.15+ */ class sqlite3 extends \phpbb\db\driver\driver { /** * @var string Stores errors during connection setup in case the driver is not available */ protected $connect_error = ''; /** * @var \SQLite3 The SQLite3 database object to operate against */ protected $dbo = null; /** * {@inheritDoc} */ public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $this->persistency = false; $this->user = $sqluser; $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; if (!class_exists('SQLite3', false)) { $this->connect_error = 'SQLite3 not found, is the extension installed?'; return $this->sql_error(''); } try { $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); $this->db_connect_id = true; } catch (\Exception $e) { $this->connect_error = $e->getMessage(); return array('message' => $this->connect_error); } return true; } /** * {@inheritDoc} */ public function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false) { $version = \SQLite3::version(); $this->sql_server_version = $version['versionString']; if (!empty($cache) && $use_cache) { $cache->put('sqlite_version', $this->sql_server_version); } } return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version; } /** * SQL Transaction * * @param string $status Should be one of the following strings: * begin, commit, rollback * @return bool Success/failure of the transaction query */ protected function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return $this->dbo->exec('BEGIN IMMEDIATE'); break; case 'commit': return $this->dbo->exec('COMMIT'); break; case 'rollback': return $this->dbo->exec('ROLLBACK'); break; } return true; } /** * {@inheritDoc} */ public function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->last_query_text = $query; $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @$this->dbo->query($query)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query * * @param string $query The SQL query to execute * @param int $total The number of rows to select * @param int $offset * @param int $cache_ttl Either 0 to avoid caching or * the time in seconds which the result shall be kept in cache * @return mixed Buffered, seekable result handle, false on error */ protected function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // if $total is set to 0 we do not want to limit the number of rows if ($total == 0) { $total = -1; } $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); return $this->sql_query($query, $cache_ttl); } /** * {@inheritDoc} */ public function sql_affectedrows() { return ($this->db_connect_id) ? $this->dbo->changes() : false; } /** * {@inheritDoc} */ public function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } return is_object($query_id) ? $query_id->fetchArray(SQLITE3_ASSOC) : false; } /** * {@inheritDoc} */ public function sql_nextid() { return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false; } /** * {@inheritDoc} */ public function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if ($query_id) { return @$query_id->finalize(); } } /** * {@inheritDoc} */ public function sql_escape($msg) { return \SQLite3::escapeString($msg); } /** * {@inheritDoc} * * For SQLite an underscore is an unknown character. */ public function sql_like_expression($expression) { // Unlike LIKE, GLOB is unfortunately case sensitive. // We only catch * and ? here, not the character map possible on file globbing. $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); return 'GLOB \'' . $this->sql_escape($expression) . '\''; } /** * {@inheritDoc} * * For SQLite an underscore is an unknown character. */ public function sql_not_like_expression($expression) { // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive // We only catch * and ? here, not the character map possible on file globbing. $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); return 'NOT GLOB \'' . $this->sql_escape($expression) . '\''; } /** * return sql error array * * @return array */ protected function _sql_error() { if (class_exists('SQLite3', false) && isset($this->dbo)) { $error = array( 'message' => $this->dbo->lastErrorMsg(), 'code' => $this->dbo->lastErrorCode(), ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Build db-specific query data * * @param string $stage Available stages: FROM, WHERE * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses * * @return string The db-specific query fragment */ protected function _sql_custom_build($stage, $data) { return $data; } /** * Close sql connection * * @return bool False if failure */ protected function _sql_close() { return $this->dbo->close(); } /** * Build db-specific report * * @param string $mode Available modes: display, start, stop, * add_select_row, fromcache, record_fromcache * @param string $query The Query that should be explained * @return mixed Either a full HTML page, boolean or null */ protected function _sql_report($mode, $query = '') { switch ($mode) { case 'start': $explain_query = $query; if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } if (preg_match('/^SELECT/', $explain_query)) { $html_table = false; if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query")) { while ($row = $result->fetchArray(SQLITE3_ASSOC)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } if ($html_table) { $this->html_hold .= '</table>'; } } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = $this->dbo->query($query); while ($void = $result->fetchArray(SQLITE3_ASSOC)) { // Take the time spent on parsing rows into account } $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/mssql_base.php000077700000002303151514672100010710 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * MSSQL Database Base Abstraction Layer */ abstract class mssql_base extends \phpbb\db\driver\driver { /** * {@inheritDoc} */ public function sql_concatenate($expr1, $expr2) { return $expr1 . ' + ' . $expr2; } /** * {@inheritDoc} */ function sql_escape($msg) { return str_replace(array("'", "\0"), array("''", ''), $msg); } /** * {@inheritDoc} */ function sql_lower_text($column_name) { return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; } /** * Build LIKE expression * @access private */ function _sql_like_expression($expression) { return $expression . " ESCAPE '\\'"; } /** * Build NOT LIKE expression * @access private */ function _sql_not_like_expression($expression) { return $expression . " ESCAPE '\\'"; } /** * Build db-specific query data * @access private */ function _sql_custom_build($stage, $data) { return $data; } } driver/mssqlnative.php000077700000022671151514672100011137 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ /** * This is the MS SQL Server Native database abstraction layer. * PHP mssql native driver required. * @author Chris Pucci * */ namespace phpbb\db\driver; class mssqlnative extends \phpbb\db\driver\mssql_base { var $m_insert_id = null; var $last_query_text = ''; var $query_options = array(); var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { // Test for driver support, to avoid suppressed fatal error if (!function_exists('sqlsrv_connect')) { $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; return $this->sql_error(''); } //set up connection variables $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); //connect to database $this->db_connect_id = sqlsrv_connect($this->server, array( 'Database' => $this->dbname, 'UID' => $this->user, 'PWD' => $sqlpassword )); return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false) { $arr_server_info = sqlsrv_server_info($this->db_connect_id); $this->sql_server_version = $arr_server_info['SQLServerVersion']; if (!empty($cache) && $use_cache) { $cache->put('mssql_version', $this->sql_server_version); } } if ($raw) { return $this->sql_server_version; } return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL'; } /** * {@inheritDoc} */ function sql_buffer_nested_transactions() { return true; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return sqlsrv_begin_transaction($this->db_connect_id); break; case 'commit': return sqlsrv_commit($this->db_connect_id); break; case 'rollback': return sqlsrv_rollback($this->db_connect_id); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->last_query_text = $query; $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) { $this->sql_error($query); } // reset options for next query $this->query_options = array(); if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // total == 0 means all results - not zero results if ($offset == 0 && $total !== 0) { if (strpos($query, "SELECT") === false) { $query = "TOP {$total} " . $query; } else { $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query); } } else if ($offset > 0) { $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query); $query = 'SELECT * FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3'; if ($total > 0) { $query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total); } else { $query .= ' WHERE line3 > ' . $offset; } } $result = $this->sql_query($query, $cache_ttl); return $result; } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->db_connect_id) ? @sqlsrv_rows_affected($this->query_result) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } if ($query_id === false) { return false; } $row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); if ($row) { foreach ($row as $key => $value) { $row[$key] = ($value === ' ' || $value === null) ? '' : $value; } // remove helper values from LIMIT queries if (isset($row['line2'])) { unset($row['line2'], $row['line3']); } } return (sizeof($row)) ? $row : false; } /** * {@inheritDoc} */ function sql_nextid() { $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); if ($result_id !== false) { $row = @sqlsrv_fetch_array($result_id); $id = $row[0]; @sqlsrv_free_stmt($result_id); return $id; } else { return false; } } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @sqlsrv_free_stmt($query_id); } return false; } /** * return sql error array * @access private */ function _sql_error() { if (function_exists('sqlsrv_errors')) { $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); $error_message = ''; $code = 0; if ($errors != null) { foreach ($errors as $error) { $error_message .= "SQLSTATE: " . $error['SQLSTATE'] . "\n"; $error_message .= "code: " . $error['code'] . "\n"; $code = $error['code']; $error_message .= "message: " . $error['message'] . "\n"; } $this->last_error_result = $error_message; $error = $this->last_error_result; } else { $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); } $error = array( 'message' => $error, 'code' => $code, ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Close sql connection * @access private */ function _sql_close() { return @sqlsrv_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': $html_table = false; @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;'); if ($result = @sqlsrv_query($this->db_connect_id, $query)) { @sqlsrv_next_result($result); while ($row = @sqlsrv_fetch_array($result)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); @sqlsrv_free_stmt($result); if ($html_table) { $this->html_hold .= '</table>'; } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @sqlsrv_query($this->db_connect_id, $query); while ($void = @sqlsrv_fetch_array($result)) { // Take the time spent on parsing rows into account } @sqlsrv_free_stmt($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } /** * Utility method used to retrieve number of rows * Emulates mysql_num_rows * Used in acp_database.php -> write_data_mssqlnative() * Requires a static or keyset cursor to be definde via * mssqlnative_set_query_options() */ function mssqlnative_num_rows($res) { if ($res !== false) { return sqlsrv_num_rows($res); } else { return false; } } /** * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. */ function mssqlnative_set_query_options($options) { $this->query_options = $options; } } driver/postgres.php000077700000023652151514672100010437 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * PostgreSQL Database Abstraction Layer * Minimum Requirement is Version 8.3+ */ class postgres extends \phpbb\db\driver\driver { var $multi_insert = true; var $last_query_text = ''; var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $connect_string = ''; if ($sqluser) { $connect_string .= "user=$sqluser "; } if ($sqlpassword) { $connect_string .= "password=$sqlpassword "; } if ($sqlserver) { // $sqlserver can carry a port separated by : for compatibility reasons // If $sqlserver has more than one : it's probably an IPv6 address. // In this case we only allow passing a port via the $port variable. if (substr_count($sqlserver, ':') === 1) { list($sqlserver, $port) = explode(':', $sqlserver); } if ($sqlserver !== 'localhost') { $connect_string .= "host=$sqlserver "; } if ($port) { $connect_string .= "port=$port "; } } $schema = ''; if ($database) { $this->dbname = $database; if (strpos($database, '.') !== false) { list($database, $schema) = explode('.', $database); } $connect_string .= "dbname=$database"; } $this->persistency = $persistency; if ($this->persistency) { if (!function_exists('pg_pconnect')) { $this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?'; return $this->sql_error(''); } $collector = new \phpbb\error_collector; $collector->install(); $this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW); } else { if (!function_exists('pg_connect')) { $this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?'; return $this->sql_error(''); } $collector = new \phpbb\error_collector; $collector->install(); $this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW); } $collector->uninstall(); if ($this->db_connect_id) { if ($schema !== '') { @pg_query($this->db_connect_id, 'SET search_path TO ' . $schema); } return $this->db_connect_id; } $this->connect_error = $collector->format_errors(); return $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false) { $query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version'); $row = @pg_fetch_assoc($query_id, null); @pg_free_result($query_id); $this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0; if (!empty($cache) && $use_cache) { $cache->put('pgsql_version', $this->sql_server_version); } } return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @pg_query($this->db_connect_id, 'BEGIN'); break; case 'commit': return @pg_query($this->db_connect_id, 'COMMIT'); break; case 'rollback': return @pg_query($this->db_connect_id, 'ROLLBACK'); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->last_query_text = $query; $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @pg_query($this->db_connect_id, $query)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build db-specific query data * @access private */ function _sql_custom_build($stage, $data) { return $data; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // if $total is set to 0 we do not want to limit the number of rows if ($total == 0) { $total = 'ALL'; } $query .= "\n LIMIT $total OFFSET $offset"; return $this->sql_query($query, $cache_ttl); } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->query_result) ? @pg_affected_rows($this->query_result) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false; } /** * {@inheritDoc} */ function sql_nextid() { $query_id = $this->query_result; if ($query_id !== false && $this->last_query_text != '') { if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) { $query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value"; $temp_q_id = @pg_query($this->db_connect_id, $query); if (!$temp_q_id) { return false; } $temp_result = @pg_fetch_assoc($temp_q_id, null); @pg_free_result($query_id); return ($temp_result) ? $temp_result['last_value'] : false; } } return false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @pg_free_result($query_id); } return false; } /** * {@inheritDoc} */ function sql_escape($msg) { return @pg_escape_string($msg); } /** * Build LIKE expression * @access private */ function _sql_like_expression($expression) { return $expression; } /** * Build NOT LIKE expression * @access private */ function _sql_not_like_expression($expression) { return $expression; } /** * {@inheritDoc} */ function cast_expr_to_bigint($expression) { return 'CAST(' . $expression . ' as DECIMAL(255, 0))'; } /** * {@inheritDoc} */ function cast_expr_to_string($expression) { return 'CAST(' . $expression . ' as VARCHAR(255))'; } /** * return sql error array * @access private */ function _sql_error() { // pg_last_error only works when there is an established connection. // Connection errors have to be tracked by us manually. if ($this->db_connect_id) { $message = @pg_last_error($this->db_connect_id); } else { $message = $this->connect_error; } return array( 'message' => $message, 'code' => '' ); } /** * Close sql connection * @access private */ function _sql_close() { return @pg_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': $explain_query = $query; if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } if (preg_match('/^SELECT/', $explain_query)) { $html_table = false; if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query")) { while ($row = @pg_fetch_assoc($result, null)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @pg_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @pg_query($this->db_connect_id, $query); while ($void = @pg_fetch_assoc($result, null)) { // Take the time spent on parsing rows into account } @pg_free_result($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/driver.php000077700000057637151514672100010076 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * Database Abstraction Layer */ abstract class driver implements driver_interface { var $db_connect_id; var $query_result; var $return_on_error = false; var $transaction = false; var $sql_time = 0; var $num_queries = array(); var $open_queries = array(); var $curtime = 0; var $query_hold = ''; var $html_hold = ''; var $sql_report = ''; var $persistency = false; var $user = ''; var $server = ''; var $dbname = ''; // Set to true if error triggered var $sql_error_triggered = false; // Holding the last sql query on sql error var $sql_error_sql = ''; // Holding the error information - only populated if sql_error_triggered is set var $sql_error_returned = array(); // Holding transaction count var $transactions = 0; // Supports multi inserts? var $multi_insert = false; /** * Current sql layer */ var $sql_layer = ''; /** * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions */ var $any_char; var $one_char; /** * Exact version of the DBAL, directly queried */ var $sql_server_version = false; /** * Constructor */ function __construct() { $this->num_queries = array( 'cached' => 0, 'normal' => 0, 'total' => 0, ); // Fill default sql layer based on the class being called. // This can be changed by the specified layer itself later if needed. $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\')); // Do not change this please! This variable is used to easy the use of it - and is hardcoded. $this->any_char = chr(0) . '%'; $this->one_char = chr(0) . '_'; } /** * {@inheritdoc} */ public function get_sql_layer() { return $this->sql_layer; } /** * {@inheritdoc} */ public function get_db_name() { return $this->dbname; } /** * {@inheritdoc} */ public function get_any_char() { return $this->any_char; } /** * {@inheritdoc} */ public function get_one_char() { return $this->one_char; } /** * {@inheritdoc} */ public function get_db_connect_id() { return $this->db_connect_id; } /** * {@inheritdoc} */ public function get_sql_error_triggered() { return $this->sql_error_triggered; } /** * {@inheritdoc} */ public function get_sql_error_sql() { return $this->sql_error_sql; } /** * {@inheritdoc} */ public function get_transaction() { return $this->transaction; } /** * {@inheritdoc} */ public function get_sql_time() { return $this->sql_time; } /** * {@inheritdoc} */ public function get_sql_error_returned() { return $this->sql_error_returned; } /** * {@inheritdoc} */ public function get_multi_insert() { return $this->multi_insert; } /** * {@inheritdoc} */ public function set_multi_insert($multi_insert) { $this->multi_insert = $multi_insert; } /** * {@inheritDoc} */ function sql_return_on_error($fail = false) { $this->sql_error_triggered = false; $this->sql_error_sql = ''; $this->return_on_error = $fail; } /** * {@inheritDoc} */ function sql_num_queries($cached = false) { return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; } /** * {@inheritDoc} */ function sql_add_num_queries($cached = false) { $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; $this->num_queries['total'] += 1; } /** * {@inheritDoc} */ function sql_close() { if (!$this->db_connect_id) { return false; } if ($this->transaction) { do { $this->sql_transaction('commit'); } while ($this->transaction); } foreach ($this->open_queries as $query_id) { $this->sql_freeresult($query_id); } // Connection closed correctly. Set db_connect_id to false to prevent errors if ($result = $this->_sql_close()) { $this->db_connect_id = false; } return $result; } /** * {@inheritDoc} */ function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { if (empty($query)) { return false; } // Never use a negative total or offset $total = ($total < 0) ? 0 : $total; $offset = ($offset < 0) ? 0 : $offset; return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); } /** * {@inheritDoc} */ function sql_fetchrowset($query_id = false) { if ($query_id === false) { $query_id = $this->query_result; } if ($query_id !== false) { $result = array(); while ($row = $this->sql_fetchrow($query_id)) { $result[] = $row; } return $result; } return false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } if ($query_id === false) { return false; } $this->sql_freeresult($query_id); $query_id = $this->sql_query($this->last_query_text); if ($query_id === false) { return false; } // We do not fetch the row for rownum == 0 because then the next resultset would be the second row for ($i = 0; $i < $rownum; $i++) { if (!$this->sql_fetchrow($query_id)) { return false; } } return true; } /** * {@inheritDoc} */ function sql_fetchfield($field, $rownum = false, $query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($query_id !== false) { if ($rownum !== false) { $this->sql_rowseek($rownum, $query_id); } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_fetchfield($query_id, $field); } $row = $this->sql_fetchrow($query_id); return (isset($row[$field])) ? $row[$field] : false; } return false; } /** * {@inheritDoc} */ function sql_like_expression($expression) { $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); } /** * {@inheritDoc} */ function sql_not_like_expression($expression) { $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\''); } /** * {@inheritDoc} */ public function sql_case($condition, $action_true, $action_false = false) { $sql_case = 'CASE WHEN ' . $condition; $sql_case .= ' THEN ' . $action_true; $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; $sql_case .= ' END'; return $sql_case; } /** * {@inheritDoc} */ public function sql_concatenate($expr1, $expr2) { return $expr1 . ' || ' . $expr2; } /** * {@inheritDoc} */ function sql_buffer_nested_transactions() { return false; } /** * {@inheritDoc} */ function sql_transaction($status = 'begin') { switch ($status) { case 'begin': // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit) if ($this->transaction) { $this->transactions++; return true; } $result = $this->_sql_transaction('begin'); if (!$result) { $this->sql_error(); } $this->transaction = true; break; case 'commit': // If there was a previously opened transaction we do not commit yet... // but count back the number of inner transactions if ($this->transaction && $this->transactions) { $this->transactions--; return true; } // Check if there is a transaction (no transaction can happen if // there was an error, with a combined rollback and error returning enabled) // This implies we have transaction always set for autocommit db's if (!$this->transaction) { return false; } $result = $this->_sql_transaction('commit'); if (!$result) { $this->sql_error(); } $this->transaction = false; $this->transactions = 0; break; case 'rollback': $result = $this->_sql_transaction('rollback'); $this->transaction = false; $this->transactions = 0; break; default: $result = $this->_sql_transaction($status); break; } return $result; } /** * {@inheritDoc} */ function sql_build_array($query, $assoc_ary = false) { if (!is_array($assoc_ary)) { return false; } $fields = $values = array(); if ($query == 'INSERT' || $query == 'INSERT_SELECT') { foreach ($assoc_ary as $key => $var) { $fields[] = $key; if (is_array($var) && is_string($var[0])) { // This is used for INSERT_SELECT(s) $values[] = $var[0]; } else { $values[] = $this->_sql_validate_value($var); } } $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; } else if ($query == 'MULTI_INSERT') { trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); } else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE') { $values = array(); foreach ($assoc_ary as $key => $var) { $values[] = "$key = " . $this->_sql_validate_value($var); } $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); } return $query; } /** * {@inheritDoc} */ function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) { if (!sizeof($array)) { if (!$allow_empty_set) { // Print the backtrace to help identifying the location of the problematic code $this->sql_error('No values specified for SQL IN comparison'); } else { // NOT IN () actually means everything so use a tautology if ($negate) { return '1=1'; } // IN () actually means nothing so use a contradiction else { return '1=0'; } } } if (!is_array($array)) { $array = array($array); } if (sizeof($array) == 1) { @reset($array); $var = current($array); return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); } else { return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; } } /** * {@inheritDoc} */ function sql_bit_and($column_name, $bit, $compare = '') { if (method_exists($this, '_sql_bit_and')) { return $this->_sql_bit_and($column_name, $bit, $compare); } return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); } /** * {@inheritDoc} */ function sql_bit_or($column_name, $bit, $compare = '') { if (method_exists($this, '_sql_bit_or')) { return $this->_sql_bit_or($column_name, $bit, $compare); } return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); } /** * {@inheritDoc} */ function cast_expr_to_bigint($expression) { return $expression; } /** * {@inheritDoc} */ function cast_expr_to_string($expression) { return $expression; } /** * {@inheritDoc} */ function sql_lower_text($column_name) { return "LOWER($column_name)"; } /** * {@inheritDoc} */ function sql_multi_insert($table, $sql_ary) { if (!sizeof($sql_ary)) { return false; } if ($this->multi_insert) { $ary = array(); foreach ($sql_ary as $id => $_sql_ary) { // If by accident the sql array is only one-dimensional we build a normal insert statement if (!is_array($_sql_ary)) { return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); } $values = array(); foreach ($_sql_ary as $key => $var) { $values[] = $this->_sql_validate_value($var); } $ary[] = '(' . implode(', ', $values) . ')'; } return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); } else { foreach ($sql_ary as $ary) { if (!is_array($ary)) { return false; } $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); if (!$result) { return false; } } } return true; } /** * Function for validating values * @access private */ function _sql_validate_value($var) { if (is_null($var)) { return 'NULL'; } else if (is_string($var)) { return "'" . $this->sql_escape($var) . "'"; } else { return (is_bool($var)) ? intval($var) : $var; } } /** * {@inheritDoc} */ function sql_build_query($query, $array) { $sql = ''; switch ($query) { case 'SELECT': case 'SELECT_DISTINCT'; $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; // Build table array. We also build an alias array for later checks. $table_array = $aliases = array(); $used_multi_alias = false; foreach ($array['FROM'] as $table_name => $alias) { if (is_array($alias)) { $used_multi_alias = true; foreach ($alias as $multi_alias) { $table_array[] = $table_name . ' ' . $multi_alias; $aliases[] = $multi_alias; } } else { $table_array[] = $table_name . ' ' . $alias; $aliases[] = $alias; } } // We run the following code to determine if we need to re-order the table array. ;) // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) { // Take first LEFT JOIN $join = current($array['LEFT_JOIN']); // Determine the table used there (even if there are more than one used, we only want to have one preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); // If there is a first join match, we need to make sure the table order is correct if (!empty($matches[1])) { $first_join_match = trim($matches[1]); $table_array = $last = array(); foreach ($array['FROM'] as $table_name => $alias) { if (is_array($alias)) { foreach ($alias as $multi_alias) { ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; } } else { ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; } } $table_array = array_merge($table_array, $last); } } $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); if (!empty($array['LEFT_JOIN'])) { foreach ($array['LEFT_JOIN'] as $join) { $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; } } if (!empty($array['WHERE'])) { $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); } if (!empty($array['GROUP_BY'])) { $sql .= ' GROUP BY ' . $array['GROUP_BY']; } if (!empty($array['ORDER_BY'])) { $sql .= ' ORDER BY ' . $array['ORDER_BY']; } break; } return $sql; } /** * {@inheritDoc} */ function sql_error($sql = '') { global $auth, $user, $config; // Set var to retrieve errored status $this->sql_error_triggered = true; $this->sql_error_sql = $sql; $this->sql_error_returned = $this->_sql_error(); if (!$this->return_on_error) { $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; // Show complete SQL error and path to administrators only // Additionally show complete error on installation or if extended debug mode is enabled // The DEBUG constant is for development only! if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) { $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : ''; } else { // If error occurs in initiating the session we need to use a pre-defined language string // This could happen if the connection could not be established for example (then we are not able to grab the default language) if (!isset($user->lang['SQL_ERROR_OCCURRED'])) { $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; } else { if (!empty($config['board_contact'])) { $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); } else { $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); } } } if ($this->transaction) { $this->sql_transaction('rollback'); } if (strlen($message) > 1024) { // We need to define $msg_long_text here to circumvent text stripping. global $msg_long_text; $msg_long_text = $message; trigger_error(false, E_USER_ERROR); } trigger_error($message, E_USER_ERROR); } if ($this->transaction) { $this->sql_transaction('rollback'); } return $this->sql_error_returned; } /** * {@inheritDoc} */ function sql_report($mode, $query = '') { global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper, $user; global $request; if (is_object($request) && !$request->variable('explain', false)) { return false; } if (!$query && $this->query_hold != '') { $query = $this->query_hold; } switch ($mode) { case 'display': if (!empty($cache)) { $cache->unload(); } $this->sql_close(); $mtime = explode(' ', microtime()); $totaltime = $mtime[0] + $mtime[1] - $starttime; echo '<!DOCTYPE html> <html dir="ltr"> <head> <meta charset="utf-8"> <title>SQL Report</title> <link href="' . htmlspecialchars($phpbb_path_helper->update_web_root_path($phpbb_root_path) . $phpbb_path_helper->get_adm_relative_path()) . 'style/admin.css" rel="stylesheet" type="text/css" media="screen" /> </head> <body id="errorpage"> <div id="wrap"> <div id="page-header"> <a href="' . build_url('explain') . '">Return to previous page</a> </div> <div id="page-body"> <div id="acp"> <div class="panel"> <span class="corners-top"><span></span></span> <div id="content"> <h1>SQL Report</h1> <br /> <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p> <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p> <br /><br /> ' . $this->sql_report . ' </div> <span class="corners-bottom"><span></span></span> </div> </div> </div> <div id="page-footer"> Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited </div> </div> </body> </html>'; exit_handler(); break; case 'stop': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $this->sql_report .= ' <table cellspacing="1"> <thead> <tr> <th>Query #' . $this->num_queries['total'] . '</th> </tr> </thead> <tbody> <tr> <td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td> </tr> </tbody> </table> ' . $this->html_hold . ' <p style="text-align: center;"> '; if ($this->query_result) { if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) { $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | '; } $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>'; } else { $error = $this->sql_error(); $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); } $this->sql_report .= '</p><br /><br />'; $this->sql_time += $endtime - $this->curtime; break; case 'start': $this->query_hold = $query; $this->html_hold = ''; $this->_sql_report($mode, $query); $this->curtime = explode(' ', microtime()); $this->curtime = $this->curtime[0] + $this->curtime[1]; break; case 'add_select_row': $html_table = func_get_arg(2); $row = func_get_arg(3); if (!$html_table && sizeof($row)) { $html_table = true; $this->html_hold .= '<table cellspacing="1"><tr>'; foreach (array_keys($row) as $val) { $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; } $this->html_hold .= '</tr>'; } $this->html_hold .= '<tr>'; $class = 'row1'; foreach (array_values($row) as $val) { $class = ($class == 'row1') ? 'row2' : 'row1'; $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; } $this->html_hold .= '</tr>'; return $html_table; break; case 'fromcache': $this->_sql_report($mode, $query); break; case 'record_fromcache': $endtime = func_get_arg(2); $splittime = func_get_arg(3); $time_cache = $endtime - $this->curtime; $time_db = $splittime - $endtime; $color = ($time_db > $time_cache) ? 'green' : 'red'; $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>'; $this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>'; $this->sql_report .= '<p style="text-align: center;">'; $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />'; // Pad the start time to not interfere with page timing $starttime += $time_db; break; default: $this->_sql_report($mode, $query); break; } return true; } /** * {@inheritDoc} */ function get_estimated_row_count($table_name) { return $this->get_row_count($table_name); } /** * {@inheritDoc} */ function get_row_count($table_name) { $sql = 'SELECT COUNT(*) AS rows_total FROM ' . $this->sql_escape($table_name); $result = $this->sql_query($sql); $rows_total = $this->sql_fetchfield('rows_total'); $this->sql_freeresult($result); return $rows_total; } } driver/mysql.php000077700000025203151514672100007730 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * MySQL4 Database Abstraction Layer * Compatible with: * MySQL 3.23+ * MySQL 4.0+ * MySQL 4.1+ * MySQL 5.0+ */ class mysql extends \phpbb\db\driver\mysql_base { var $multi_insert = true; var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $this->persistency = $persistency; $this->user = $sqluser; $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; $this->sql_layer = 'mysql4'; if ($this->persistency) { if (!function_exists('mysql_pconnect')) { $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); } else { if (!function_exists('mysql_connect')) { $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); } if ($this->db_connect_id && $this->dbname != '') { if (@mysql_select_db($this->dbname, $this->db_connect_id)) { // Determine what version we are using and if it natively supports UNICODE if (version_compare($this->sql_server_info(true), '4.1.0', '>=')) { @mysql_query("SET NAMES 'utf8'", $this->db_connect_id); // enforce strict mode on databases that support it if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) { $result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id); $row = @mysql_fetch_assoc($result); @mysql_free_result($result); $modes = array_map('trim', explode(',', $row['sql_mode'])); // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES if (!in_array('TRADITIONAL', $modes)) { if (!in_array('STRICT_ALL_TABLES', $modes)) { $modes[] = 'STRICT_ALL_TABLES'; } if (!in_array('STRICT_TRANS_TABLES', $modes)) { $modes[] = 'STRICT_TRANS_TABLES'; } } $mode = implode(',', $modes); @mysql_query("SET SESSION sql_mode='{$mode}'", $this->db_connect_id); } } else if (version_compare($this->sql_server_info(true), '4.0.0', '<')) { $this->sql_layer = 'mysql'; } return $this->db_connect_id; } } return $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false) { $result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id); $row = @mysql_fetch_assoc($result); @mysql_free_result($result); $this->sql_server_version = $row['version']; if (!empty($cache) && $use_cache) { $cache->put('mysql_version', $this->sql_server_version); } } return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @mysql_query('BEGIN', $this->db_connect_id); break; case 'commit': return @mysql_query('COMMIT', $this->db_connect_id); break; case 'rollback': return @mysql_query('ROLLBACK', $this->db_connect_id); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * {@inheritDoc} */ function sql_affectedrows() { if ($this->db_connect_id) { // We always want the number of matched rows // instead of changed rows, when running an update. // So when mysql_info() returns the number of matched rows // we return that one instead of mysql_affected_rows() $mysql_info = @mysql_info($this->db_connect_id); if ($mysql_info !== false) { $match = array(); preg_match('#^Rows matched: (\d)+ Changed: (\d)+ Warnings: (\d)+$#', $mysql_info, $match); if (isset($match[1])) { return $match[1]; } } return @mysql_affected_rows($this->db_connect_id); } return false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false; } /** * {@inheritDoc} */ function sql_nextid() { return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @mysql_free_result($query_id); } return false; } /** * {@inheritDoc} */ function sql_escape($msg) { if (!$this->db_connect_id) { return @mysql_real_escape_string($msg); } return @mysql_real_escape_string($msg, $this->db_connect_id); } /** * return sql error array * @access private */ function _sql_error() { if ($this->db_connect_id) { $error = array( 'message' => @mysql_error($this->db_connect_id), 'code' => @mysql_errno($this->db_connect_id), ); } else if (function_exists('mysql_error')) { $error = array( 'message' => @mysql_error(), 'code' => @mysql_errno(), ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Close sql connection * @access private */ function _sql_close() { return @mysql_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { static $test_prof; // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING if ($test_prof === null) { $test_prof = false; if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<')) { $test_prof = true; } } switch ($mode) { case 'start': $explain_query = $query; if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } if (preg_match('/^SELECT/', $explain_query)) { $html_table = false; // begin profiling if ($test_prof) { @mysql_query('SET profiling = 1;', $this->db_connect_id); } if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) { while ($row = @mysql_fetch_assoc($result)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @mysql_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } if ($test_prof) { $html_table = false; // get the last profile if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id)) { $this->html_hold .= '<br />'; while ($row = @mysql_fetch_assoc($result)) { // make <unknown> HTML safe if (!empty($row['Source_function'])) { $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); } // remove unsupported features foreach ($row as $key => $val) { if ($val === null) { unset($row[$key]); } } $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @mysql_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } @mysql_query('SET profiling = 0;', $this->db_connect_id); } } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @mysql_query($query, $this->db_connect_id); while ($void = @mysql_fetch_assoc($result)) { // Take the time spent on parsing rows into account } @mysql_free_result($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/sqlite.php000077700000020265151514672100010067 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * Sqlite Database Abstraction Layer * Minimum Requirement: 2.8.2+ */ class sqlite extends \phpbb\db\driver\driver { var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $this->persistency = $persistency; $this->user = $sqluser; $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; $error = ''; if ($this->persistency) { if (!function_exists('sqlite_popen')) { $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @sqlite_popen($this->server, 0666, $error); } else { if (!function_exists('sqlite_open')) { $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @sqlite_open($this->server, 0666, $error); } if ($this->db_connect_id) { @sqlite_query('PRAGMA short_column_names = 1', $this->db_connect_id); // @sqlite_query('PRAGMA encoding = "UTF-8"', $this->db_connect_id); } return ($this->db_connect_id) ? true : array('message' => $error); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false) { $result = @sqlite_query('SELECT sqlite_version() AS version', $this->db_connect_id); $row = @sqlite_fetch_array($result, SQLITE_ASSOC); $this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0; if (!empty($cache) && $use_cache) { $cache->put('sqlite_version', $this->sql_server_version); } } return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @sqlite_query('BEGIN', $this->db_connect_id); break; case 'commit': return @sqlite_query('COMMIT', $this->db_connect_id); break; case 'rollback': return @sqlite_query('ROLLBACK', $this->db_connect_id); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @sqlite_query($query, $this->db_connect_id)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // if $total is set to 0 we do not want to limit the number of rows if ($total == 0) { $total = -1; } $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); return $this->sql_query($query, $cache_ttl); } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->db_connect_id) ? @sqlite_changes($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false; } /** * {@inheritDoc} */ function sql_nextid() { return ($this->db_connect_id) ? @sqlite_last_insert_rowid($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } return true; } /** * {@inheritDoc} */ function sql_escape($msg) { return @sqlite_escape_string($msg); } /** * {@inheritDoc} * * For SQLite an underscore is a not-known character... this may change with SQLite3 */ function sql_like_expression($expression) { // Unlike LIKE, GLOB is unfortunately case sensitive. // We only catch * and ? here, not the character map possible on file globbing. $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); return 'GLOB \'' . $this->sql_escape($expression) . '\''; } /** * {@inheritDoc} * * For SQLite an underscore is a not-known character... */ function sql_not_like_expression($expression) { // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive. // We only catch * and ? here, not the character map possible on file globbing. $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); return 'NOT GLOB \'' . $this->sql_escape($expression) . '\''; } /** * return sql error array * @access private */ function _sql_error() { if (function_exists('sqlite_error_string')) { $error = array( 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), 'code' => @sqlite_last_error($this->db_connect_id), ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Build db-specific query data * @access private */ function _sql_custom_build($stage, $data) { return $data; } /** * Close sql connection * @access private */ function _sql_close() { return @sqlite_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @sqlite_query($query, $this->db_connect_id); while ($void = @sqlite_fetch_array($result, SQLITE_ASSOC)) { // Take the time spent on parsing rows into account } $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/mssql_odbc.php000077700000020175151514672100010714 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * Unified ODBC functions * Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere... * Here we only support MSSQL Server 2000+ because of the provided schema * * @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting. * If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example. * @note odbc.defaultbinmode may affect UTF8 characters */ class mssql_odbc extends \phpbb\db\driver\mssql_base { var $last_query_text = ''; var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); $max_size = @ini_get('odbc.defaultlrl'); if (!empty($max_size)) { $unit = strtolower(substr($max_size, -1, 1)); $max_size = (int) $max_size; if ($unit == 'k') { $max_size = floor($max_size / 1024); } else if ($unit == 'g') { $max_size *= 1024; } else if (is_numeric($unit)) { $max_size = floor((int) ($max_size . $unit) / 1048576); } $max_size = max(8, $max_size) . 'M'; @ini_set('odbc.defaultlrl', $max_size); } if ($this->persistency) { if (!function_exists('odbc_pconnect')) { $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); } else { if (!function_exists('odbc_connect')) { $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; return $this->sql_error(''); } $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssqlodbc_version')) === false) { $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')"); $row = false; if ($result_id) { $row = @odbc_fetch_array($result_id); @odbc_free_result($result_id); } $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; if (!empty($cache) && $use_cache) { $cache->put('mssqlodbc_version', $this->sql_server_version); } } if ($raw) { return $this->sql_server_version; } return ($this->sql_server_version) ? 'MSSQL (ODBC)<br />' . $this->sql_server_version : 'MSSQL (ODBC)'; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION'); break; case 'commit': return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION'); break; case 'rollback': return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION'); break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->last_query_text = $query; $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->open_queries[(int) $this->query_result] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { $this->open_queries[(int) $this->query_result] = $this->query_result; } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) if ($total) { // We need to grab the total number of rows + the offset number of rows to get the correct result if (strpos($query, 'SELECT DISTINCT') === 0) { $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); } else { $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); } } $result = $this->sql_query($query, $cache_ttl); // Seek by $offset rows if ($offset) { $this->sql_rowseek($offset, $result); } return $result; } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->db_connect_id) ? @odbc_num_rows($this->query_result) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } return ($query_id !== false) ? @odbc_fetch_array($query_id) : false; } /** * {@inheritDoc} */ function sql_nextid() { $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY'); if ($result_id) { if (@odbc_fetch_array($result_id)) { $id = @odbc_result($result_id, 1); @odbc_free_result($result_id); return $id; } @odbc_free_result($result_id); } return false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } if (isset($this->open_queries[(int) $query_id])) { unset($this->open_queries[(int) $query_id]); return @odbc_free_result($query_id); } return false; } /** * return sql error array * @access private */ function _sql_error() { if (function_exists('odbc_errormsg')) { $error = array( 'message' => @odbc_errormsg(), 'code' => @odbc_error(), ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Close sql connection * @access private */ function _sql_close() { return @odbc_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { switch ($mode) { case 'start': break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @odbc_exec($this->db_connect_id, $query); while ($void = @odbc_fetch_array($result)) { // Take the time spent on parsing rows into account } @odbc_free_result($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/driver_interface.php000077700000032122151514672100012074 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; interface driver_interface { /** * Gets the name of the sql layer. * * @return string */ public function get_sql_layer(); /** * Gets the name of the database. * * @return string */ public function get_db_name(); /** * Wildcards for matching any (%) character within LIKE expressions * * @return string */ public function get_any_char(); /** * Wildcards for matching exactly one (_) character within LIKE expressions * * @return string */ public function get_one_char(); /** * Gets the time spent into the queries * * @return int */ public function get_sql_time(); /** * Gets the connect ID. * * @return mixed */ public function get_db_connect_id(); /** * Indicates if an error was triggered. * * @return bool */ public function get_sql_error_triggered(); /** * Gets the last faulty query * * @return string */ public function get_sql_error_sql(); /** * Indicates if we are in a transaction. * * @return bool */ public function get_transaction(); /** * Gets the returned error. * * @return array */ public function get_sql_error_returned(); /** * Indicates if multiple insertion can be used * * @return bool */ public function get_multi_insert(); /** * Set if multiple insertion can be used * * @param bool $multi_insert */ public function set_multi_insert($multi_insert); /** * Gets the exact number of rows in a specified table. * * @param string $table_name Table name * @return string Exact number of rows in $table_name. */ public function get_row_count($table_name); /** * Gets the estimated number of rows in a specified table. * * @param string $table_name Table name * @return string Number of rows in $table_name. * Prefixed with ~ if estimated (otherwise exact). */ public function get_estimated_row_count($table_name); /** * Run LOWER() on DB column of type text (i.e. neither varchar nor char). * * @param string $column_name The column name to use * @return string A SQL statement like "LOWER($column_name)" */ public function sql_lower_text($column_name); /** * Display sql error page * * @param string $sql The SQL query causing the error * @return mixed Returns the full error message, if $this->return_on_error * is set, null otherwise */ public function sql_error($sql = ''); /** * Returns whether results of a query need to be buffered to run a * transaction while iterating over them. * * @return bool Whether buffering is required. */ public function sql_buffer_nested_transactions(); /** * Run binary OR operator on DB column. * * @param string $column_name The column name to use * @param int $bit The value to use for the OR operator, * will be converted to (1 << $bit). Is used by options, * using the number schema... 0, 1, 2...29 * @param string $compare Any custom SQL code after the check (e.g. "= 0") * @return string A SQL statement like "$column | (1 << $bit) {$compare}" */ public function sql_bit_or($column_name, $bit, $compare = ''); /** * Version information about used database * * @param bool $raw Only return the fetched sql_server_version * @param bool $use_cache Is it safe to retrieve the value from the cache * @return string sql server version */ public function sql_server_info($raw = false, $use_cache = true); /** * Return on error or display error message * * @param bool $fail Should we return on errors, or stop * @return null */ public function sql_return_on_error($fail = false); /** * Build sql statement from an array * * @param string $query Should be on of the following strings: * INSERT, INSERT_SELECT, UPDATE, SELECT, DELETE * @param array $assoc_ary Array with "column => value" pairs * @return string A SQL statement like "c1 = 'a' AND c2 = 'b'" */ public function sql_build_array($query, $assoc_ary = array()); /** * Fetch all rows * * @param mixed $query_id Already executed query to get the rows from, * if false, the last query will be used. * @return mixed Nested array if the query had rows, false otherwise */ public function sql_fetchrowset($query_id = false); /** * SQL Transaction * * @param string $status Should be one of the following strings: * begin, commit, rollback * @return mixed Buffered, seekable result handle, false on error */ public function sql_transaction($status = 'begin'); /** * Build a concatenated expression * * @param string $expr1 Base SQL expression where we append the second one * @param string $expr2 SQL expression that is appended to the first expression * @return string Concatenated string */ public function sql_concatenate($expr1, $expr2); /** * Build a case expression * * Note: The two statements action_true and action_false must have the same * data type (int, vchar, ...) in the database! * * @param string $condition The condition which must be true, * to use action_true rather then action_else * @param string $action_true SQL expression that is used, if the condition is true * @param mixed $action_false SQL expression that is used, if the condition is false * @return string CASE expression including the condition and statements */ public function sql_case($condition, $action_true, $action_false = false); /** * Build sql statement from array for select and select distinct statements * * Possible query values: SELECT, SELECT_DISTINCT * * @param string $query Should be one of: SELECT, SELECT_DISTINCT * @param array $array Array with the query data: * SELECT A comma imploded list of columns to select * FROM Array with "table => alias" pairs, * (alias can also be an array) * Optional: LEFT_JOIN Array of join entries: * FROM Table that should be joined * ON Condition for the join * Optional: WHERE Where SQL statement * Optional: GROUP_BY Group by SQL statement * Optional: ORDER_BY Order by SQL statement * @return string A SQL statement ready for execution */ public function sql_build_query($query, $array); /** * Fetch field * if rownum is false, the current row is used, else it is pointing to the row (zero-based) * * @param string $field Name of the column * @param mixed $rownum Row number, if false the current row will be used * and the row curser will point to the next row * Note: $rownum is 0 based * @param mixed $query_id Already executed query to get the rows from, * if false, the last query will be used. * @return mixed String value of the field in the selected row, * false, if the row does not exist */ public function sql_fetchfield($field, $rownum = false, $query_id = false); /** * Fetch current row * * @param mixed $query_id Already executed query to get the rows from, * if false, the last query will be used. * @return mixed Array with the current row, * false, if the row does not exist */ public function sql_fetchrow($query_id = false); /** * Returns SQL string to cast a string expression to an int. * * @param string $expression An expression evaluating to string * @return string Expression returning an int */ public function cast_expr_to_bigint($expression); /** * Get last inserted id after insert statement * * @return string Autoincrement value of the last inserted row */ public function sql_nextid(); /** * Add to query count * * @param bool $cached Is this query cached? * @return null */ public function sql_add_num_queries($cached = false); /** * Build LIMIT query * * @param string $query The SQL query to execute * @param int $total The number of rows to select * @param int $offset * @param int $cache_ttl Either 0 to avoid caching or * the time in seconds which the result shall be kept in cache * @return mixed Buffered, seekable result handle, false on error */ public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0); /** * Base query method * * @param string $query The SQL query to execute * @param int $cache_ttl Either 0 to avoid caching or * the time in seconds which the result shall be kept in cache * @return mixed Buffered, seekable result handle, false on error */ public function sql_query($query = '', $cache_ttl = 0); /** * Returns SQL string to cast an integer expression to a string. * * @param string $expression An expression evaluating to int * @return string Expression returning a string */ public function cast_expr_to_string($expression); /** * Connect to server * * @param string $sqlserver Address of the database server * @param string $sqluser User name of the SQL user * @param string $sqlpassword Password of the SQL user * @param string $database Name of the database * @param mixed $port Port of the database server * @param bool $persistency * @param bool $new_link Should a new connection be established * @return mixed Connection ID on success, string error message otherwise */ public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false); /** * Run binary AND operator on DB column. * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" * * @param string $column_name The column name to use * @param int $bit The value to use for the AND operator, * will be converted to (1 << $bit). Is used by * options, using the number schema: 0, 1, 2...29 * @param string $compare Any custom SQL code after the check (for example "= 0") * @return string A SQL statement like: "{$column} & (1 << {$bit}) {$compare}" */ public function sql_bit_and($column_name, $bit, $compare = ''); /** * Free sql result * * @param mixed $query_id Already executed query result, * if false, the last query will be used. * @return null */ public function sql_freeresult($query_id = false); /** * Return number of sql queries and cached sql queries used * * @param bool $cached Should we return the number of cached or normal queries? * @return int Number of queries that have been executed */ public function sql_num_queries($cached = false); /** * Run more than one insert statement. * * @param string $table Table name to run the statements on * @param array $sql_ary Multi-dimensional array holding the statement data * @return bool false if no statements were executed. */ public function sql_multi_insert($table, $sql_ary); /** * Return number of affected rows * * @return mixed Number of the affected rows by the last query * false if no query has been run before */ public function sql_affectedrows(); /** * DBAL garbage collection, close SQL connection * * @return mixed False if no connection was opened before, * Server response otherwise */ public function sql_close(); /** * Seek to given row number * * @param mixed $rownum Row number the curser should point to * Note: $rownum is 0 based * @param mixed $query_id ID of the query to set the row cursor on * if false, the last query will be used. * $query_id will then be set correctly * @return bool False if something went wrong */ public function sql_rowseek($rownum, &$query_id); /** * Escape string used in sql query * * @param string $msg String to be escaped * @return string Escaped version of $msg */ public function sql_escape($msg); /** * Correctly adjust LIKE expression for special characters * Some DBMS are handling them in a different way * * @param string $expression The expression to use. Every wildcard is * escaped, except $this->any_char and $this->one_char * @return string A SQL statement like: "LIKE 'bertie_%'" */ public function sql_like_expression($expression); /** * Correctly adjust NOT LIKE expression for special characters * Some DBMS are handling them in a different way * * @param string $expression The expression to use. Every wildcard is * escaped, except $this->any_char and $this->one_char * @return string A SQL statement like: "NOT LIKE 'bertie_%'" */ public function sql_not_like_expression($expression); /** * Explain queries * * @param string $mode Available modes: display, start, stop, * add_select_row, fromcache, record_fromcache * @param string $query The Query that should be explained * @return mixed Either a full HTML page, boolean or null */ public function sql_report($mode, $query = ''); /** * Build IN or NOT IN sql comparison string, uses <> or = on single element * arrays to improve comparison speed * * @param string $field Name of the sql column that shall be compared * @param array $array Array of values that are (not) allowed * @param bool $negate true for NOT IN (), false for IN () * @param bool $allow_empty_set If true, allow $array to be empty, * this function will return 1=1 or 1=0 then. * @return string A SQL statement like: "IN (1, 2, 3, 4)" or "= 1" */ public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false); } driver/factory.php000077700000017335151514672100010241 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; use \Symfony\Component\DependencyInjection\ContainerInterface; /** * Database Abstraction Layer */ class factory implements driver_interface { /** * @var driver_interface */ protected $driver = null; /** * @var ContainerInterface */ protected $container; /** * Constructor. * * @param ContainerInterface $container A ContainerInterface instance */ public function __construct(ContainerInterface $container) { $this->container = $container; } /** * Return the current driver (and retrieved it from the container if necessary) * * @return driver_interface */ protected function get_driver() { if ($this->driver === null) { $this->driver = $this->container->get('dbal.conn.driver'); } return $this->driver; } /** * Set the current driver * * @param driver_interface $driver */ public function set_driver(driver_interface $driver) { $this->driver = $driver; } /** * {@inheritdoc} */ public function get_sql_layer() { return $this->get_driver()->get_sql_layer(); } /** * {@inheritdoc} */ public function get_db_name() { return $this->get_driver()->get_db_name(); } /** * {@inheritdoc} */ public function get_any_char() { return $this->get_driver()->get_any_char(); } /** * {@inheritdoc} */ public function get_one_char() { return $this->get_driver()->get_one_char(); } /** * {@inheritdoc} */ public function get_db_connect_id() { return $this->get_driver()->get_db_connect_id(); } /** * {@inheritdoc} */ public function get_sql_error_triggered() { return $this->get_driver()->get_sql_error_triggered(); } /** * {@inheritdoc} */ public function get_sql_error_sql() { return $this->get_driver()->get_sql_error_sql(); } /** * {@inheritdoc} */ public function get_transaction() { return $this->get_driver()->get_transaction(); } /** * {@inheritdoc} */ public function get_sql_time() { return $this->get_driver()->get_sql_time(); } /** * {@inheritdoc} */ public function get_sql_error_returned() { return $this->get_driver()->get_sql_error_returned(); } /** * {@inheritdoc} */ public function get_multi_insert() { return $this->get_driver()->get_multi_insert(); } /** * {@inheritdoc} */ public function set_multi_insert($multi_insert) { $this->get_driver()->set_multi_insert($multi_insert); } /** * {@inheritdoc} */ public function get_row_count($table_name) { return $this->get_driver()->get_row_count($table_name); } /** * {@inheritdoc} */ public function get_estimated_row_count($table_name) { return $this->get_driver()->get_estimated_row_count($table_name); } /** * {@inheritdoc} */ public function sql_lower_text($column_name) { return $this->get_driver()->sql_lower_text($column_name); } /** * {@inheritdoc} */ public function sql_error($sql = '') { return $this->get_driver()->sql_error($sql); } /** * {@inheritdoc} */ public function sql_buffer_nested_transactions() { return $this->get_driver()->sql_buffer_nested_transactions(); } /** * {@inheritdoc} */ public function sql_bit_or($column_name, $bit, $compare = '') { return $this->get_driver()->sql_bit_or($column_name, $bit, $compare); } /** * {@inheritdoc} */ public function sql_server_info($raw = false, $use_cache = true) { return $this->get_driver()->sql_server_info($raw, $use_cache); } /** * {@inheritdoc} */ public function sql_return_on_error($fail = false) { return $this->get_driver()->sql_return_on_error($fail); } /** * {@inheritdoc} */ public function sql_build_array($query, $assoc_ary = array()) { return $this->get_driver()->sql_build_array($query, $assoc_ary); } /** * {@inheritdoc} */ public function sql_fetchrowset($query_id = false) { return $this->get_driver()->sql_fetchrowset($query_id); } /** * {@inheritdoc} */ public function sql_transaction($status = 'begin') { return $this->get_driver()->sql_transaction($status); } /** * {@inheritdoc} */ public function sql_concatenate($expr1, $expr2) { return $this->get_driver()->sql_concatenate($expr1, $expr2); } /** * {@inheritdoc} */ public function sql_case($condition, $action_true, $action_false = false) { return $this->get_driver()->sql_case($condition, $action_true, $action_false); } /** * {@inheritdoc} */ public function sql_build_query($query, $array) { return $this->get_driver()->sql_build_query($query, $array); } /** * {@inheritdoc} */ public function sql_fetchfield($field, $rownum = false, $query_id = false) { return $this->get_driver()->sql_fetchfield($field, $rownum, $query_id); } /** * {@inheritdoc} */ public function sql_fetchrow($query_id = false) { return $this->get_driver()->sql_fetchrow($query_id); } /** * {@inheritdoc} */ public function cast_expr_to_bigint($expression) { return $this->get_driver()->cast_expr_to_bigint($expression); } /** * {@inheritdoc} */ public function sql_nextid() { return $this->get_driver()->sql_nextid(); } /** * {@inheritdoc} */ public function sql_add_num_queries($cached = false) { return $this->get_driver()->sql_add_num_queries($cached); } /** * {@inheritdoc} */ public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { return $this->get_driver()->sql_query_limit($query, $total, $offset, $cache_ttl); } /** * {@inheritdoc} */ public function sql_query($query = '', $cache_ttl = 0) { return $this->get_driver()->sql_query($query, $cache_ttl); } /** * {@inheritdoc} */ public function cast_expr_to_string($expression) { return $this->get_driver()->cast_expr_to_string($expression); } /** * {@inheritdoc} */ public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { throw new \Exception('Disabled method.'); } /** * {@inheritdoc} */ public function sql_bit_and($column_name, $bit, $compare = '') { return $this->get_driver()->sql_bit_and($column_name, $bit, $compare); } /** * {@inheritdoc} */ public function sql_freeresult($query_id = false) { return $this->get_driver()->sql_freeresult($query_id); } /** * {@inheritdoc} */ public function sql_num_queries($cached = false) { return $this->get_driver()->sql_num_queries($cached); } /** * {@inheritdoc} */ public function sql_multi_insert($table, $sql_ary) { return $this->get_driver()->sql_multi_insert($table, $sql_ary); } /** * {@inheritdoc} */ public function sql_affectedrows() { return $this->get_driver()->sql_affectedrows(); } /** * {@inheritdoc} */ public function sql_close() { return $this->get_driver()->sql_close(); } /** * {@inheritdoc} */ public function sql_rowseek($rownum, &$query_id) { return $this->get_driver()->sql_rowseek($rownum, $query_id); } /** * {@inheritdoc} */ public function sql_escape($msg) { return $this->get_driver()->sql_escape($msg); } /** * {@inheritdoc} */ public function sql_like_expression($expression) { return $this->get_driver()->sql_like_expression($expression); } /** * {@inheritdoc} */ public function sql_not_like_expression($expression) { return $this->get_driver()->sql_not_like_expression($expression); } /** * {@inheritdoc} */ public function sql_report($mode, $query = '') { return $this->get_driver()->sql_report($mode, $query); } /** * {@inheritdoc} */ public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) { return $this->get_driver()->sql_in_set($field, $array, $negate, $allow_empty_set); } } driver/mysqli.php000077700000024147151514672100010107 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * MySQLi Database Abstraction Layer * mysqli-extension has to be compiled with: * MySQL 4.1+ or MySQL 5.0+ */ class mysqli extends \phpbb\db\driver\mysql_base { var $multi_insert = true; var $connect_error = ''; /** * {@inheritDoc} */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { if (!function_exists('mysqli_connect')) { $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; return $this->sql_error(''); } $this->persistency = $persistency; $this->user = $sqluser; // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; $this->dbname = $database; $port = (!$port) ? null : $port; // If port is set and it is not numeric, most likely mysqli socket is set. // Try to map it to the $socket parameter. $socket = null; if ($port) { if (is_numeric($port)) { $port = (int) $port; } else { $socket = $port; $port = null; } } $this->db_connect_id = mysqli_init(); if (!@mysqli_real_connect($this->db_connect_id, $this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket, MYSQLI_CLIENT_FOUND_ROWS)) { $this->db_connect_id = ''; } if ($this->db_connect_id && $this->dbname != '') { @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'"); // enforce strict mode on databases that support it if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) { $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode'); if ($result !== null) { $row = @mysqli_fetch_assoc($result); $modes = array_map('trim', explode(',', $row['sql_mode'])); } else { $modes = array(); } @mysqli_free_result($result); // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES if (!in_array('TRADITIONAL', $modes)) { if (!in_array('STRICT_ALL_TABLES', $modes)) { $modes[] = 'STRICT_ALL_TABLES'; } if (!in_array('STRICT_TRANS_TABLES', $modes)) { $modes[] = 'STRICT_TRANS_TABLES'; } } $mode = implode(',', $modes); @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'"); } return $this->db_connect_id; } return $this->sql_error(''); } /** * {@inheritDoc} */ function sql_server_info($raw = false, $use_cache = true) { global $cache; if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false) { $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); if ($result !== null) { $row = @mysqli_fetch_assoc($result); $this->sql_server_version = $row['version']; if (!empty($cache) && $use_cache) { $cache->put('mysqli_version', $this->sql_server_version); } } @mysqli_free_result($result); } return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; } /** * SQL Transaction * @access private */ function _sql_transaction($status = 'begin') { switch ($status) { case 'begin': return @mysqli_autocommit($this->db_connect_id, false); break; case 'commit': $result = @mysqli_commit($this->db_connect_id); @mysqli_autocommit($this->db_connect_id, true); return $result; break; case 'rollback': $result = @mysqli_rollback($this->db_connect_id); @mysqli_autocommit($this->db_connect_id, true); return $result; break; } return true; } /** * {@inheritDoc} */ function sql_query($query = '', $cache_ttl = 0) { if ($query != '') { global $cache; // EXPLAIN only in extra debug mode if (defined('DEBUG')) { $this->sql_report('start', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->curtime = microtime(true); } $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); if ($this->query_result === false) { if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false) { $this->sql_error($query); } if (defined('DEBUG')) { $this->sql_report('stop', $query); } else if (defined('PHPBB_DISPLAY_LOAD_TIME')) { $this->sql_time += microtime(true) - $this->curtime; } if ($cache && $cache_ttl) { $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } } else if (defined('DEBUG')) { $this->sql_report('fromcache', $query); } } else { return false; } return $this->query_result; } /** * {@inheritDoc} */ function sql_affectedrows() { return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_fetchrow($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_fetchrow($query_id); } if ($query_id !== false && $query_id !== null) { $result = @mysqli_fetch_assoc($query_id); return $result !== null ? $result : false; } return false; } /** * {@inheritDoc} */ function sql_rowseek($rownum, &$query_id) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_rowseek($rownum, $query_id); } return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false; } /** * {@inheritDoc} */ function sql_nextid() { return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false; } /** * {@inheritDoc} */ function sql_freeresult($query_id = false) { global $cache; if ($query_id === false) { $query_id = $this->query_result; } if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) { return $cache->sql_freeresult($query_id); } return @mysqli_free_result($query_id); } /** * {@inheritDoc} */ function sql_escape($msg) { return @mysqli_real_escape_string($this->db_connect_id, $msg); } /** * return sql error array * @access private */ function _sql_error() { if ($this->db_connect_id) { $error = array( 'message' => @mysqli_error($this->db_connect_id), 'code' => @mysqli_errno($this->db_connect_id) ); } else if (function_exists('mysqli_connect_error')) { $error = array( 'message' => @mysqli_connect_error(), 'code' => @mysqli_connect_errno(), ); } else { $error = array( 'message' => $this->connect_error, 'code' => '', ); } return $error; } /** * Close sql connection * @access private */ function _sql_close() { return @mysqli_close($this->db_connect_id); } /** * Build db-specific report * @access private */ function _sql_report($mode, $query = '') { static $test_prof; // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING if ($test_prof === null) { $test_prof = false; if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false) { $ver = mysqli_get_server_version($this->db_connect_id); if ($ver >= 50037 && $ver < 50100) { $test_prof = true; } } } switch ($mode) { case 'start': $explain_query = $query; if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) { $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; } if (preg_match('/^SELECT/', $explain_query)) { $html_table = false; // begin profiling if ($test_prof) { @mysqli_query($this->db_connect_id, 'SET profiling = 1;'); } if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) { while ($row = @mysqli_fetch_assoc($result)) { $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @mysqli_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } if ($test_prof) { $html_table = false; // get the last profile if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;')) { $this->html_hold .= '<br />'; while ($row = @mysqli_fetch_assoc($result)) { // make <unknown> HTML safe if (!empty($row['Source_function'])) { $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); } // remove unsupported features foreach ($row as $key => $val) { if ($val === null) { unset($row[$key]); } } $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); } } @mysqli_free_result($result); if ($html_table) { $this->html_hold .= '</table>'; } @mysqli_query($this->db_connect_id, 'SET profiling = 0;'); } } break; case 'fromcache': $endtime = explode(' ', microtime()); $endtime = $endtime[0] + $endtime[1]; $result = @mysqli_query($this->db_connect_id, $query); if ($result !== null) { while ($void = @mysqli_fetch_assoc($result)) { // Take the time spent on parsing rows into account } } @mysqli_free_result($result); $splittime = explode(' ', microtime()); $splittime = $splittime[0] + $splittime[1]; $this->sql_report('record_fromcache', $query, $endtime, $splittime); break; } } } driver/mysql_base.php000077700000005132151514672100010721 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\driver; /** * Abstract MySQL Database Base Abstraction Layer */ abstract class mysql_base extends \phpbb\db\driver\driver { /** * {@inheritDoc} */ public function sql_concatenate($expr1, $expr2) { return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')'; } /** * Build LIMIT query */ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { $this->query_result = false; // if $total is set to 0 we do not want to limit the number of rows if ($total == 0) { // MySQL 4.1+ no longer supports -1 in limit queries $total = '18446744073709551615'; } $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); return $this->sql_query($query, $cache_ttl); } /** * {@inheritDoc} */ function get_estimated_row_count($table_name) { $table_status = $this->get_table_status($table_name); if (isset($table_status['Engine'])) { if ($table_status['Engine'] === 'MyISAM') { return $table_status['Rows']; } else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000) { return '~' . $table_status['Rows']; } } return parent::get_row_count($table_name); } /** * {@inheritDoc} */ function get_row_count($table_name) { $table_status = $this->get_table_status($table_name); if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM') { return $table_status['Rows']; } return parent::get_row_count($table_name); } /** * Gets some information about the specified table. * * @param string $table_name Table name * * @return array * * @access protected */ function get_table_status($table_name) { $sql = "SHOW TABLE STATUS LIKE '" . $this->sql_escape($table_name) . "'"; $result = $this->sql_query($sql); $table_status = $this->sql_fetchrow($result); $this->sql_freeresult($result); return $table_status; } /** * Build LIKE expression * @access private */ function _sql_like_expression($expression) { return $expression; } /** * Build NOT LIKE expression * @access private */ function _sql_not_like_expression($expression) { return $expression; } /** * Build db-specific query data * @access private */ function _sql_custom_build($stage, $data) { switch ($stage) { case 'FROM': $data = '(' . $data . ')'; break; } return $data; } } null_migrator_output_handler.php000077700000000717151514672100013266 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; class null_migrator_output_handler implements migrator_output_handler_interface { /** * {@inheritdoc} */ public function write($message, $verbosity) { } } log_wrapper_migrator_output_handler.php000077700000003565151514672100014641 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; use phpbb\user; class log_wrapper_migrator_output_handler implements migrator_output_handler_interface { /** * User object. * * @var user */ protected $user; /** * A migrator output handler * * @var migrator_output_handler_interface */ protected $migrator; /** * Log file handle * @var resource */ protected $file_handle = false; /** * Constructor * * @param user $user User object * @param migrator_output_handler_interface $migrator Migrator output handler * @param string $log_file File to log to */ public function __construct(user $user, migrator_output_handler_interface $migrator, $log_file) { $this->user = $user; $this->migrator = $migrator; $this->file_open($log_file); } /** * Open file for logging * * @param string $file File to open */ protected function file_open($file) { if (phpbb_is_writable(dirname($file))) { $this->file_handle = fopen($file, 'w'); } else { throw new \RuntimeException('Unable to write to migrator log file'); } } /** * {@inheritdoc} */ public function write($message, $verbosity) { $this->migrator->write($message, $verbosity); if ($this->file_handle !== false) { $translated_message = call_user_func_array(array($this->user, 'lang'), $message) . "\n"; if ($verbosity <= migrator_output_handler_interface::VERBOSITY_NORMAL) { $translated_message = '[INFO] ' . $translated_message; } else { $translated_message = '[DEBUG] ' . $translated_message; } fwrite($this->file_handle, $translated_message); fflush($this->file_handle); } } } migrator.php000077700000052262151514672100007121 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * The migrator is responsible for applying new migrations in the correct order. */ class migrator { /** * @var ContainerInterface */ protected $container; /** @var \phpbb\config\config */ protected $config; /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var \phpbb\db\tools */ protected $db_tools; /** @var \phpbb\db\migration\helper */ protected $helper; /** @var string */ protected $table_prefix; /** @var string */ protected $phpbb_root_path; /** @var string */ protected $php_ext; /** @var string */ protected $migrations_table; /** * State of all migrations * * (SELECT * FROM migrations table) * * @var array */ protected $migration_state = array(); /** * Array of all migrations available to be run * * @var array */ protected $migrations = array(); /** * Array of migrations that have been determined to be fulfillable * * @var array */ protected $fulfillable_migrations = array(); /** * 'name,' 'class,' and 'state' of the last migration run * * 'effectively_installed' set and set to true if the migration was effectively_installed * * @var array */ public $last_run_migration = false; /** * The output handler. A null handler is configured by default. * * @var migrator_output_handler_interface */ public $output_handler; /** * Constructor of the database migrator */ public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper) { $this->container = $container; $this->config = $config; $this->db = $db; $this->db_tools = $db_tools; $this->helper = $helper; $this->migrations_table = $migrations_table; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->table_prefix = $table_prefix; $this->output_handler = new null_migrator_output_handler(); foreach ($tools as $tool) { $this->tools[$tool->get_name()] = $tool; } $this->tools['dbtools'] = $this->db_tools; $this->load_migration_state(); } /** * Set the output handler. * * @param migrator_output_handler $handler The output handler */ public function set_output_handler(migrator_output_handler_interface $handler) { $this->output_handler = $handler; } /** * Loads all migrations and their application state from the database. * * @return null */ public function load_migration_state() { $this->migration_state = array(); // prevent errors in case the table does not exist yet $this->db->sql_return_on_error(true); $sql = "SELECT * FROM " . $this->migrations_table; $result = $this->db->sql_query($sql); if (!$this->db->get_sql_error_triggered()) { while ($migration = $this->db->sql_fetchrow($result)) { $this->migration_state[$migration['migration_name']] = $migration; $this->migration_state[$migration['migration_name']]['migration_depends_on'] = unserialize($migration['migration_depends_on']); } } $this->db->sql_freeresult($result); $this->db->sql_return_on_error(false); } /** * Sets the list of available migration class names to the given array. * * @param array $class_names An array of migration class names * @return null */ public function set_migrations($class_names) { $this->migrations = $class_names; } /** * Runs a single update step from the next migration to be applied. * * The update step can either be a schema or a (partial) data update. To * check if update() needs to be called again use the finished() method. * * @return null */ public function update() { $this->container->get('dispatcher')->disable(); $this->update_do(); $this->container->get('dispatcher')->enable(); } /** * Effectively runs a single update step from the next migration to be applied. * * @return null */ protected function update_do() { foreach ($this->migrations as $name) { if (!isset($this->migration_state[$name]) || !$this->migration_state[$name]['migration_schema_done'] || !$this->migration_state[$name]['migration_data_done']) { if (!$this->try_apply($name)) { continue; } else { return; } } else { $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); } } } /** * Attempts to apply a step of the given migration or one of its dependencies * * @param string $name The class name of the migration * @return bool Whether any update step was successfully run * @throws \phpbb\db\migration\exception */ protected function try_apply($name) { if (!class_exists($name)) { $this->output_handler->write(array('MIGRATION_NOT_VALID', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); return false; } $migration = $this->get_migration($name); $state = (isset($this->migration_state[$name])) ? $this->migration_state[$name] : array( 'migration_depends_on' => $migration->depends_on(), 'migration_schema_done' => false, 'migration_data_done' => false, 'migration_data_state' => '', 'migration_start_time' => 0, 'migration_end_time' => 0, ); if (!empty($state['migration_depends_on'])) { $this->output_handler->write(array('MIGRATION_APPLY_DEPENDENCIES', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); } foreach ($state['migration_depends_on'] as $depend) { if ($this->unfulfillable($depend) !== false) { throw new \phpbb\db\migration\exception('MIGRATION_NOT_FULFILLABLE', $name, $depend); } if (!isset($this->migration_state[$depend]) || !$this->migration_state[$depend]['migration_schema_done'] || !$this->migration_state[$depend]['migration_data_done']) { return $this->try_apply($depend); } } $this->last_run_migration = array( 'name' => $name, 'class' => $migration, 'state' => $state, 'task' => '', ); if (!isset($this->migration_state[$name])) { if ($state['migration_start_time'] == 0 && $migration->effectively_installed()) { $state = array( 'migration_depends_on' => $migration->depends_on(), 'migration_schema_done' => true, 'migration_data_done' => true, 'migration_data_state' => '', 'migration_start_time' => 0, 'migration_end_time' => 0, ); $this->last_run_migration['effectively_installed'] = true; $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); } else { $state['migration_start_time'] = time(); } } $this->set_migration_state($name, $state); if (!$state['migration_schema_done']) { $this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); $this->last_run_migration['task'] = 'process_schema_step'; $elapsed_time = microtime(true); $steps = $this->helper->get_schema_steps($migration->update_schema()); $result = $this->process_data_step($steps, $state['migration_data_state']); $elapsed_time = microtime(true) - $elapsed_time; $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_schema_done'] = ($result === true); $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL); } else if (!$state['migration_data_done']) { try { $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); $this->last_run_migration['task'] = 'process_data_step'; $elapsed_time = microtime(true); $result = $this->process_data_step($migration->update_data(), $state['migration_data_state']); $elapsed_time = microtime(true) - $elapsed_time; $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_data_done'] = ($result === true); $state['migration_end_time'] = ($result === true) ? time() : 0; if ($state['migration_schema_done']) { $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL); } else { $this->output_handler->write(array('MIGRATION_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); } } catch (\phpbb\db\migration\exception $e) { // Revert the schema changes $this->revert_do($name); // Rethrow exception throw $e; } } $this->set_migration_state($name, $state); return true; } /** * Runs a single revert step from the last migration installed * * YOU MUST ADD/SET ALL MIGRATIONS THAT COULD BE DEPENDENT ON THE MIGRATION TO REVERT TO BEFORE CALLING THIS METHOD! * The revert step can either be a schema or a (partial) data revert. To * check if revert() needs to be called again use the migration_state() method. * * @param string $migration String migration name to revert (including any that depend on this migration) */ public function revert($migration) { $this->container->get('dispatcher')->disable(); $this->revert_do($migration); $this->container->get('dispatcher')->enable(); } /** * Effectively runs a single revert step from the last migration installed * * @param string $migration String migration name to revert (including any that depend on this migration) * @return null */ protected function revert_do($migration) { if (!isset($this->migration_state[$migration])) { // Not installed return; } foreach ($this->migration_state as $name => $state) { if (!empty($state['migration_depends_on']) && in_array($migration, $state['migration_depends_on'])) { $this->revert_do($name); } } $this->try_revert($migration); } /** * Attempts to revert a step of the given migration or one of its dependencies * * @param string $name The class name of the migration * @return bool Whether any update step was successfully run */ protected function try_revert($name) { if (!class_exists($name)) { return false; } $migration = $this->get_migration($name); $state = $this->migration_state[$name]; $this->last_run_migration = array( 'name' => $name, 'class' => $migration, 'task' => '', ); if ($state['migration_data_done']) { if ($state['migration_data_state'] !== 'revert_data') { $result = $this->process_data_step($migration->update_data(), $state['migration_data_state'], true); $state['migration_data_state'] = ($result === true) ? 'revert_data' : $result; } else { $result = $this->process_data_step($migration->revert_data(), '', false); $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_data_done'] = ($result === true) ? false : true; } $this->set_migration_state($name, $state); } else if ($state['migration_schema_done']) { $steps = $this->helper->get_schema_steps($migration->revert_schema()); $result = $this->process_data_step($steps, $state['migration_data_state']); $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_schema_done'] = ($result === true) ? false : true; if (!$state['migration_schema_done']) { $sql = 'DELETE FROM ' . $this->migrations_table . " WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); unset($this->migration_state[$name]); } } return true; } /** * Process the data step of the migration * * @param array $steps The steps to run * @param bool|string $state Current state of the migration * @param bool $revert true to revert a data step * @return bool|string migration state. True if completed, serialized array if not finished * @throws \phpbb\db\migration\exception */ protected function process_data_step($steps, $state, $revert = false) { $state = ($state) ? unserialize($state) : false; // reverse order of steps if reverting if ($revert === true) { $steps = array_reverse($steps); } foreach ($steps as $step_identifier => $step) { $last_result = 0; if ($state) { // Continue until we reach the step that matches the last step called if ($state['step'] != $step_identifier) { continue; } // We send the result from last time to the callable function $last_result = $state['result']; // Set state to false since we reached the point we were at $state = false; } try { // Result will be null or true if everything completed correctly $result = $this->run_step($step, $last_result, $revert); if ($result !== null && $result !== true) { return serialize(array( 'result' => $result, 'step' => $step_identifier, )); } } catch (\phpbb\db\migration\exception $e) { // We should try rolling back here foreach ($steps as $reverse_step_identifier => $reverse_step) { // If we've reached the current step we can break because we reversed everything that was run if ($reverse_step_identifier == $step_identifier) { break; } // Reverse the step that was run $result = $this->run_step($reverse_step, false, !$revert); } // rethrow the exception throw $e; } } return true; } /** * Run a single step * * An exception should be thrown if an error occurs * * @param mixed $step Data step from migration * @param mixed $last_result Result to pass to the callable (only for 'custom' method) * @param bool $reverse False to install, True to attempt uninstallation by reversing the call * @return null */ protected function run_step($step, $last_result = 0, $reverse = false) { $callable_and_parameters = $this->get_callable_from_step($step, $last_result, $reverse); if ($callable_and_parameters === false) { return; } $callable = $callable_and_parameters[0]; $parameters = $callable_and_parameters[1]; return call_user_func_array($callable, $parameters); } /** * Get a callable statement from a data step * * @param array $step Data step from migration * @param mixed $last_result Result to pass to the callable (only for 'custom' method) * @param bool $reverse False to install, True to attempt uninstallation by reversing the call * @return array Array with parameters for call_user_func_array(), 0 is the callable, 1 is parameters * @throws \phpbb\db\migration\exception */ protected function get_callable_from_step(array $step, $last_result = 0, $reverse = false) { $type = $step[0]; $parameters = $step[1]; $parts = explode('.', $type); $class = $parts[0]; $method = false; if (isset($parts[1])) { $method = $parts[1]; } switch ($class) { case 'if': if (!isset($parameters[0])) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_CONDITION', $step); } if (!isset($parameters[1])) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_STEP', $step); } $condition = $parameters[0]; if (!$condition) { return false; } $step = $parameters[1]; return $this->get_callable_from_step($step); break; case 'custom': if (!is_callable($parameters[0])) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_CUSTOM_NOT_CALLABLE', $step); } if ($reverse) { return false; } else { return array( $parameters[0], array($last_result), ); } break; default: if (!$method) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNKNOWN_TYPE', $step); } if (!isset($this->tools[$class])) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_TOOL', $step); } if (!method_exists(get_class($this->tools[$class]), $method)) { throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_METHOD', $step); } // Attempt to reverse operations if ($reverse) { array_unshift($parameters, $method); return array( array($this->tools[$class], 'reverse'), $parameters, ); } return array( array($this->tools[$class], $method), $parameters, ); break; } } /** * Insert/Update migration row into the database * * @param string $name Name of the migration * @param array $state * @return null */ protected function set_migration_state($name, $state) { $migration_row = $state; $migration_row['migration_depends_on'] = serialize($state['migration_depends_on']); if (isset($this->migration_state[$name])) { $sql = 'UPDATE ' . $this->migrations_table . ' SET ' . $this->db->sql_build_array('UPDATE', $migration_row) . " WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); } else { $migration_row['migration_name'] = $name; $sql = 'INSERT INTO ' . $this->migrations_table . ' ' . $this->db->sql_build_array('INSERT', $migration_row); $this->db->sql_query($sql); } $this->migration_state[$name] = $state; $this->last_run_migration['state'] = $state; } /** * Checks if a migration's dependencies can even theoretically be satisfied. * * @param string $name The class name of the migration * @return bool|string False if fulfillable, string of missing migration name if unfulfillable */ public function unfulfillable($name) { if (isset($this->migration_state[$name]) || isset($this->fulfillable_migrations[$name])) { return false; } if (!class_exists($name)) { return $name; } $migration = $this->get_migration($name); $depends = $migration->depends_on(); foreach ($depends as $depend) { $unfulfillable = $this->unfulfillable($depend); if ($unfulfillable !== false) { return $unfulfillable; } } $this->fulfillable_migrations[$name] = true; return false; } /** * Checks whether all available, fulfillable migrations have been applied. * * @return bool Whether the migrations have been applied */ public function finished() { foreach ($this->migrations as $name) { if (!isset($this->migration_state[$name])) { // skip unfulfillable migrations, but fulfillables mean we // are not finished yet if ($this->unfulfillable($name) !== false) { continue; } return false; } $migration = $this->migration_state[$name]; if (!$migration['migration_schema_done'] || !$migration['migration_data_done']) { return false; } } return true; } /** * Gets a migration state (whether it is installed and to what extent) * * @param string $migration String migration name to check if it is installed * @return bool|array False if the migration has not at all been installed, array */ public function migration_state($migration) { if (!isset($this->migration_state[$migration])) { return false; } return $this->migration_state[$migration]; } /** * Helper to get a migration * * @param string $name Name of the migration * @return \phpbb\db\migration\migration */ protected function get_migration($name) { $migration = new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); if ($migration instanceof ContainerAwareInterface) { $migration->setContainer($this->container); } return $migration; } /** * This function adds all migrations sent to it to the migrations table * * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER. * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE! * * @param array $migrations Array of migrations (names) to add to the migrations table * @return null */ public function populate_migrations($migrations) { foreach ($migrations as $name) { if ($this->migration_state($name) === false) { $state = array( 'migration_depends_on' => $name::depends_on(), 'migration_schema_done' => true, 'migration_data_done' => true, 'migration_data_state' => '', 'migration_start_time' => time(), 'migration_end_time' => time(), ); $this->set_migration_state($name, $state); } } } /** * Creates the migrations table if it does not exist. * @return null */ public function create_migrations_table() { // Make sure migrations have been installed. if (!$this->db_tools->sql_table_exists($this->table_prefix . 'migrations')) { $this->db_tools->sql_create_table($this->table_prefix . 'migrations', array( 'COLUMNS' => array( 'migration_name' => array('VCHAR', ''), 'migration_depends_on' => array('TEXT', ''), 'migration_schema_done' => array('BOOL', 0), 'migration_data_done' => array('BOOL', 0), 'migration_data_state' => array('TEXT', ''), 'migration_start_time' => array('TIMESTAMP', 0), 'migration_end_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => 'migration_name', )); } } } migration/helper.php000077700000003532151514672100010541 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; /** * The migrator is responsible for applying new migrations in the correct order. */ class helper { /** * Get the schema steps from an array of schema changes * * This splits up $schema_changes into individual changes so that the * changes can be chunked * * @param array $schema_changes from migration * @return array */ public function get_schema_steps($schema_changes) { $steps = array(); // Nested level of data (only supports 1/2 currently) $nested_level = array( 'drop_tables' => 1, 'add_tables' => 1, 'change_columns' => 2, 'add_columns' => 2, 'drop_keys' => 2, 'drop_columns' => 2, 'add_primary_keys' => 2, // perform_schema_changes only uses one level, but second is in the function 'add_unique_index' => 2, 'add_index' => 2, ); foreach ($nested_level as $change_type => $data_depth) { if (!empty($schema_changes[$change_type])) { foreach ($schema_changes[$change_type] as $key => $value) { if ($data_depth === 1) { $steps[] = array( 'dbtools.perform_schema_changes', array(array( $change_type => array( (!is_int($key)) ? $key : 0 => $value, ), )), ); } else if ($data_depth === 2) { foreach ($value as $key2 => $value2) { $steps[] = array( 'dbtools.perform_schema_changes', array(array( $change_type => array( $key => array( $key2 => $value2, ), ), )), ); } } } } } return $steps; } } migration/profilefield_base_migration.php000077700000014262151514672100014773 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; abstract class profilefield_base_migration extends container_aware_migration { protected $profilefield_name; protected $profilefield_database_type; protected $profilefield_data; /** * Language data should be in array -> each language_data in separate key * array( * array( * 'option_id' => value, * 'field_type' => value, * 'lang_value' => value, * ), * array( * 'option_id' => value, * 'field_type' => value, * 'lang_value' => value, * ), * ) */ protected $profilefield_language_data; protected $user_column_name; public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'profile_fields_data', 'pf_' . $this->profilefield_name); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields_data' => array( 'pf_' . $this->profilefield_name => $this->profilefield_database_type, ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields_data' => array( 'pf_' . $this->profilefield_name, ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), array('custom', array(array($this, 'convert_user_field_to_custom_field'))), ); } public function revert_data() { return array( array('custom', array(array($this, 'delete_custom_profile_field_data'))), ); } public function create_custom_field() { $sql = 'SELECT MAX(field_order) as max_field_order FROM ' . PROFILE_FIELDS_TABLE; $result = $this->db->sql_query($sql); $max_field_order = (int) $this->db->sql_fetchfield('max_field_order'); $this->db->sql_freeresult($result); $sql_ary = array_merge($this->profilefield_data, array( 'field_order' => $max_field_order + 1, )); $sql = 'INSERT INTO ' . PROFILE_FIELDS_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary); $this->db->sql_query($sql); $field_id = (int) $this->db->sql_nextid(); $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, PROFILE_LANG_TABLE); $sql = 'SELECT lang_id FROM ' . LANG_TABLE; $result = $this->db->sql_query($sql); $lang_name = (strpos($this->profilefield_name, 'phpbb_') === 0) ? strtoupper(substr($this->profilefield_name, 6)) : strtoupper($this->profilefield_name); while ($lang_id = (int) $this->db->sql_fetchfield('lang_id')) { $insert_buffer->insert(array( 'field_id' => (int) $field_id, 'lang_id' => (int) $lang_id, 'lang_name' => $lang_name, 'lang_explain' => '', 'lang_default_value' => '', )); } $this->db->sql_freeresult($result); $insert_buffer->flush(); } /** * Create Custom profile fields languguage entries */ public function create_language_entries() { $field_id = $this->get_custom_profile_field_id(); $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, PROFILE_FIELDS_LANG_TABLE); $sql = 'SELECT lang_id FROM ' . LANG_TABLE; $result = $this->db->sql_query($sql); while ($lang_id = (int) $this->db->sql_fetchfield('lang_id')) { foreach ($this->profilefield_language_data as $language_data) { $insert_buffer->insert(array_merge(array( 'field_id' => (int) $field_id, 'lang_id' => (int) $lang_id, ), $language_data)); } } $this->db->sql_freeresult($result); $insert_buffer->flush(); } /** * Clean database when reverting the migration */ public function delete_custom_profile_field_data() { $field_id = $this->get_custom_profile_field_id(); $sql = 'DELETE FROM ' . PROFILE_FIELDS_TABLE . ' WHERE field_id = ' . (int) $field_id; $this->db->sql_query($sql); $sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE field_id = ' . (int) $field_id; $this->db->sql_query($sql); $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE field_id = ' . (int) $field_id; $this->db->sql_query($sql); } /** * Get custom profile field id * @return int custom profile filed id */ public function get_custom_profile_field_id() { $sql = 'SELECT field_id FROM ' . PROFILE_FIELDS_TABLE . " WHERE field_name = '" . $this->profilefield_name . "'"; $result = $this->db->sql_query($sql); $field_id = (int) $this->db->sql_fetchfield('field_id'); $this->db->sql_freeresult($result); return $field_id; } /** * @param int $start Start of staggering step * @return mixed int start of the next step, null if the end was reached */ public function convert_user_field_to_custom_field($start) { $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->table_prefix . 'profile_fields_data'); $limit = 250; $converted_users = 0; $sql = 'SELECT user_id, ' . $this->user_column_name . ' FROM ' . $this->table_prefix . 'users WHERE ' . $this->user_column_name . " <> '' ORDER BY user_id"; $result = $this->db->sql_query_limit($sql, $limit, $start); while ($row = $this->db->sql_fetchrow($result)) { $converted_users++; $cp_data = array( 'pf_' . $this->profilefield_name => $row[$this->user_column_name], ); $sql = 'UPDATE ' . $this->table_prefix . 'profile_fields_data SET ' . $this->db->sql_build_array('UPDATE', $cp_data) . ' WHERE user_id = ' . (int) $row['user_id']; $this->db->sql_query($sql); if (!$this->db->sql_affectedrows()) { $cp_data['user_id'] = (int) $row['user_id']; $cp_data = array_merge($this->get_insert_sql_array(), $cp_data); $insert_buffer->insert($cp_data); } } $this->db->sql_freeresult($result); $insert_buffer->flush(); if ($converted_users < $limit) { // No more users left, we are done... return; } return $start + $limit; } protected function get_insert_sql_array() { static $profile_row; if ($profile_row === null) { $manager = $this->container->get('profilefields.manager'); $profile_row = $manager->build_insert_sql_array(array()); } return $profile_row; } } migration/exception.php000077700000002677151514672100011271 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; /** * The migrator is responsible for applying new migrations in the correct order. */ class exception extends \Exception { /** * Extra parameters sent to exception to aid in debugging * @var array */ protected $parameters; /** * Throw an exception. * * First argument is the error message. * Additional arguments will be output with the error message. */ public function __construct() { $parameters = func_get_args(); $message = array_shift($parameters); parent::__construct($message); $this->parameters = $parameters; } /** * Output the error as a string * * @return string */ public function __toString() { return $this->message . ': ' . var_export($this->parameters, true); } /** * Get the parameters * * @return array */ public function getParameters() { return $this->parameters; } /** * Get localised message (with $user->lang()) * * @param \phpbb\user $user * @return string */ public function getLocalisedMessage(\phpbb\user $user) { $parameters = $this->getParameters(); array_unshift($parameters, $this->getMessage()); return call_user_func_array(array($user, 'lang'), $parameters); } } migration/tool/config.php000077700000006563151514672100011513 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\tool; /** * Migration config tool */ class config implements \phpbb\db\migration\tool\tool_interface { /** @var \phpbb\config\config */ protected $config; /** * Constructor * * @param \phpbb\config\config $config */ public function __construct(\phpbb\config\config $config) { $this->config = $config; } /** * {@inheritdoc} */ public function get_name() { return 'config'; } /** * Add a config setting. * * @param string $config_name The name of the config setting * you would like to add * @param mixed $config_value The value of the config setting * @param bool $is_dynamic True if it is dynamic (changes very often) * and should not be stored in the cache, false if not. * @return null */ public function add($config_name, $config_value, $is_dynamic = false) { if (isset($this->config[$config_name])) { return; } $this->config->set($config_name, $config_value, !$is_dynamic); } /** * Update an existing config setting. * * @param string $config_name The name of the config setting you would * like to update * @param mixed $config_value The value of the config setting * @return null * @throws \phpbb\db\migration\exception */ public function update($config_name, $config_value) { if (!isset($this->config[$config_name])) { throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); } $this->config->set($config_name, $config_value); } /** * Update a config setting if the first argument equal to the * current config value * * @param string $compare If equal to the current config value, will be * updated to the new config value, otherwise not * @param string $config_name The name of the config setting you would * like to update * @param mixed $config_value The value of the config setting * @return null * @throws \phpbb\db\migration\exception */ public function update_if_equals($compare, $config_name, $config_value) { if (!isset($this->config[$config_name])) { throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); } $this->config->set_atomic($config_name, $compare, $config_value); } /** * Remove an existing config setting. * * @param string $config_name The name of the config setting you would * like to remove * @return null */ public function remove($config_name) { if (!isset($this->config[$config_name])) { return; } $this->config->delete($config_name); } /** * {@inheritdoc} */ public function reverse() { $arguments = func_get_args(); $original_call = array_shift($arguments); $call = false; switch ($original_call) { case 'add': $call = 'remove'; break; case 'remove': $call = 'add'; if (sizeof($arguments) == 1) { $arguments[] = ''; } break; case 'update_if_equals': $call = 'update_if_equals'; // Set to the original value if the current value is what we compared to originally $arguments = array( $arguments[2], $arguments[1], $arguments[0], ); break; } if ($call) { return call_user_func_array(array(&$this, $call), $arguments); } } } migration/tool/tool_interface.php000077700000001401151514672100013225 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\tool; /** * Migration tool interface */ interface tool_interface { /** * Retrieve a short name used for commands in migrations. * * @return string short name */ public function get_name(); /** * Reverse an original install action * * First argument is the original call to the class (e.g. add, remove) * After the first argument, send the original arguments to the function in the original call * * @return null */ public function reverse(); } migration/tool/config_text.php000077700000004627151514672100012556 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\tool; /** * Migration config_text tool */ class config_text implements \phpbb\db\migration\tool\tool_interface { /** @var \phpbb\config\db_text */ protected $config_text; /** * Constructor * * @param \phpbb\config\db_text $config_text */ public function __construct(\phpbb\config\db_text $config_text) { $this->config_text = $config_text; } /** * {@inheritdoc} */ public function get_name() { return 'config_text'; } /** * Add a config_text setting. * * @param string $config_name The name of the config_text setting * you would like to add * @param mixed $config_value The value of the config_text setting * @return null */ public function add($config_name, $config_value) { if (!is_null($this->config_text->get($config_name))) { return; } $this->config_text->set($config_name, $config_value); } /** * Update an existing config_text setting. * * @param string $config_name The name of the config_text setting you would * like to update * @param mixed $config_value The value of the config_text setting * @return null * @throws \phpbb\db\migration\exception */ public function update($config_name, $config_value) { if (is_null($this->config_text->get($config_name))) { throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); } $this->config_text->set($config_name, $config_value); } /** * Remove an existing config_text setting. * * @param string $config_name The name of the config_text setting you would * like to remove * @return null */ public function remove($config_name) { if (is_null($this->config_text->get($config_name))) { return; } $this->config_text->delete($config_name); } /** * {@inheritdoc} */ public function reverse() { $arguments = func_get_args(); $original_call = array_shift($arguments); $call = false; switch ($original_call) { case 'add': $call = 'remove'; break; case 'remove': $call = 'add'; if (sizeof($arguments) == 1) { $arguments[] = ''; } break; } if ($call) { return call_user_func_array(array(&$this, $call), $arguments); } } } migration/tool/module.php000077700000033356151514672100011533 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\tool; /** * Migration module management tool */ class module implements \phpbb\db\migration\tool\tool_interface { /** @var \phpbb\cache\service */ protected $cache; /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var \phpbb\user */ protected $user; /** @var string */ protected $phpbb_root_path; /** @var string */ protected $php_ext; /** @var string */ protected $modules_table; /** * Constructor * * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\cache\service $cache * @param \phpbb\user $user * @param string $phpbb_root_path * @param string $php_ext * @param string $modules_table */ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, $phpbb_root_path, $php_ext, $modules_table) { $this->db = $db; $this->cache = $cache; $this->user = $user; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->modules_table = $modules_table; } /** * {@inheritdoc} */ public function get_name() { return 'module'; } /** * Module Exists * * Check if a module exists * * @param string $class The module class(acp|mcp|ucp) * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent). * Use false to ignore the parent check and check class wide. * @param int|string $module The module_id|module_langname you would like to * check for to see if it exists * @return bool true/false if module exists */ public function exists($class, $parent, $module) { // the main root directory should return true if (!$module) { return true; } $parent_sql = ''; if ($parent !== false) { // Allows '' to be sent as 0 $parent = $parent ?: 0; if (!is_numeric($parent)) { $sql = 'SELECT module_id FROM ' . $this->modules_table . " WHERE module_langname = '" . $this->db->sql_escape($parent) . "' AND module_class = '" . $this->db->sql_escape($class) . "'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); if (!$module_id) { return false; } $parent_sql = 'AND parent_id = ' . (int) $module_id; } else { $parent_sql = 'AND parent_id = ' . (int) $parent; } } $sql = 'SELECT module_id FROM ' . $this->modules_table . " WHERE module_class = '" . $this->db->sql_escape($class) . "' $parent_sql AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'"); $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); if ($module_id) { return true; } return false; } /** * Module Add * * Add a new module * * @param string $class The module class(acp|mcp|ucp) * @param int|string $parent The parent module_id|module_langname (0 for no parent) * @param array $data an array of the data on the new \module. * This can be setup in two different ways. * 1. The "manual" way. For inserting a category or one at a time. * It will be merged with the base array shown a bit below, * but at the least requires 'module_langname' to be sent, and, * if you want to create a module (instead of just a category) you must * send module_basename and module_mode. * array( * 'module_enabled' => 1, * 'module_display' => 1, * 'module_basename' => '', * 'module_class' => $class, * 'parent_id' => (int) $parent, * 'module_langname' => '', * 'module_mode' => '', * 'module_auth' => '', * ) * 2. The "automatic" way. For inserting multiple at a time based on the * specs in the info file for the module(s). For this to work the * modules must be correctly setup in the info file. * An example follows (this would insert the settings, log, and flag * modes from the includes/acp/info/acp_asacp.php file): * array( * 'module_basename' => 'asacp', * 'modes' => array('settings', 'log', 'flag'), * ) * Optionally you may not send 'modes' and it will insert all of the * modules in that info file. * path, specify that here * @return null * @throws \phpbb\db\migration\exception */ public function add($class, $parent = 0, $data = array()) { // Allows '' to be sent as 0 $parent = $parent ?: 0; // allow sending the name as a string in $data to create a category if (!is_array($data)) { $data = array('module_langname' => $data); } if (!isset($data['module_langname'])) { // The "automatic" way $basename = (isset($data['module_basename'])) ? $data['module_basename'] : ''; $module = $this->get_module_info($class, $basename); $result = ''; foreach ($module['modes'] as $mode => $module_info) { if (!isset($data['modes']) || in_array($mode, $data['modes'])) { $new_module = array( 'module_basename' => $basename, 'module_langname' => $module_info['title'], 'module_mode' => $mode, 'module_auth' => $module_info['auth'], 'module_display' => (isset($module_info['display'])) ? $module_info['display'] : true, 'before' => (isset($module_info['before'])) ? $module_info['before'] : false, 'after' => (isset($module_info['after'])) ? $module_info['after'] : false, ); // Run the "manual" way with the data we've collected. $this->add($class, $parent, $new_module); } } return; } // The "manual" way if (!is_numeric($parent)) { $sql = 'SELECT module_id FROM ' . $this->modules_table . " WHERE module_langname = '" . $this->db->sql_escape($parent) . "' AND module_class = '" . $this->db->sql_escape($class) . "'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); if (!$module_id) { throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); } $parent = $data['parent_id'] = $module_id; } else if (!$this->exists($class, false, $parent)) { throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); } if ($this->exists($class, $parent, $data['module_langname'])) { return; } if (!class_exists('acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); $this->user->add_lang('acp/modules'); } $acp_modules = new \acp_modules(); $module_data = array( 'module_enabled' => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1, 'module_display' => (isset($data['module_display'])) ? $data['module_display'] : 1, 'module_basename' => (isset($data['module_basename'])) ? $data['module_basename'] : '', 'module_class' => $class, 'parent_id' => (int) $parent, 'module_langname' => (isset($data['module_langname'])) ? $data['module_langname'] : '', 'module_mode' => (isset($data['module_mode'])) ? $data['module_mode'] : '', 'module_auth' => (isset($data['module_auth'])) ? $data['module_auth'] : '', ); $result = $acp_modules->update_module_data($module_data, true); // update_module_data can either return a string or an empty array... if (is_string($result)) { // Error throw new \phpbb\db\migration\exception('MODULE_ERROR', $result); } else { // Success $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']); add_log('admin', 'LOG_MODULE_ADD', $module_log_name); // Move the module if requested above/below an existing one if (isset($data['before']) && $data['before']) { $sql = 'SELECT left_id FROM ' . $this->modules_table . " WHERE module_class = '" . $this->db->sql_escape($class) . "' AND parent_id = " . (int) $parent . " AND module_langname = '" . $this->db->sql_escape($data['before']) . "'"; $this->db->sql_query($sql); $to_left = (int) $this->db->sql_fetchfield('left_id'); $sql = 'UPDATE ' . $this->modules_table . " SET left_id = left_id + 2, right_id = right_id + 2 WHERE module_class = '" . $this->db->sql_escape($class) . "' AND left_id >= $to_left AND left_id < {$module_data['left_id']}"; $this->db->sql_query($sql); $sql = 'UPDATE ' . $this->modules_table . " SET left_id = $to_left, right_id = " . ($to_left + 1) . " WHERE module_class = '" . $this->db->sql_escape($class) . "' AND module_id = {$module_data['module_id']}"; $this->db->sql_query($sql); } else if (isset($data['after']) && $data['after']) { $sql = 'SELECT right_id FROM ' . $this->modules_table . " WHERE module_class = '" . $this->db->sql_escape($class) . "' AND parent_id = " . (int) $parent . " AND module_langname = '" . $this->db->sql_escape($data['after']) . "'"; $this->db->sql_query($sql); $to_right = (int) $this->db->sql_fetchfield('right_id'); $sql = 'UPDATE ' . $this->modules_table . " SET left_id = left_id + 2, right_id = right_id + 2 WHERE module_class = '" . $this->db->sql_escape($class) . "' AND left_id >= $to_right AND left_id < {$module_data['left_id']}"; $this->db->sql_query($sql); $sql = 'UPDATE ' . $this->modules_table . ' SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . " WHERE module_class = '" . $this->db->sql_escape($class) . "' AND module_id = {$module_data['module_id']}"; $this->db->sql_query($sql); } } // Clear the Modules Cache $this->cache->destroy("_modules_$class"); } /** * Module Remove * * Remove a module * * @param string $class The module class(acp|mcp|ucp) * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent). * Use false to ignore the parent check and check class wide. * @param int|string $module The module id|module_langname * specify that here * @return null * @throws \phpbb\db\migration\exception */ public function remove($class, $parent = 0, $module = '') { // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto if (is_array($module)) { if (isset($module['module_langname'])) { // Manual Method return $this->remove($class, $parent, $module['module_langname']); } // Failed. if (!isset($module['module_basename'])) { throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST'); } // Automatic method $basename = $module['module_basename']; $module_info = $this->get_module_info($class, $basename); foreach ($module_info['modes'] as $mode => $info) { if (!isset($module['modes']) || in_array($mode, $module['modes'])) { $this->remove($class, $parent, $info['title']); } } } else { if (!$this->exists($class, $parent, $module)) { return; } $parent_sql = ''; if ($parent !== false) { // Allows '' to be sent as 0 $parent = ($parent) ?: 0; if (!is_numeric($parent)) { $sql = 'SELECT module_id FROM ' . $this->modules_table . " WHERE module_langname = '" . $this->db->sql_escape($parent) . "' AND module_class = '" . $this->db->sql_escape($class) . "'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); // we know it exists from the module_exists check $parent_sql = 'AND parent_id = ' . (int) $module_id; } else { $parent_sql = 'AND parent_id = ' . (int) $parent; } } $module_ids = array(); if (!is_numeric($module)) { $sql = 'SELECT module_id FROM ' . $this->modules_table . " WHERE module_langname = '" . $this->db->sql_escape($module) . "' AND module_class = '" . $this->db->sql_escape($class) . "' $parent_sql"; $result = $this->db->sql_query($sql); while ($module_id = $this->db->sql_fetchfield('module_id')) { $module_ids[] = (int) $module_id; } $this->db->sql_freeresult($result); } else { $module_ids[] = (int) $module; } if (!class_exists('acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); $this->user->add_lang('acp/modules'); } $acp_modules = new \acp_modules(); $acp_modules->module_class = $class; foreach ($module_ids as $module_id) { $result = $acp_modules->delete_module($module_id); if (!empty($result)) { return; } } $this->cache->destroy("_modules_$class"); } } /** * {@inheritdoc} */ public function reverse() { $arguments = func_get_args(); $original_call = array_shift($arguments); $call = false; switch ($original_call) { case 'add': $call = 'remove'; break; case 'remove': $call = 'add'; break; } if ($call) { return call_user_func_array(array(&$this, $call), $arguments); } } /** * Wrapper for \acp_modules::get_module_infos() * * @param string $class Module Class * @param string $basename Module Basename * @return array Module Information * @throws \phpbb\db\migration\exception */ protected function get_module_info($class, $basename) { if (!class_exists('acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); $this->user->add_lang('acp/modules'); } $acp_modules = new \acp_modules(); $module = $acp_modules->get_module_infos($basename, $class, true); if (empty($module)) { throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename); } return array_pop($module); } } migration/tool/permission.php000077700000040206151514672100012426 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\tool; /** * Migration permission management tool */ class permission implements \phpbb\db\migration\tool\tool_interface { /** @var \phpbb\auth\auth */ protected $auth; /** @var \phpbb\cache\service */ protected $cache; /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var string */ protected $phpbb_root_path; /** @var string */ protected $php_ext; /** * Constructor * * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\cache\service $cache * @param \phpbb\auth\auth $auth * @param string $phpbb_root_path * @param string $php_ext */ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\auth\auth $auth, $phpbb_root_path, $php_ext) { $this->db = $db; $this->cache = $cache; $this->auth = $auth; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; } /** * {@inheritdoc} */ public function get_name() { return 'permission'; } /** * Permission Exists * * Check if a permission (auth) setting exists * * @param string $auth_option The name of the permission (auth) option * @param bool $global True for checking a global permission setting, * False for a local permission setting * @return bool true if it exists, false if not */ public function exists($auth_option, $global = true) { if ($global) { $type_sql = ' AND is_global = 1'; } else { $type_sql = ' AND is_local = 1'; } $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'" . $type_sql; $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); if ($row) { return true; } return false; } /** * Permission Add * * Add a permission (auth) option * * @param string $auth_option The name of the permission (auth) option * @param bool $global True for checking a global permission setting, * False for a local permission setting * @param int|false $copy_from If set, contains the id of the permission from which to copy the new one. * @return null */ public function add($auth_option, $global = true, $copy_from = false) { if ($this->exists($auth_option, $global)) { return; } // We've added permissions, so set to true to notify the user. $this->permissions_added = true; if (!class_exists('auth_admin')) { include($this->phpbb_root_path . 'includes/acp/auth.' . $this->php_ext); } $auth_admin = new \auth_admin(); // We have to add a check to see if the !$global (if global, local, and if local, global) permission already exists. If it does, acl_add_option currently has a bug which would break the ACL system, so we are having a work-around here. if ($this->exists($auth_option, !$global)) { $sql_ary = array( 'is_global' => 1, 'is_local' => 1, ); $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . " WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'"; $this->db->sql_query($sql); } else { if ($global) { $auth_admin->acl_add_option(array('global' => array($auth_option))); } else { $auth_admin->acl_add_option(array('local' => array($auth_option))); } } // The permission has been added, now we can copy it if needed if ($copy_from && isset($auth_admin->acl_options['id'][$copy_from])) { $old_id = $auth_admin->acl_options['id'][$copy_from]; $new_id = $auth_admin->acl_options['id'][$auth_option]; $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE); foreach ($tables as $table) { $sql = 'SELECT * FROM ' . $table . ' WHERE auth_option_id = ' . $old_id; $result = $this->db->sql_query($sql); $sql_ary = array(); while ($row = $this->db->sql_fetchrow($result)) { $row['auth_option_id'] = $new_id; $sql_ary[] = $row; } $this->db->sql_freeresult($result); if (!empty($sql_ary)) { $this->db->sql_multi_insert($table, $sql_ary); } } $auth_admin->acl_clear_prefetch(); } } /** * Permission Remove * * Remove a permission (auth) option * * @param string $auth_option The name of the permission (auth) option * @param bool $global True for checking a global permission setting, * False for a local permission setting * @return null */ public function remove($auth_option, $global = true) { if (!$this->exists($auth_option, $global)) { return; } if ($global) { $type_sql = ' AND is_global = 1'; } else { $type_sql = ' AND is_local = 1'; } $sql = 'SELECT auth_option_id, is_global, is_local FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'" . $type_sql; $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); $id = (int) $row['auth_option_id']; // If it is a local and global permission, do not remove the row! :P if ($row['is_global'] && $row['is_local']) { $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' SET ' . (($global) ? 'is_global = 0' : 'is_local = 0') . ' WHERE auth_option_id = ' . $id; $this->db->sql_query($sql); } else { // Delete time $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE, ACL_OPTIONS_TABLE); foreach ($tables as $table) { $this->db->sql_query('DELETE FROM ' . $table . ' WHERE auth_option_id = ' . $id); } } // Purge the auth cache $this->cache->destroy('_acl_options'); $this->auth->acl_clear_prefetch(); } /** * Add a new permission role * * @param string $role_name The new role name * @param string $role_type The type (u_, m_, a_) * @param string $role_description Description of the new role * * @return null */ public function role_add($role_name, $role_type, $role_description = '') { $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = '" . $this->db->sql_escape($role_name) . "'"; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('role_id'); if ($role_id) { return; } $sql = 'SELECT MAX(role_order) AS max_role_order FROM ' . ACL_ROLES_TABLE . " WHERE role_type = '" . $this->db->sql_escape($role_type) . "'"; $this->db->sql_query($sql); $role_order = (int) $this->db->sql_fetchfield('max_role_order'); $role_order = (!$role_order) ? 1 : $role_order + 1; $sql_ary = array( 'role_name' => $role_name, 'role_description' => $role_description, 'role_type' => $role_type, 'role_order' => $role_order, ); $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary); $this->db->sql_query($sql); } /** * Update the name on a permission role * * @param string $old_role_name The old role name * @param string $new_role_name The new role name * @return null * @throws \phpbb\db\migration\exception */ public function role_update($old_role_name, $new_role_name) { $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = '" . $this->db->sql_escape($old_role_name) . "'"; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('role_id'); if (!$role_id) { throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $old_role_name); } $sql = 'UPDATE ' . ACL_ROLES_TABLE . " SET role_name = '" . $this->db->sql_escape($new_role_name) . "' WHERE role_name = '" . $this->db->sql_escape($old_role_name) . "'"; $this->db->sql_query($sql); } /** * Remove a permission role * * @param string $role_name The role name to remove * @return null */ public function role_remove($role_name) { $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = '" . $this->db->sql_escape($role_name) . "'"; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('role_id'); if (!$role_id) { return; } $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' WHERE role_id = ' . $role_id; $this->db->sql_query($sql); $sql = 'DELETE FROM ' . ACL_ROLES_TABLE . ' WHERE role_id = ' . $role_id; $this->db->sql_query($sql); $this->auth->acl_clear_prefetch(); } /** * Permission Set * * Allows you to set permissions for a certain group/role * * @param string $name The name of the role/group * @param string|array $auth_option The auth_option or array of * auth_options you would like to set * @param string $type The type (role|group) * @param bool $has_permission True if you want to give them permission, * false if you want to deny them permission * @return null * @throws \phpbb\db\migration\exception */ public function permission_set($name, $auth_option, $type = 'role', $has_permission = true) { if (!is_array($auth_option)) { $auth_option = array($auth_option); } $new_auth = array(); $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . ' WHERE ' . $this->db->sql_in_set('auth_option', $auth_option); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $new_auth[] = (int) $row['auth_option_id']; } $this->db->sql_freeresult($result); if (empty($new_auth)) { return; } $current_auth = array(); $type = (string) $type; // Prevent PHP bug. switch ($type) { case 'role': $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('role_id'); if (!$role_id) { throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name); } $sql = 'SELECT auth_option_id, auth_setting FROM ' . ACL_ROLES_DATA_TABLE . ' WHERE role_id = ' . $role_id; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $current_auth[$row['auth_option_id']] = $row['auth_setting']; } $this->db->sql_freeresult($result); break; case 'group': $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); $group_id = (int) $this->db->sql_fetchfield('group_id'); if (!$group_id) { throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name); } // If the group has a role set for them we will add the requested permissions to that role. $sql = 'SELECT auth_role_id FROM ' . ACL_GROUPS_TABLE . ' WHERE group_id = ' . $group_id . ' AND auth_role_id <> 0 AND forum_id = 0'; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('auth_role_id'); if ($role_id) { $sql = 'SELECT role_name, role_type FROM ' . ACL_ROLES_TABLE . ' WHERE role_id = ' . $role_id; $this->db->sql_query($sql); $role_data = $this->db->sql_fetchrow(); $role_name = $role_data['role_name']; $role_type = $role_data['role_type']; // Filter new auth options to match the role type: a_ | f_ | m_ | u_ // Set new auth options to the role only if options matching the role type were found $auth_option = array_filter($auth_option, function ($option) use ($role_type) { return strpos($option, $role_type) === 0; } ); if (sizeof($auth_option)) { return $this->permission_set($role_name, $auth_option, 'role', $has_permission); } } $sql = 'SELECT auth_option_id, auth_setting FROM ' . ACL_GROUPS_TABLE . ' WHERE group_id = ' . $group_id; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $current_auth[$row['auth_option_id']] = $row['auth_setting']; } $this->db->sql_freeresult($result); break; } $sql_ary = array(); switch ($type) { case 'role': foreach ($new_auth as $auth_option_id) { if (!isset($current_auth[$auth_option_id])) { $sql_ary[] = array( 'role_id' => $role_id, 'auth_option_id' => $auth_option_id, 'auth_setting' => $has_permission, ); } } $this->db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary); break; case 'group': foreach ($new_auth as $auth_option_id) { if (!isset($current_auth[$auth_option_id])) { $sql_ary[] = array( 'group_id' => $group_id, 'auth_option_id' => $auth_option_id, 'auth_setting' => $has_permission, ); } } $this->db->sql_multi_insert(ACL_GROUPS_TABLE, $sql_ary); break; } $this->auth->acl_clear_prefetch(); } /** * Permission Unset * * Allows you to unset (remove) permissions for a certain group/role * * @param string $name The name of the role/group * @param string|array $auth_option The auth_option or array of * auth_options you would like to set * @param string $type The type (role|group) * @return null * @throws \phpbb\db\migration\exception */ public function permission_unset($name, $auth_option, $type = 'role') { if (!is_array($auth_option)) { $auth_option = array($auth_option); } $to_remove = array(); $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . ' WHERE ' . $this->db->sql_in_set('auth_option', $auth_option); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $to_remove[] = (int) $row['auth_option_id']; } $this->db->sql_freeresult($result); if (empty($to_remove)) { return; } $type = (string) $type; // Prevent PHP bug. switch ($type) { case 'role': $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('role_id'); if (!$role_id) { throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name); } $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove) . ' AND role_id = ' . (int) $role_id; $this->db->sql_query($sql); break; case 'group': $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); $group_id = (int) $this->db->sql_fetchfield('group_id'); if (!$group_id) { throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name); } // If the group has a role set for them we will remove the requested permissions from that role. $sql = 'SELECT auth_role_id FROM ' . ACL_GROUPS_TABLE . ' WHERE group_id = ' . $group_id . ' AND auth_role_id <> 0'; $this->db->sql_query($sql); $role_id = (int) $this->db->sql_fetchfield('auth_role_id'); if ($role_id) { $sql = 'SELECT role_name FROM ' . ACL_ROLES_TABLE . ' WHERE role_id = ' . $role_id; $this->db->sql_query($sql); $role_name = $this->db->sql_fetchfield('role_name'); return $this->permission_unset($role_name, $auth_option, 'role'); } $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove); $this->db->sql_query($sql); break; } $this->auth->acl_clear_prefetch(); } /** * {@inheritdoc} */ public function reverse() { $arguments = func_get_args(); $original_call = array_shift($arguments); $call = false; switch ($original_call) { case 'add': $call = 'remove'; break; case 'remove': $call = 'add'; break; case 'permission_set': $call = 'permission_unset'; break; case 'permission_unset': $call = 'permission_set'; break; case 'role_add': $call = 'role_remove'; break; case 'role_remove': $call = 'role_add'; break; case 'role_update': // Set to the original value if the current value is what we compared to originally $arguments = array( $arguments[1], $arguments[0], ); break; } if ($call) { return call_user_func_array(array(&$this, $call), $arguments); } } } migration/container_aware_migration.php000077700000001445151514672100014475 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Abstract base class for container aware database migrations. */ abstract class container_aware_migration extends migration implements ContainerAwareInterface { /** * @var ContainerInterface */ protected $container; /** * {@inheritdoc} */ public function setContainer(ContainerInterface $container = null) { $this->container = $container; } } migration/schema_generator.php000077700000013322151514672100012566 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; /** * The schema generator generates the schema based on the existing migrations */ class schema_generator { /** @var \phpbb\config\config */ protected $config; /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var \phpbb\db\tools */ protected $db_tools; /** @var array */ protected $class_names; /** @var string */ protected $table_prefix; /** @var string */ protected $phpbb_root_path; /** @var string */ protected $php_ext; /** @var array */ protected $tables; /** @var array */ protected $dependencies = array(); /** * Constructor */ public function __construct(array $class_names, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix) { $this->config = $config; $this->db = $db; $this->db_tools = $db_tools; $this->class_names = $class_names; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->table_prefix = $table_prefix; } /** * Loads all migrations and their application state from the database. * * @return array */ public function get_schema() { if (!empty($this->tables)) { return $this->tables; } $migrations = $this->class_names; $tree = array(); $check_dependencies = true; while (!empty($migrations)) { foreach ($migrations as $migration_class) { $open_dependencies = array_diff($migration_class::depends_on(), $tree); if (empty($open_dependencies)) { $migration = new $migration_class($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); $tree[] = $migration_class; $migration_key = array_search($migration_class, $migrations); foreach ($migration->update_schema() as $change_type => $data) { if ($change_type === 'add_tables') { foreach ($data as $table => $table_data) { $this->tables[$table] = $table_data; } } else if ($change_type === 'drop_tables') { foreach ($data as $table) { unset($this->tables[$table]); } } else if ($change_type === 'add_columns') { foreach ($data as $table => $add_columns) { foreach ($add_columns as $column => $column_data) { if (isset($column_data['after'])) { $columns = $this->tables[$table]['COLUMNS']; $offset = array_search($column_data['after'], array_keys($columns)); unset($column_data['after']); if ($offset === false) { $this->tables[$table]['COLUMNS'][$column] = array_values($column_data); } else { $this->tables[$table]['COLUMNS'] = array_merge(array_slice($columns, 0, $offset + 1, true), array($column => array_values($column_data)), array_slice($columns, $offset)); } } else { $this->tables[$table]['COLUMNS'][$column] = $column_data; } } } } else if ($change_type === 'change_columns') { foreach ($data as $table => $change_columns) { foreach ($change_columns as $column => $column_data) { $this->tables[$table]['COLUMNS'][$column] = $column_data; } } } else if ($change_type === 'drop_columns') { foreach ($data as $table => $drop_columns) { if (is_array($drop_columns)) { foreach ($drop_columns as $column) { unset($this->tables[$table]['COLUMNS'][$column]); } } else { unset($this->tables[$table]['COLUMNS'][$drop_columns]); } } } else if ($change_type === 'add_unique_index') { foreach ($data as $table => $add_index) { foreach ($add_index as $key => $index_data) { $this->tables[$table]['KEYS'][$key] = array('UNIQUE', $index_data); } } } else if ($change_type === 'add_index') { foreach ($data as $table => $add_index) { foreach ($add_index as $key => $index_data) { $this->tables[$table]['KEYS'][$key] = array('INDEX', $index_data); } } } else if ($change_type === 'drop_keys') { foreach ($data as $table => $drop_keys) { foreach ($drop_keys as $key) { unset($this->tables[$table]['KEYS'][$key]); } } } else { var_dump($change_type); } } unset($migrations[$migration_key]); } else if ($check_dependencies) { $this->dependencies = array_merge($this->dependencies, $open_dependencies); } } // Only run this check after the first run if ($check_dependencies) { $this->check_dependencies(); $check_dependencies = false; } } ksort($this->tables); return $this->tables; } /** * Check if one of the migrations files' dependencies can't be resolved * by the supplied list of migrations * * @throws \UnexpectedValueException If a dependency can't be resolved */ protected function check_dependencies() { // Strip duplicate values from array $this->dependencies = array_unique($this->dependencies); foreach ($this->dependencies as $dependency) { if (!in_array($dependency, $this->class_names)) { throw new \UnexpectedValueException("Unable to resolve the dependency '$dependency'"); } } } } migration/data/v30x/release_3_0_13.php000077700000001601151514672100013352 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_13 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.13', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_13_rc1'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.13', '<'), array('config.update', array('version', '3.0.13')), )), ); } } migration/data/v30x/release_3_0_6_rc1.php000077700000025075151514672100014054 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_6_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.6-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_5'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'confirm' => array( 'attempts' => array('UINT', 0), ), $this->table_prefix . 'users' => array( 'user_new' => array('BOOL', 1), 'user_reminded' => array('TINT:4', 0), 'user_reminded_time' => array('TIMESTAMP', 0), ), $this->table_prefix . 'groups' => array( 'group_skip_auth' => array('BOOL', 0, 'after' => 'group_founder_manage'), ), $this->table_prefix . 'privmsgs' => array( 'message_reported' => array('BOOL', 0), ), $this->table_prefix . 'reports' => array( 'pm_id' => array('UINT', 0), ), $this->table_prefix . 'profile_fields' => array( 'field_show_on_vt' => array('BOOL', 0), ), $this->table_prefix . 'forums' => array( 'forum_options' => array('UINT:20', 0), ), ), 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_options' => array('UINT:11', 230271), ), ), 'add_index' => array( $this->table_prefix . 'reports' => array( 'post_id' => array('post_id'), 'pm_id' => array('pm_id'), ), $this->table_prefix . 'posts' => array( 'post_username' => array('post_username:255'), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'confirm' => array( 'attempts', ), $this->table_prefix . 'users' => array( 'user_new', 'user_reminded', 'user_reminded_time', ), $this->table_prefix . 'groups' => array( 'group_skip_auth', ), $this->table_prefix . 'privmsgs' => array( 'message_reported', ), $this->table_prefix . 'reports' => array( 'pm_id', ), $this->table_prefix . 'profile_fields' => array( 'field_show_on_vt', ), $this->table_prefix . 'forums' => array( 'forum_options', ), ), 'drop_keys' => array( $this->table_prefix . 'reports' => array( 'post_id', 'pm_id', ), $this->table_prefix . 'posts' => array( 'post_username', ), ), ); } public function update_data() { return array( array('config.add', array('captcha_plugin', 'phpbb_captcha_nogd')), array('if', array( ($this->config['captcha_gd']), array('config.update', array('captcha_plugin', 'phpbb_captcha_gd')), )), array('config.add', array('feed_enable', 0)), array('config.add', array('feed_limit', 10)), array('config.add', array('feed_overall_forums', 1)), array('config.add', array('feed_overall_forums_limit', 15)), array('config.add', array('feed_overall_topics', 0)), array('config.add', array('feed_overall_topics_limit', 15)), array('config.add', array('feed_forum', 1)), array('config.add', array('feed_topic', 1)), array('config.add', array('feed_item_statistics', 1)), array('config.add', array('smilies_per_page', 50)), array('config.add', array('allow_pm_report', 1)), array('config.add', array('min_post_chars', 1)), array('config.add', array('allow_quick_reply', 1)), array('config.add', array('new_member_post_limit', 0)), array('config.add', array('new_member_group_default', 0)), array('config.add', array('delete_time', $this->config['edit_time'])), array('config.add', array('allow_avatar', 0)), array('if', array( ($this->config['allow_avatar_upload'] || $this->config['allow_avatar_local'] || $this->config['allow_avatar_remote']), array('config.update', array('allow_avatar', 1)), )), array('config.add', array('allow_avatar_remote_upload', 0)), array('if', array( ($this->config['allow_avatar_remote'] && $this->config['allow_avatar_upload']), array('config.update', array('allow_avatar_remote_upload', 1)), )), array('module.add', array( 'acp', 'ACP_BOARD_CONFIGURATION', array( 'module_basename' => 'acp_board', 'modes' => array('feed'), ), )), array('module.add', array( 'acp', 'ACP_CAT_USERS', array( 'module_basename' => 'acp_users', 'modes' => array('warnings'), ), )), array('module.add', array( 'acp', 'ACP_SERVER_CONFIGURATION', array( 'module_basename' => 'acp_send_statistics', 'modes' => array('send_statistics'), ), )), array('module.add', array( 'acp', 'ACP_FORUM_BASED_PERMISSIONS', array( 'module_basename' => 'acp_permissions', 'modes' => array('setting_forum_copy'), ), )), array('module.add', array( 'mcp', 'MCP_REPORTS', array( 'module_basename' => 'mcp_pm_reports', 'modes' => array('pm_reports','pm_reports_closed','pm_report_details'), ), )), array('custom', array(array(&$this, 'add_newly_registered_group'))), array('custom', array(array(&$this, 'set_user_options_default'))), array('config.update', array('version', '3.0.6-RC1')), ); } public function set_user_options_default() { // 229376 is the added value to enable all three signature options $sql = 'UPDATE ' . USERS_TABLE . ' SET user_options = user_options + 229376'; $this->sql_query($sql); } public function add_newly_registered_group() { // Add newly_registered group... but check if it already exists (we always supported running the updater on any schema) $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'NEWLY_REGISTERED'"; $result = $this->db->sql_query($sql); $group_id = (int) $this->db->sql_fetchfield('group_id'); $this->db->sql_freeresult($result); if (!$group_id) { $sql = 'INSERT INTO ' . GROUPS_TABLE . " (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5)"; $this->sql_query($sql); $group_id = $this->db->sql_nextid(); } // Insert new user role... at the end of the chain $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = 'ROLE_USER_NEW_MEMBER' AND role_type = 'u_'"; $result = $this->db->sql_query($sql); $u_role = (int) $this->db->sql_fetchfield('role_id'); $this->db->sql_freeresult($result); if (!$u_role) { $sql = 'SELECT MAX(role_order) as max_order_id FROM ' . ACL_ROLES_TABLE . " WHERE role_type = 'u_'"; $result = $this->db->sql_query($sql); $next_order_id = (int) $this->db->sql_fetchfield('max_order_id'); $this->db->sql_freeresult($result); $next_order_id++; $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_USER_NEW_MEMBER', 'ROLE_DESCRIPTION_USER_NEW_MEMBER', 'u_', $next_order_id)"; $this->sql_query($sql); $u_role = $this->db->sql_nextid(); // Now add the correct data to the roles... // The standard role says that new users are not able to send a PM, Mass PM, are not able to PM groups $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $u_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group')"; $this->sql_query($sql); // Add user role to group $sql = 'INSERT INTO ' . ACL_GROUPS_TABLE . " (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES ($group_id, 0, 0, $u_role, 0)"; $this->sql_query($sql); } // Insert new forum role $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_name = 'ROLE_FORUM_NEW_MEMBER' AND role_type = 'f_'"; $result = $this->db->sql_query($sql); $f_role = (int) $this->db->sql_fetchfield('role_id'); $this->db->sql_freeresult($result); if (!$f_role) { $sql = 'SELECT MAX(role_order) as max_order_id FROM ' . ACL_ROLES_TABLE . " WHERE role_type = 'f_'"; $result = $this->db->sql_query($sql); $next_order_id = (int) $this->db->sql_fetchfield('max_order_id'); $this->db->sql_freeresult($result); $next_order_id++; $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', $next_order_id)"; $this->sql_query($sql); $f_role = $this->db->sql_nextid(); $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $f_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove')"; $this->sql_query($sql); } // Set every members user_new column to 0 (old users) only if there is no one yet (this makes sure we do not execute this more than once) $sql = 'SELECT 1 FROM ' . USERS_TABLE . ' WHERE user_new = 0'; $result = $this->db->sql_query_limit($sql, 1); $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); if (!$row) { $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new = 0'; $this->sql_query($sql); } // To mimick the old "feature" we will assign the forum role to every forum, regardless of the setting (this makes sure there are no "this does not work!!!! YUO!!!" posts... // Check if the role is already assigned... $sql = 'SELECT forum_id FROM ' . ACL_GROUPS_TABLE . ' WHERE group_id = ' . $group_id . ' AND auth_role_id = ' . $f_role; $result = $this->db->sql_query($sql); $is_options = (int) $this->db->sql_fetchfield('forum_id'); $this->db->sql_freeresult($result); // Not assigned at all... :/ if (!$is_options) { // Get postable forums $sql = 'SELECT forum_id FROM ' . FORUMS_TABLE . ' WHERE forum_type != ' . FORUM_LINK; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $this->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (' . $group_id . ', ' . (int) $row['forum_id'] . ', 0, ' . $f_role . ', 0)'); } $this->db->sql_freeresult($result); } // Clear permissions... include_once($this->phpbb_root_path . 'includes/acp/auth.' . $this->php_ext); $auth_admin = new \auth_admin(); $auth_admin->acl_clear_prefetch(); } } migration/data/v30x/release_3_0_14.php000077700000001601151514672100013353 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_14 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.14', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_14_rc1'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.14', '<'), array('config.update', array('version', '3.0.14')), )), ); } } migration/data/v30x/release_3_0_2_rc1.php000077700000001707151514672100014044 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_2_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.2-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_1'); } public function update_data() { return array( array('config.add', array('referer_validation', '1')), array('config.add', array('check_attachment_content', '1')), array('config.add', array('mime_triggers', 'body|head|html|img|plaintext|a href|pre|script|table|title')), array('config.update', array('version', '3.0.2-RC1')), ); } } migration/data/v30x/release_3_0_9_rc4.php000077700000001342151514672100014051 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_9_rc4 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.9-RC4', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_9_rc3'); } public function update_data() { return array( array('config.update', array('version', '3.0.9-RC4')), ); } } migration/data/v30x/release_3_0_9_rc3.php000077700000001342151514672100014050 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_9_rc3 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.9-RC3', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_9_rc2'); } public function update_data() { return array( array('config.update', array('version', '3.0.9-RC3')), ); } } migration/data/v30x/release_3_0_12_rc1.php000077700000003315151514672100014122 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; /** @todo DROP LOGIN_ATTEMPT_TABLE.attempt_id in 3.0.12-RC1 **/ class release_3_0_12_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.12-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_data() { return array( array('custom', array(array(&$this, 'update_module_auth'))), array('custom', array(array(&$this, 'disable_bots_from_receiving_pms'))), array('config.update', array('version', '3.0.12-RC1')), ); } public function disable_bots_from_receiving_pms() { // Disable receiving pms for bots $sql = 'SELECT user_id FROM ' . BOTS_TABLE; $result = $this->db->sql_query($sql); $bot_user_ids = array(); while ($row = $this->db->sql_fetchrow($result)) { $bot_user_ids[] = (int) $row['user_id']; } $this->db->sql_freeresult($result); if (!empty($bot_user_ids)) { $sql = 'UPDATE ' . USERS_TABLE . ' SET user_allow_pm = 0 WHERE ' . $this->db->sql_in_set('user_id', $bot_user_ids); $this->sql_query($sql); } } public function update_module_auth() { $sql = 'UPDATE ' . MODULES_TABLE . ' SET module_auth = \'acl_u_sig\' WHERE module_class = \'ucp\' AND module_basename = \'profile\' AND module_mode = \'signature\''; $this->sql_query($sql); } } migration/data/v30x/release_3_0_4.php000077700000002437151514672100013302 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_4 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.4', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_4_rc1'); } public function update_data() { return array( array('custom', array(array(&$this, 'rename_log_delete_topic'))), array('config.update', array('version', '3.0.4')), ); } public function rename_log_delete_topic() { if ($this->db->get_sql_layer() == 'oracle') { // log_operation is CLOB - but we can change this later $sql = 'UPDATE ' . $this->table_prefix . "log SET log_operation = 'LOG_DELETE_TOPIC' WHERE log_operation LIKE 'LOG_TOPIC_DELETED'"; $this->sql_query($sql); } else { $sql = 'UPDATE ' . $this->table_prefix . "log SET log_operation = 'LOG_DELETE_TOPIC' WHERE log_operation = 'LOG_TOPIC_DELETED'"; $this->sql_query($sql); } } } migration/data/v30x/release_3_0_3.php000077700000001326151514672100013275 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_3 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.3', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_3_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.3')), ); } } migration/data/v30x/release_3_0_10_rc2.php000077700000001346151514672100014123 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_10_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.10-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_10_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.10-RC2')), ); } } migration/data/v30x/release_3_0_9_rc2.php000077700000001342151514672100014047 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_9_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.9-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_9_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.9-RC2')), ); } } migration/data/v30x/release_3_0_12.php000077700000001601151514672100013351 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_12 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.12', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_12_rc3'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.12', '<'), array('config.update', array('version', '3.0.12')), )), ); } } migration/data/v30x/release_3_0_11_rc2.php000077700000002145151514672100014122 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_11_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.11-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11_rc1'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_novalue' => array('BOOL', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_novalue', ), ), ); } public function update_data() { return array( array('config.update', array('version', '3.0.11-RC2')), ); } } migration/data/v30x/release_3_0_7_rc1.php000077700000004077151514672100014054 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_7_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.7-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_6'); } public function update_schema() { return array( 'drop_keys' => array( $this->table_prefix . 'log' => array( 'log_time', ), ), 'add_index' => array( $this->table_prefix . 'topics_track' => array( 'topic_id' => array('topic_id'), ), ), ); } public function revert_schema() { return array( 'add_index' => array( $this->table_prefix . 'log' => array( 'log_time' => array('log_time'), ), ), 'drop_keys' => array( $this->table_prefix . 'topics_track' => array( 'topic_id', ), ), ); } public function update_data() { return array( array('config.add', array('feed_overall', 1)), array('config.add', array('feed_http_auth', 0)), array('config.add', array('feed_limit_post', $this->config['feed_limit'])), array('config.add', array('feed_limit_topic', $this->config['feed_overall_topics_limit'])), array('config.add', array('feed_topics_new', $this->config['feed_overall_topics'])), array('config.add', array('feed_topics_active', $this->config['feed_overall_topics'])), array('custom', array(array(&$this, 'delete_text_templates'))), array('config.update', array('version', '3.0.7-RC1')), ); } public function delete_text_templates() { // Delete all text-templates from the template_data $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . ' WHERE template_filename ' . $this->db->sql_like_expression($this->db->get_any_char() . '.txt'); $this->sql_query($sql); } } migration/data/v30x/release_3_0_3_rc1.php000077700000004654151514672100014051 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_3_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.3-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_2'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'styles_template' => array( 'template_inherits_id' => array('UINT:4', 0), 'template_inherit_path' => array('VCHAR', ''), ), $this->table_prefix . 'groups' => array( 'group_max_recipients' => array('UINT', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'styles_template' => array( 'template_inherits_id', 'template_inherit_path', ), $this->table_prefix . 'groups' => array( 'group_max_recipients', ), ), ); } public function update_data() { return array( array('config.add', array('enable_queue_trigger', '0')), array('config.add', array('queue_trigger_posts', '3')), array('config.add', array('pm_max_recipients', '0')), array('custom', array(array(&$this, 'set_group_default_max_recipients'))), array('config.add', array('dbms_version', $this->db->sql_server_info(true))), array('permission.add', array('u_masspm_group', true, 'u_masspm')), array('custom', array(array(&$this, 'correct_acp_email_permissions'))), array('config.update', array('version', '3.0.3-RC1')), ); } public function correct_acp_email_permissions() { $sql = 'UPDATE ' . $this->table_prefix . 'modules SET module_auth = \'acl_a_email && cfg_email_enable\' WHERE module_class = \'acp\' AND module_basename = \'email\''; $this->sql_query($sql); } public function set_group_default_max_recipients() { // Set maximum number of recipients for the registered users, bots, guests group $sql = 'UPDATE ' . GROUPS_TABLE . ' SET group_max_recipients = 5 WHERE ' . $this->db->sql_in_set('group_name', array('GUESTS', 'REGISTERED', 'REGISTERED_COPPA', 'BOTS')); $this->sql_query($sql); } } migration/data/v30x/release_3_0_10_rc3.php000077700000001346151514672100014124 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_10_rc3 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.10-RC3', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_10_rc2'); } public function update_data() { return array( array('config.update', array('version', '3.0.10-RC3')), ); } } migration/data/v30x/local_url_bbcode.php000077700000003474151514672100014252 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class local_url_bbcode extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_12_rc1'); } public function update_data() { return array( array('custom', array(array($this, 'update_local_url_bbcode'))), ); } /** * Update BBCodes that currently use the LOCAL_URL tag * * To fix http://tracker.phpbb.com/browse/PHPBB3-8319 we changed * the second_pass_replace value, so that needs updating for existing ones */ public function update_local_url_bbcode() { $sql = 'SELECT * FROM ' . BBCODES_TABLE . ' WHERE bbcode_match ' . $this->db->sql_like_expression($this->db->get_any_char() . 'LOCAL_URL' . $this->db->get_any_char()); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (!class_exists('acp_bbcodes')) { if (function_exists('phpbb_require_updated')) { phpbb_require_updated('includes/acp/acp_bbcodes.' . $this->php_ext); } else { require($this->phpbb_root_path . 'includes/acp/acp_bbcodes.' . $this->php_ext); } } $bbcode_match = $row['bbcode_match']; $bbcode_tpl = $row['bbcode_tpl']; $acp_bbcodes = new \acp_bbcodes(); $sql_ary = $acp_bbcodes->build_regexp($bbcode_match, $bbcode_tpl); $sql = 'UPDATE ' . BBCODES_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE bbcode_id = ' . (int) $row['bbcode_id']; $this->sql_query($sql); } $this->db->sql_freeresult($result); } } migration/data/v30x/release_3_0_2.php000077700000001326151514672100013274 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_2_rc2'); } public function update_data() { return array( array('config.update', array('version', '3.0.2')), ); } } migration/data/v30x/release_3_0_13_rc1.php000077700000001615151514672100014124 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_13_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.13-RC1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_12'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.13-RC1', '<'), array('config.update', array('version', '3.0.13-RC1')), )), ); } } migration/data/v30x/release_3_0_5.php000077700000001333151514672100013275 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_5 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.5', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_5_rc1part2'); } public function update_data() { return array( array('config.update', array('version', '3.0.5')), ); } } migration/data/v30x/release_3_0_7_rc2.php000077700000003606151514672100014052 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_7_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.7-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_7_rc1'); } public function update_data() { return array( array('custom', array(array(&$this, 'update_email_hash'))), array('config.update', array('version', '3.0.7-RC2')), ); } public function update_email_hash($start = 0) { $limit = 1000; $sql = 'SELECT user_id, user_email, user_email_hash FROM ' . USERS_TABLE . ' WHERE user_type <> ' . USER_IGNORE . " AND user_email <> ''"; $result = $this->db->sql_query_limit($sql, $limit, $start); $i = 0; while ($row = $this->db->sql_fetchrow($result)) { $i++; // Snapshot of the phpbb_email_hash() function // We cannot call it directly because the auto updater updates the DB first. :/ $user_email_hash = sprintf('%u', crc32(strtolower($row['user_email']))) . strlen($row['user_email']); if ($user_email_hash != $row['user_email_hash']) { $sql_ary = array( 'user_email_hash' => $user_email_hash, ); $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . (int) $row['user_id']; $this->sql_query($sql); } } $this->db->sql_freeresult($result); if ($i < $limit) { // Completed return; } // Return the next start, will be sent to $start when this function is called again return $start + $limit; } } migration/data/v30x/release_3_0_6.php000077700000001326151514672100013300 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_6 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.6', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_6_rc4'); } public function update_data() { return array( array('config.update', array('version', '3.0.6')), ); } } migration/data/v30x/release_3_0_1.php000077700000001326151514672100013273 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_1_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.1')), ); } } migration/data/v30x/release_3_0_8.php000077700000001326151514672100013302 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_8 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.8', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_8_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.8')), ); } } migration/data/v30x/release_3_0_5_rc1.php000077700000010043151514672100014040 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; use phpbb\db\migration\container_aware_migration; class release_3_0_5_rc1 extends container_aware_migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.5-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_4'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'forums' => array( 'forum_style' => array('UINT', 0), ), ), ); } public function update_data() { $search_indexing_state = $this->config['search_indexing_state']; return array( array('config.add', array('captcha_gd_wave', 0)), array('config.add', array('captcha_gd_3d_noise', 1)), array('config.add', array('captcha_gd_fonts', 1)), array('config.add', array('confirm_refresh', 1)), array('config.add', array('max_num_search_keywords', 10)), array('config.remove', array('search_indexing_state')), array('config.add', array('search_indexing_state', $search_indexing_state, true)), array('custom', array(array(&$this, 'hash_old_passwords'))), array('custom', array(array(&$this, 'update_ichiro_bot'))), ); } public function hash_old_passwords() { $passwords_manager = $this->container->get('passwords.manager'); $sql = 'SELECT user_id, user_password FROM ' . $this->table_prefix . 'users WHERE user_pass_convert = 1'; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (strlen($row['user_password']) == 32) { $sql_ary = array( 'user_password' => '$CP$' . $passwords_manager->hash($row['user_password'], 'passwords.driver.salted_md5'), ); $this->sql_query('UPDATE ' . $this->table_prefix . 'users SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id']); } } $this->db->sql_freeresult($result); } public function update_ichiro_bot() { // Adjust bot entry $sql = 'UPDATE ' . $this->table_prefix . "bots SET bot_agent = 'ichiro/' WHERE bot_agent = 'ichiro/2'"; $this->sql_query($sql); } public function remove_duplicate_auth_options() { // Before we are able to add a unique key to auth_option, we need to remove duplicate entries $sql = 'SELECT auth_option FROM ' . $this->table_prefix . 'acl_options GROUP BY auth_option HAVING COUNT(*) >= 2'; $result = $this->db->sql_query($sql); $auth_options = array(); while ($row = $this->db->sql_fetchrow($result)) { $auth_options[] = $row['auth_option']; } $this->db->sql_freeresult($result); // Remove specific auth options if (!empty($auth_options)) { foreach ($auth_options as $option) { // Select auth_option_ids... the largest id will be preserved $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option = '" . $this->db->sql_escape($option) . "' ORDER BY auth_option_id DESC"; // sql_query_limit not possible here, due to bug in postgresql layer $result = $this->db->sql_query($sql); // Skip first row, this is our original auth option we want to preserve $row = $this->db->sql_fetchrow($result); while ($row = $this->db->sql_fetchrow($result)) { // Ok, remove this auth option... $this->sql_query('DELETE FROM ' . ACL_OPTIONS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id']); $this->sql_query('DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id']); $this->sql_query('DELETE FROM ' . ACL_GROUPS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id']); $this->sql_query('DELETE FROM ' . ACL_USERS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id']); } $this->db->sql_freeresult($result); } } } } migration/data/v30x/release_3_0_13_pl1.php000077700000001615151514672100014133 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_13_pl1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.13-PL1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_13'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.13-PL1', '<'), array('config.update', array('version', '3.0.13-PL1')), )), ); } } migration/data/v30x/release_3_0_1_rc1.php000077700000006137151514672100014045 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_1_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.1-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_0'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'forums' => array( 'display_subforum_list' => array('BOOL', 1), ), $this->table_prefix . 'sessions' => array( 'session_forum_id' => array('UINT', 0), ), ), 'drop_keys' => array( $this->table_prefix . 'groups' => array( 'group_legend', ), ), 'add_index' => array( $this->table_prefix . 'sessions' => array( 'session_forum_id' => array('session_forum_id'), ), $this->table_prefix . 'groups' => array( 'group_legend_name' => array('group_legend', 'group_name'), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'forums' => array( 'display_subforum_list', ), $this->table_prefix . 'sessions' => array( 'session_forum_id', ), ), 'add_index' => array( $this->table_prefix . 'groups' => array( 'group_legend' => array('group_legend'), ), ), 'drop_keys' => array( $this->table_prefix . 'sessions' => array( 'session_forum_id', ), $this->table_prefix . 'groups' => array( 'group_legend_name', ), ), ); } public function update_data() { return array( array('custom', array(array(&$this, 'fix_unset_last_view_time'))), array('custom', array(array(&$this, 'reset_smiley_size'))), array('config.update', array('version', '3.0.1-RC1')), ); } public function fix_unset_last_view_time() { $sql = 'UPDATE ' . $this->table_prefix . "topics SET topic_last_view_time = topic_last_post_time WHERE topic_last_view_time = 0"; $this->sql_query($sql); } public function reset_smiley_size() { // Update smiley sizes $smileys = array('icon_e_surprised.gif', 'icon_eek.gif', 'icon_cool.gif', 'icon_lol.gif', 'icon_mad.gif', 'icon_razz.gif', 'icon_redface.gif', 'icon_cry.gif', 'icon_evil.gif', 'icon_twisted.gif', 'icon_rolleyes.gif', 'icon_exclaim.gif', 'icon_question.gif', 'icon_idea.gif', 'icon_arrow.gif', 'icon_neutral.gif', 'icon_mrgreen.gif', 'icon_e_ugeek.gif'); foreach ($smileys as $smiley) { if (file_exists($this->phpbb_root_path . 'images/smilies/' . $smiley)) { list($width, $height) = getimagesize($this->phpbb_root_path . 'images/smilies/' . $smiley); $sql = 'UPDATE ' . SMILIES_TABLE . ' SET smiley_width = ' . $width . ', smiley_height = ' . $height . " WHERE smiley_url = '" . $this->db->sql_escape($smiley) . "'"; $this->sql_query($sql); } } } } migration/data/v30x/release_3_0_9_rc1.php000077700000007364151514672100014060 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_9_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.9-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_8'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'login_attempts' => array( 'COLUMNS' => array( // this column was removed from the database updater // after 3.0.9-RC3 was released. It might still exist // in 3.0.9-RCX installations and has to be dropped as // soon as the db_tools class is capable of properly // removing a primary key. // 'attempt_id' => array('UINT', NULL, 'auto_increment'), 'attempt_ip' => array('VCHAR:40', ''), 'attempt_browser' => array('VCHAR:150', ''), 'attempt_forwarded_for' => array('VCHAR:255', ''), 'attempt_time' => array('TIMESTAMP', 0), 'user_id' => array('UINT', 0), 'username' => array('VCHAR_UNI:255', 0), 'username_clean' => array('VCHAR_CI', 0), ), //'PRIMARY_KEY' => 'attempt_id', 'KEYS' => array( 'att_ip' => array('INDEX', array('attempt_ip', 'attempt_time')), 'att_for' => array('INDEX', array('attempt_forwarded_for', 'attempt_time')), 'att_time' => array('INDEX', array('attempt_time')), 'user_id' => array('INDEX', 'user_id'), ), ), ), 'change_columns' => array( $this->table_prefix . 'bbcodes' => array( 'bbcode_id' => array('USINT', 0), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'login_attempts', ), ); } public function update_data() { return array( array('config.add', array('ip_login_limit_max', 50)), array('config.add', array('ip_login_limit_time', 21600)), array('config.add', array('ip_login_limit_use_forwarded', 0)), array('custom', array(array(&$this, 'update_file_extension_group_names'))), array('custom', array(array(&$this, 'fix_firebird_qa_captcha'))), array('config.update', array('version', '3.0.9-RC1')), ); } public function update_file_extension_group_names() { // Update file extension group names to use language strings, again. $sql = 'SELECT group_id, group_name FROM ' . EXTENSION_GROUPS_TABLE . ' WHERE group_name ' . $this->db->sql_like_expression('EXT_GROUP_' . $this->db->get_any_char()); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $sql_ary = array( 'group_name' => substr($row['group_name'], 10), // Strip off 'EXT_GROUP_' ); $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE group_id = ' . $row['group_id']; $this->sql_query($sql); } $this->db->sql_freeresult($result); } public function fix_firebird_qa_captcha() { // Recover from potentially broken Q&A CAPTCHA table on firebird // Q&A CAPTCHA was uninstallable, so it's safe to remove these // without data loss if ($this->db_tools->sql_layer == 'firebird') { $tables = array( $this->table_prefix . 'captcha_questions', $this->table_prefix . 'captcha_answers', $this->table_prefix . 'qa_confirm', ); foreach ($tables as $table) { if ($this->db_tools->sql_table_exists($table)) { $this->db_tools->sql_table_drop($table); } } } } } migration/data/v30x/release_3_0_12_rc3.php000077700000001621151514672100014122 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_12_rc3 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.12-RC3', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_12_rc2'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.12-RC3', '<'), array('config.update', array('version', '3.0.12-RC3')), )), ); } } migration/data/v30x/release_3_0_11.php000077700000001332151514672100013351 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_11 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.11', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11_rc2'); } public function update_data() { return array( array('config.update', array('version', '3.0.11')), ); } } migration/data/v30x/release_3_0_6_rc4.php000077700000001342151514672100014046 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_6_rc4 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.6-RC4', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_6_rc3'); } public function update_data() { return array( array('config.update', array('version', '3.0.6-RC4')), ); } } migration/data/v30x/release_3_0_7_pl1.php000077700000001336151514672100014056 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_7_pl1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.7-pl1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_7'); } public function update_data() { return array( array('config.update', array('version', '3.0.7-pl1')), ); } } migration/data/v30x/release_3_0_11_rc1.php000077700000004705151514672100014125 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_11_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.11-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_10'); } public function update_data() { return array( array('custom', array(array(&$this, 'cleanup_deactivated_styles'))), array('custom', array(array(&$this, 'delete_orphan_private_messages'))), array('config.update', array('version', '3.0.11-RC1')), ); } public function cleanup_deactivated_styles() { // Updates users having current style a deactivated one $sql = 'SELECT style_id FROM ' . STYLES_TABLE . ' WHERE style_active = 0'; $result = $this->sql_query($sql); $deactivated_style_ids = array(); while ($style_id = $this->db->sql_fetchfield('style_id', false, $result)) { $deactivated_style_ids[] = (int) $style_id; } $this->db->sql_freeresult($result); if (!empty($deactivated_style_ids)) { $sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = ' . (int) $this->config['default_style'] .' WHERE ' . $this->db->sql_in_set('user_style', $deactivated_style_ids); $this->sql_query($sql); } } public function delete_orphan_private_messages() { // Delete orphan private messages $batch_size = 500; $sql_array = array( 'SELECT' => 'p.msg_id', 'FROM' => array( PRIVMSGS_TABLE => 'p', ), 'LEFT_JOIN' => array( array( 'FROM' => array(PRIVMSGS_TO_TABLE => 't'), 'ON' => 'p.msg_id = t.msg_id', ), ), 'WHERE' => 't.user_id IS NULL', ); $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query_limit($sql, $batch_size); $delete_pms = array(); while ($row = $this->db->sql_fetchrow($result)) { $delete_pms[] = (int) $row['msg_id']; } $this->db->sql_freeresult($result); if (!empty($delete_pms)) { $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' WHERE ' . $this->db->sql_in_set('msg_id', $delete_pms); $this->sql_query($sql); // Return false to have the Migrator call this function again return false; } } } migration/data/v30x/release_3_0_6_rc3.php000077700000002156151514672100014051 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_6_rc3 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.6-RC3', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_6_rc2'); } public function update_data() { return array( array('custom', array(array(&$this, 'update_cp_fields'))), array('config.update', array('version', '3.0.6-RC3')), ); } public function update_cp_fields() { // Update the Custom Profile Fields based on previous settings to the new \format $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . ' SET field_show_on_vt = 1 WHERE field_hide = 0 AND (field_required = 1 OR field_show_on_reg = 1 OR field_show_profile = 1)'; $this->sql_query($sql); } } migration/data/v30x/release_3_0_5_rc1part2.php000077700000002024151514672100015011 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_5_rc1part2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.5-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_5_rc1'); } public function update_schema() { return array( 'drop_keys' => array( $this->table_prefix . 'acl_options' => array('auth_option'), ), 'add_unique_index' => array( $this->table_prefix . 'acl_options' => array( 'auth_option' => array('auth_option'), ), ), ); } public function update_data() { return array( array('config.update', array('version', '3.0.5-RC1')), ); } } migration/data/v30x/release_3_0_9.php000077700000001326151514672100013303 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_9 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.9', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_9_rc4'); } public function update_data() { return array( array('config.update', array('version', '3.0.9')), ); } } migration/data/v30x/release_3_0_0.php000077700000122220151514672100013267 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_0 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.0', '>='); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'attachments' => array( 'COLUMNS' => array( 'attach_id' => array('UINT', NULL, 'auto_increment'), 'post_msg_id' => array('UINT', 0), 'topic_id' => array('UINT', 0), 'in_message' => array('BOOL', 0), 'poster_id' => array('UINT', 0), 'is_orphan' => array('BOOL', 1), 'physical_filename' => array('VCHAR', ''), 'real_filename' => array('VCHAR', ''), 'download_count' => array('UINT', 0), 'attach_comment' => array('TEXT_UNI', ''), 'extension' => array('VCHAR:100', ''), 'mimetype' => array('VCHAR:100', ''), 'filesize' => array('UINT:20', 0), 'filetime' => array('TIMESTAMP', 0), 'thumbnail' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'attach_id', 'KEYS' => array( 'filetime' => array('INDEX', 'filetime'), 'post_msg_id' => array('INDEX', 'post_msg_id'), 'topic_id' => array('INDEX', 'topic_id'), 'poster_id' => array('INDEX', 'poster_id'), 'is_orphan' => array('INDEX', 'is_orphan'), ), ), $this->table_prefix . 'acl_groups' => array( 'COLUMNS' => array( 'group_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'auth_option_id' => array('UINT', 0), 'auth_role_id' => array('UINT', 0), 'auth_setting' => array('TINT:2', 0), ), 'KEYS' => array( 'group_id' => array('INDEX', 'group_id'), 'auth_opt_id' => array('INDEX', 'auth_option_id'), 'auth_role_id' => array('INDEX', 'auth_role_id'), ), ), $this->table_prefix . 'acl_options' => array( 'COLUMNS' => array( 'auth_option_id' => array('UINT', NULL, 'auto_increment'), 'auth_option' => array('VCHAR:50', ''), 'is_global' => array('BOOL', 0), 'is_local' => array('BOOL', 0), 'founder_only' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'auth_option_id', 'KEYS' => array( 'auth_option' => array('INDEX', 'auth_option'), ), ), $this->table_prefix . 'acl_roles' => array( 'COLUMNS' => array( 'role_id' => array('UINT', NULL, 'auto_increment'), 'role_name' => array('VCHAR_UNI', ''), 'role_description' => array('TEXT_UNI', ''), 'role_type' => array('VCHAR:10', ''), 'role_order' => array('USINT', 0), ), 'PRIMARY_KEY' => 'role_id', 'KEYS' => array( 'role_type' => array('INDEX', 'role_type'), 'role_order' => array('INDEX', 'role_order'), ), ), $this->table_prefix . 'acl_roles_data' => array( 'COLUMNS' => array( 'role_id' => array('UINT', 0), 'auth_option_id' => array('UINT', 0), 'auth_setting' => array('TINT:2', 0), ), 'PRIMARY_KEY' => array('role_id', 'auth_option_id'), 'KEYS' => array( 'ath_op_id' => array('INDEX', 'auth_option_id'), ), ), $this->table_prefix . 'acl_users' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'auth_option_id' => array('UINT', 0), 'auth_role_id' => array('UINT', 0), 'auth_setting' => array('TINT:2', 0), ), 'KEYS' => array( 'user_id' => array('INDEX', 'user_id'), 'auth_option_id' => array('INDEX', 'auth_option_id'), 'auth_role_id' => array('INDEX', 'auth_role_id'), ), ), $this->table_prefix . 'banlist' => array( 'COLUMNS' => array( 'ban_id' => array('UINT', NULL, 'auto_increment'), 'ban_userid' => array('UINT', 0), 'ban_ip' => array('VCHAR:40', ''), 'ban_email' => array('VCHAR_UNI:100', ''), 'ban_start' => array('TIMESTAMP', 0), 'ban_end' => array('TIMESTAMP', 0), 'ban_exclude' => array('BOOL', 0), 'ban_reason' => array('VCHAR_UNI', ''), 'ban_give_reason' => array('VCHAR_UNI', ''), ), 'PRIMARY_KEY' => 'ban_id', 'KEYS' => array( 'ban_end' => array('INDEX', 'ban_end'), 'ban_user' => array('INDEX', array('ban_userid', 'ban_exclude')), 'ban_email' => array('INDEX', array('ban_email', 'ban_exclude')), 'ban_ip' => array('INDEX', array('ban_ip', 'ban_exclude')), ), ), $this->table_prefix . 'bbcodes' => array( 'COLUMNS' => array( 'bbcode_id' => array('TINT:3', 0), 'bbcode_tag' => array('VCHAR:16', ''), 'bbcode_helpline' => array('VCHAR_UNI', ''), 'display_on_posting' => array('BOOL', 0), 'bbcode_match' => array('TEXT_UNI', ''), 'bbcode_tpl' => array('MTEXT_UNI', ''), 'first_pass_match' => array('MTEXT_UNI', ''), 'first_pass_replace' => array('MTEXT_UNI', ''), 'second_pass_match' => array('MTEXT_UNI', ''), 'second_pass_replace' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'bbcode_id', 'KEYS' => array( 'display_on_post' => array('INDEX', 'display_on_posting'), ), ), $this->table_prefix . 'bookmarks' => array( 'COLUMNS' => array( 'topic_id' => array('UINT', 0), 'user_id' => array('UINT', 0), ), 'PRIMARY_KEY' => array('topic_id', 'user_id'), ), $this->table_prefix . 'bots' => array( 'COLUMNS' => array( 'bot_id' => array('UINT', NULL, 'auto_increment'), 'bot_active' => array('BOOL', 1), 'bot_name' => array('STEXT_UNI', ''), 'user_id' => array('UINT', 0), 'bot_agent' => array('VCHAR', ''), 'bot_ip' => array('VCHAR', ''), ), 'PRIMARY_KEY' => 'bot_id', 'KEYS' => array( 'bot_active' => array('INDEX', 'bot_active'), ), ), $this->table_prefix . 'config' => array( 'COLUMNS' => array( 'config_name' => array('VCHAR', ''), 'config_value' => array('VCHAR_UNI', ''), 'is_dynamic' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'config_name', 'KEYS' => array( 'is_dynamic' => array('INDEX', 'is_dynamic'), ), ), $this->table_prefix . 'confirm' => array( 'COLUMNS' => array( 'confirm_id' => array('CHAR:32', ''), 'session_id' => array('CHAR:32', ''), 'confirm_type' => array('TINT:3', 0), 'code' => array('VCHAR:8', ''), 'seed' => array('UINT:10', 0), ), 'PRIMARY_KEY' => array('session_id', 'confirm_id'), 'KEYS' => array( 'confirm_type' => array('INDEX', 'confirm_type'), ), ), $this->table_prefix . 'disallow' => array( 'COLUMNS' => array( 'disallow_id' => array('UINT', NULL, 'auto_increment'), 'disallow_username' => array('VCHAR_UNI:255', ''), ), 'PRIMARY_KEY' => 'disallow_id', ), $this->table_prefix . 'drafts' => array( 'COLUMNS' => array( 'draft_id' => array('UINT', NULL, 'auto_increment'), 'user_id' => array('UINT', 0), 'topic_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'save_time' => array('TIMESTAMP', 0), 'draft_subject' => array('XSTEXT_UNI', ''), 'draft_message' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'draft_id', 'KEYS' => array( 'save_time' => array('INDEX', 'save_time'), ), ), $this->table_prefix . 'extensions' => array( 'COLUMNS' => array( 'extension_id' => array('UINT', NULL, 'auto_increment'), 'group_id' => array('UINT', 0), 'extension' => array('VCHAR:100', ''), ), 'PRIMARY_KEY' => 'extension_id', ), $this->table_prefix . 'extension_groups' => array( 'COLUMNS' => array( 'group_id' => array('UINT', NULL, 'auto_increment'), 'group_name' => array('VCHAR_UNI', ''), 'cat_id' => array('TINT:2', 0), 'allow_group' => array('BOOL', 0), 'download_mode' => array('BOOL', 1), 'upload_icon' => array('VCHAR', ''), 'max_filesize' => array('UINT:20', 0), 'allowed_forums' => array('TEXT', ''), 'allow_in_pm' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'group_id', ), $this->table_prefix . 'forums' => array( 'COLUMNS' => array( 'forum_id' => array('UINT', NULL, 'auto_increment'), 'parent_id' => array('UINT', 0), 'left_id' => array('UINT', 0), 'right_id' => array('UINT', 0), 'forum_parents' => array('MTEXT', ''), 'forum_name' => array('STEXT_UNI', ''), 'forum_desc' => array('TEXT_UNI', ''), 'forum_desc_bitfield' => array('VCHAR:255', ''), 'forum_desc_options' => array('UINT:11', 7), 'forum_desc_uid' => array('VCHAR:8', ''), 'forum_link' => array('VCHAR_UNI', ''), 'forum_password' => array('VCHAR_UNI:40', ''), 'forum_style' => array('USINT', 0), 'forum_image' => array('VCHAR', ''), 'forum_rules' => array('TEXT_UNI', ''), 'forum_rules_link' => array('VCHAR_UNI', ''), 'forum_rules_bitfield' => array('VCHAR:255', ''), 'forum_rules_options' => array('UINT:11', 7), 'forum_rules_uid' => array('VCHAR:8', ''), 'forum_topics_per_page' => array('TINT:4', 0), 'forum_type' => array('TINT:4', 0), 'forum_status' => array('TINT:4', 0), 'forum_posts' => array('UINT', 0), 'forum_topics' => array('UINT', 0), 'forum_topics_real' => array('UINT', 0), 'forum_last_post_id' => array('UINT', 0), 'forum_last_poster_id' => array('UINT', 0), 'forum_last_post_subject' => array('XSTEXT_UNI', ''), 'forum_last_post_time' => array('TIMESTAMP', 0), 'forum_last_poster_name'=> array('VCHAR_UNI', ''), 'forum_last_poster_colour'=> array('VCHAR:6', ''), 'forum_flags' => array('TINT:4', 32), 'display_on_index' => array('BOOL', 1), 'enable_indexing' => array('BOOL', 1), 'enable_icons' => array('BOOL', 1), 'enable_prune' => array('BOOL', 0), 'prune_next' => array('TIMESTAMP', 0), 'prune_days' => array('UINT', 0), 'prune_viewed' => array('UINT', 0), 'prune_freq' => array('UINT', 0), ), 'PRIMARY_KEY' => 'forum_id', 'KEYS' => array( 'left_right_id' => array('INDEX', array('left_id', 'right_id')), 'forum_lastpost_id' => array('INDEX', 'forum_last_post_id'), ), ), $this->table_prefix . 'forums_access' => array( 'COLUMNS' => array( 'forum_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'session_id' => array('CHAR:32', ''), ), 'PRIMARY_KEY' => array('forum_id', 'user_id', 'session_id'), ), $this->table_prefix . 'forums_track' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'mark_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => array('user_id', 'forum_id'), ), $this->table_prefix . 'forums_watch' => array( 'COLUMNS' => array( 'forum_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'notify_status' => array('BOOL', 0), ), 'KEYS' => array( 'forum_id' => array('INDEX', 'forum_id'), 'user_id' => array('INDEX', 'user_id'), 'notify_stat' => array('INDEX', 'notify_status'), ), ), $this->table_prefix . 'groups' => array( 'COLUMNS' => array( 'group_id' => array('UINT', NULL, 'auto_increment'), 'group_type' => array('TINT:4', 1), 'group_founder_manage' => array('BOOL', 0), 'group_name' => array('VCHAR_CI', ''), 'group_desc' => array('TEXT_UNI', ''), 'group_desc_bitfield' => array('VCHAR:255', ''), 'group_desc_options' => array('UINT:11', 7), 'group_desc_uid' => array('VCHAR:8', ''), 'group_display' => array('BOOL', 0), 'group_avatar' => array('VCHAR', ''), 'group_avatar_type' => array('TINT:2', 0), 'group_avatar_width' => array('USINT', 0), 'group_avatar_height' => array('USINT', 0), 'group_rank' => array('UINT', 0), 'group_colour' => array('VCHAR:6', ''), 'group_sig_chars' => array('UINT', 0), 'group_receive_pm' => array('BOOL', 0), 'group_message_limit' => array('UINT', 0), 'group_legend' => array('BOOL', 1), ), 'PRIMARY_KEY' => 'group_id', 'KEYS' => array( 'group_legend' => array('INDEX', 'group_legend'), ), ), $this->table_prefix . 'icons' => array( 'COLUMNS' => array( 'icons_id' => array('UINT', NULL, 'auto_increment'), 'icons_url' => array('VCHAR', ''), 'icons_width' => array('TINT:4', 0), 'icons_height' => array('TINT:4', 0), 'icons_order' => array('UINT', 0), 'display_on_posting' => array('BOOL', 1), ), 'PRIMARY_KEY' => 'icons_id', 'KEYS' => array( 'display_on_posting' => array('INDEX', 'display_on_posting'), ), ), $this->table_prefix . 'lang' => array( 'COLUMNS' => array( 'lang_id' => array('TINT:4', NULL, 'auto_increment'), 'lang_iso' => array('VCHAR:30', ''), 'lang_dir' => array('VCHAR:30', ''), 'lang_english_name' => array('VCHAR_UNI:100', ''), 'lang_local_name' => array('VCHAR_UNI:255', ''), 'lang_author' => array('VCHAR_UNI:255', ''), ), 'PRIMARY_KEY' => 'lang_id', 'KEYS' => array( 'lang_iso' => array('INDEX', 'lang_iso'), ), ), $this->table_prefix . 'log' => array( 'COLUMNS' => array( 'log_id' => array('UINT', NULL, 'auto_increment'), 'log_type' => array('TINT:4', 0), 'user_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'topic_id' => array('UINT', 0), 'reportee_id' => array('UINT', 0), 'log_ip' => array('VCHAR:40', ''), 'log_time' => array('TIMESTAMP', 0), 'log_operation' => array('TEXT_UNI', ''), 'log_data' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'log_id', 'KEYS' => array( 'log_type' => array('INDEX', 'log_type'), 'forum_id' => array('INDEX', 'forum_id'), 'topic_id' => array('INDEX', 'topic_id'), 'reportee_id' => array('INDEX', 'reportee_id'), 'user_id' => array('INDEX', 'user_id'), ), ), $this->table_prefix . 'moderator_cache' => array( 'COLUMNS' => array( 'forum_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'username' => array('VCHAR_UNI:255', ''), 'group_id' => array('UINT', 0), 'group_name' => array('VCHAR_UNI', ''), 'display_on_index' => array('BOOL', 1), ), 'KEYS' => array( 'disp_idx' => array('INDEX', 'display_on_index'), 'forum_id' => array('INDEX', 'forum_id'), ), ), $this->table_prefix . 'modules' => array( 'COLUMNS' => array( 'module_id' => array('UINT', NULL, 'auto_increment'), 'module_enabled' => array('BOOL', 1), 'module_display' => array('BOOL', 1), 'module_basename' => array('VCHAR', ''), 'module_class' => array('VCHAR:10', ''), 'parent_id' => array('UINT', 0), 'left_id' => array('UINT', 0), 'right_id' => array('UINT', 0), 'module_langname' => array('VCHAR', ''), 'module_mode' => array('VCHAR', ''), 'module_auth' => array('VCHAR', ''), ), 'PRIMARY_KEY' => 'module_id', 'KEYS' => array( 'left_right_id' => array('INDEX', array('left_id', 'right_id')), 'module_enabled' => array('INDEX', 'module_enabled'), 'class_left_id' => array('INDEX', array('module_class', 'left_id')), ), ), $this->table_prefix . 'poll_options' => array( 'COLUMNS' => array( 'poll_option_id' => array('TINT:4', 0), 'topic_id' => array('UINT', 0), 'poll_option_text' => array('TEXT_UNI', ''), 'poll_option_total' => array('UINT', 0), ), 'KEYS' => array( 'poll_opt_id' => array('INDEX', 'poll_option_id'), 'topic_id' => array('INDEX', 'topic_id'), ), ), $this->table_prefix . 'poll_votes' => array( 'COLUMNS' => array( 'topic_id' => array('UINT', 0), 'poll_option_id' => array('TINT:4', 0), 'vote_user_id' => array('UINT', 0), 'vote_user_ip' => array('VCHAR:40', ''), ), 'KEYS' => array( 'topic_id' => array('INDEX', 'topic_id'), 'vote_user_id' => array('INDEX', 'vote_user_id'), 'vote_user_ip' => array('INDEX', 'vote_user_ip'), ), ), $this->table_prefix . 'posts' => array( 'COLUMNS' => array( 'post_id' => array('UINT', NULL, 'auto_increment'), 'topic_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'poster_id' => array('UINT', 0), 'icon_id' => array('UINT', 0), 'poster_ip' => array('VCHAR:40', ''), 'post_time' => array('TIMESTAMP', 0), 'post_approved' => array('BOOL', 1), 'post_reported' => array('BOOL', 0), 'enable_bbcode' => array('BOOL', 1), 'enable_smilies' => array('BOOL', 1), 'enable_magic_url' => array('BOOL', 1), 'enable_sig' => array('BOOL', 1), 'post_username' => array('VCHAR_UNI:255', ''), 'post_subject' => array('XSTEXT_UNI', '', 'true_sort'), 'post_text' => array('MTEXT_UNI', ''), 'post_checksum' => array('VCHAR:32', ''), 'post_attachment' => array('BOOL', 0), 'bbcode_bitfield' => array('VCHAR:255', ''), 'bbcode_uid' => array('VCHAR:8', ''), 'post_postcount' => array('BOOL', 1), 'post_edit_time' => array('TIMESTAMP', 0), 'post_edit_reason' => array('STEXT_UNI', ''), 'post_edit_user' => array('UINT', 0), 'post_edit_count' => array('USINT', 0), 'post_edit_locked' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'post_id', 'KEYS' => array( 'forum_id' => array('INDEX', 'forum_id'), 'topic_id' => array('INDEX', 'topic_id'), 'poster_ip' => array('INDEX', 'poster_ip'), 'poster_id' => array('INDEX', 'poster_id'), 'post_approved' => array('INDEX', 'post_approved'), 'tid_post_time' => array('INDEX', array('topic_id', 'post_time')), ), ), $this->table_prefix . 'privmsgs' => array( 'COLUMNS' => array( 'msg_id' => array('UINT', NULL, 'auto_increment'), 'root_level' => array('UINT', 0), 'author_id' => array('UINT', 0), 'icon_id' => array('UINT', 0), 'author_ip' => array('VCHAR:40', ''), 'message_time' => array('TIMESTAMP', 0), 'enable_bbcode' => array('BOOL', 1), 'enable_smilies' => array('BOOL', 1), 'enable_magic_url' => array('BOOL', 1), 'enable_sig' => array('BOOL', 1), 'message_subject' => array('XSTEXT_UNI', ''), 'message_text' => array('MTEXT_UNI', ''), 'message_edit_reason' => array('STEXT_UNI', ''), 'message_edit_user' => array('UINT', 0), 'message_attachment' => array('BOOL', 0), 'bbcode_bitfield' => array('VCHAR:255', ''), 'bbcode_uid' => array('VCHAR:8', ''), 'message_edit_time' => array('TIMESTAMP', 0), 'message_edit_count' => array('USINT', 0), 'to_address' => array('TEXT_UNI', ''), 'bcc_address' => array('TEXT_UNI', ''), ), 'PRIMARY_KEY' => 'msg_id', 'KEYS' => array( 'author_ip' => array('INDEX', 'author_ip'), 'message_time' => array('INDEX', 'message_time'), 'author_id' => array('INDEX', 'author_id'), 'root_level' => array('INDEX', 'root_level'), ), ), $this->table_prefix . 'privmsgs_folder' => array( 'COLUMNS' => array( 'folder_id' => array('UINT', NULL, 'auto_increment'), 'user_id' => array('UINT', 0), 'folder_name' => array('VCHAR_UNI', ''), 'pm_count' => array('UINT', 0), ), 'PRIMARY_KEY' => 'folder_id', 'KEYS' => array( 'user_id' => array('INDEX', 'user_id'), ), ), $this->table_prefix . 'privmsgs_rules' => array( 'COLUMNS' => array( 'rule_id' => array('UINT', NULL, 'auto_increment'), 'user_id' => array('UINT', 0), 'rule_check' => array('UINT', 0), 'rule_connection' => array('UINT', 0), 'rule_string' => array('VCHAR_UNI', ''), 'rule_user_id' => array('UINT', 0), 'rule_group_id' => array('UINT', 0), 'rule_action' => array('UINT', 0), 'rule_folder_id' => array('INT:11', 0), ), 'PRIMARY_KEY' => 'rule_id', 'KEYS' => array( 'user_id' => array('INDEX', 'user_id'), ), ), $this->table_prefix . 'privmsgs_to' => array( 'COLUMNS' => array( 'msg_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'author_id' => array('UINT', 0), 'pm_deleted' => array('BOOL', 0), 'pm_new' => array('BOOL', 1), 'pm_unread' => array('BOOL', 1), 'pm_replied' => array('BOOL', 0), 'pm_marked' => array('BOOL', 0), 'pm_forwarded' => array('BOOL', 0), 'folder_id' => array('INT:11', 0), ), 'KEYS' => array( 'msg_id' => array('INDEX', 'msg_id'), 'author_id' => array('INDEX', 'author_id'), 'usr_flder_id' => array('INDEX', array('user_id', 'folder_id')), ), ), $this->table_prefix . 'profile_fields' => array( 'COLUMNS' => array( 'field_id' => array('UINT', NULL, 'auto_increment'), 'field_name' => array('VCHAR_UNI', ''), 'field_type' => array('TINT:4', 0), 'field_ident' => array('VCHAR:20', ''), 'field_length' => array('VCHAR:20', ''), 'field_minlen' => array('VCHAR', ''), 'field_maxlen' => array('VCHAR', ''), 'field_novalue' => array('VCHAR_UNI', ''), 'field_default_value' => array('VCHAR_UNI', ''), 'field_validation' => array('VCHAR_UNI:20', ''), 'field_required' => array('BOOL', 0), 'field_show_on_reg' => array('BOOL', 0), 'field_hide' => array('BOOL', 0), 'field_no_view' => array('BOOL', 0), 'field_active' => array('BOOL', 0), 'field_order' => array('UINT', 0), ), 'PRIMARY_KEY' => 'field_id', 'KEYS' => array( 'fld_type' => array('INDEX', 'field_type'), 'fld_ordr' => array('INDEX', 'field_order'), ), ), $this->table_prefix . 'profile_fields_data' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), ), 'PRIMARY_KEY' => 'user_id', ), $this->table_prefix . 'profile_fields_lang' => array( 'COLUMNS' => array( 'field_id' => array('UINT', 0), 'lang_id' => array('UINT', 0), 'option_id' => array('UINT', 0), 'field_type' => array('TINT:4', 0), 'lang_value' => array('VCHAR_UNI', ''), ), 'PRIMARY_KEY' => array('field_id', 'lang_id', 'option_id'), ), $this->table_prefix . 'profile_lang' => array( 'COLUMNS' => array( 'field_id' => array('UINT', 0), 'lang_id' => array('UINT', 0), 'lang_name' => array('VCHAR_UNI', ''), 'lang_explain' => array('TEXT_UNI', ''), 'lang_default_value' => array('VCHAR_UNI', ''), ), 'PRIMARY_KEY' => array('field_id', 'lang_id'), ), $this->table_prefix . 'ranks' => array( 'COLUMNS' => array( 'rank_id' => array('UINT', NULL, 'auto_increment'), 'rank_title' => array('VCHAR_UNI', ''), 'rank_min' => array('UINT', 0), 'rank_special' => array('BOOL', 0), 'rank_image' => array('VCHAR', ''), ), 'PRIMARY_KEY' => 'rank_id', ), $this->table_prefix . 'reports' => array( 'COLUMNS' => array( 'report_id' => array('UINT', NULL, 'auto_increment'), 'reason_id' => array('USINT', 0), 'post_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'user_notify' => array('BOOL', 0), 'report_closed' => array('BOOL', 0), 'report_time' => array('TIMESTAMP', 0), 'report_text' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'report_id', ), $this->table_prefix . 'reports_reasons' => array( 'COLUMNS' => array( 'reason_id' => array('USINT', NULL, 'auto_increment'), 'reason_title' => array('VCHAR_UNI', ''), 'reason_description' => array('MTEXT_UNI', ''), 'reason_order' => array('USINT', 0), ), 'PRIMARY_KEY' => 'reason_id', ), $this->table_prefix . 'search_results' => array( 'COLUMNS' => array( 'search_key' => array('VCHAR:32', ''), 'search_time' => array('TIMESTAMP', 0), 'search_keywords' => array('MTEXT_UNI', ''), 'search_authors' => array('MTEXT', ''), ), 'PRIMARY_KEY' => 'search_key', ), $this->table_prefix . 'search_wordlist' => array( 'COLUMNS' => array( 'word_id' => array('UINT', NULL, 'auto_increment'), 'word_text' => array('VCHAR_UNI', ''), 'word_common' => array('BOOL', 0), 'word_count' => array('UINT', 0), ), 'PRIMARY_KEY' => 'word_id', 'KEYS' => array( 'wrd_txt' => array('UNIQUE', 'word_text'), 'wrd_cnt' => array('INDEX', 'word_count'), ), ), $this->table_prefix . 'search_wordmatch' => array( 'COLUMNS' => array( 'post_id' => array('UINT', 0), 'word_id' => array('UINT', 0), 'title_match' => array('BOOL', 0), ), 'KEYS' => array( 'unq_mtch' => array('UNIQUE', array('word_id', 'post_id', 'title_match')), 'word_id' => array('INDEX', 'word_id'), 'post_id' => array('INDEX', 'post_id'), ), ), $this->table_prefix . 'sessions' => array( 'COLUMNS' => array( 'session_id' => array('CHAR:32', ''), 'session_user_id' => array('UINT', 0), 'session_last_visit' => array('TIMESTAMP', 0), 'session_start' => array('TIMESTAMP', 0), 'session_time' => array('TIMESTAMP', 0), 'session_ip' => array('VCHAR:40', ''), 'session_browser' => array('VCHAR:150', ''), 'session_forwarded_for' => array('VCHAR:255', ''), 'session_page' => array('VCHAR_UNI', ''), 'session_viewonline' => array('BOOL', 1), 'session_autologin' => array('BOOL', 0), 'session_admin' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'session_id', 'KEYS' => array( 'session_time' => array('INDEX', 'session_time'), 'session_user_id' => array('INDEX', 'session_user_id'), ), ), $this->table_prefix . 'sessions_keys' => array( 'COLUMNS' => array( 'key_id' => array('CHAR:32', ''), 'user_id' => array('UINT', 0), 'last_ip' => array('VCHAR:40', ''), 'last_login' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => array('key_id', 'user_id'), 'KEYS' => array( 'last_login' => array('INDEX', 'last_login'), ), ), $this->table_prefix . 'sitelist' => array( 'COLUMNS' => array( 'site_id' => array('UINT', NULL, 'auto_increment'), 'site_ip' => array('VCHAR:40', ''), 'site_hostname' => array('VCHAR', ''), 'ip_exclude' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'site_id', ), $this->table_prefix . 'smilies' => array( 'COLUMNS' => array( 'smiley_id' => array('UINT', NULL, 'auto_increment'), // We may want to set 'code' to VCHAR:50 or check if unicode support is possible... at the moment only ASCII characters are allowed. 'code' => array('VCHAR_UNI:50', ''), 'emotion' => array('VCHAR_UNI:50', ''), 'smiley_url' => array('VCHAR:50', ''), 'smiley_width' => array('USINT', 0), 'smiley_height' => array('USINT', 0), 'smiley_order' => array('UINT', 0), 'display_on_posting'=> array('BOOL', 1), ), 'PRIMARY_KEY' => 'smiley_id', 'KEYS' => array( 'display_on_post' => array('INDEX', 'display_on_posting'), ), ), $this->table_prefix . 'styles' => array( 'COLUMNS' => array( 'style_id' => array('USINT', NULL, 'auto_increment'), 'style_name' => array('VCHAR_UNI:255', ''), 'style_copyright' => array('VCHAR_UNI', ''), 'style_active' => array('BOOL', 1), 'template_id' => array('USINT', 0), 'theme_id' => array('USINT', 0), 'imageset_id' => array('USINT', 0), ), 'PRIMARY_KEY' => 'style_id', 'KEYS' => array( 'style_name' => array('UNIQUE', 'style_name'), 'template_id' => array('INDEX', 'template_id'), 'theme_id' => array('INDEX', 'theme_id'), 'imageset_id' => array('INDEX', 'imageset_id'), ), ), $this->table_prefix . 'styles_template' => array( 'COLUMNS' => array( 'template_id' => array('USINT', NULL, 'auto_increment'), 'template_name' => array('VCHAR_UNI:255', ''), 'template_copyright' => array('VCHAR_UNI', ''), 'template_path' => array('VCHAR:100', ''), 'bbcode_bitfield' => array('VCHAR:255', 'kNg='), 'template_storedb' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'template_id', 'KEYS' => array( 'tmplte_nm' => array('UNIQUE', 'template_name'), ), ), $this->table_prefix . 'styles_template_data' => array( 'COLUMNS' => array( 'template_id' => array('USINT', 0), 'template_filename' => array('VCHAR:100', ''), 'template_included' => array('TEXT', ''), 'template_mtime' => array('TIMESTAMP', 0), 'template_data' => array('MTEXT_UNI', ''), ), 'KEYS' => array( 'tid' => array('INDEX', 'template_id'), 'tfn' => array('INDEX', 'template_filename'), ), ), $this->table_prefix . 'styles_theme' => array( 'COLUMNS' => array( 'theme_id' => array('USINT', NULL, 'auto_increment'), 'theme_name' => array('VCHAR_UNI:255', ''), 'theme_copyright' => array('VCHAR_UNI', ''), 'theme_path' => array('VCHAR:100', ''), 'theme_storedb' => array('BOOL', 0), 'theme_mtime' => array('TIMESTAMP', 0), 'theme_data' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'theme_id', 'KEYS' => array( 'theme_name' => array('UNIQUE', 'theme_name'), ), ), $this->table_prefix . 'styles_imageset' => array( 'COLUMNS' => array( 'imageset_id' => array('USINT', NULL, 'auto_increment'), 'imageset_name' => array('VCHAR_UNI:255', ''), 'imageset_copyright' => array('VCHAR_UNI', ''), 'imageset_path' => array('VCHAR:100', ''), ), 'PRIMARY_KEY' => 'imageset_id', 'KEYS' => array( 'imgset_nm' => array('UNIQUE', 'imageset_name'), ), ), $this->table_prefix . 'styles_imageset_data' => array( 'COLUMNS' => array( 'image_id' => array('USINT', NULL, 'auto_increment'), 'image_name' => array('VCHAR:200', ''), 'image_filename' => array('VCHAR:200', ''), 'image_lang' => array('VCHAR:30', ''), 'image_height' => array('USINT', 0), 'image_width' => array('USINT', 0), 'imageset_id' => array('USINT', 0), ), 'PRIMARY_KEY' => 'image_id', 'KEYS' => array( 'i_d' => array('INDEX', 'imageset_id'), ), ), $this->table_prefix . 'topics' => array( 'COLUMNS' => array( 'topic_id' => array('UINT', NULL, 'auto_increment'), 'forum_id' => array('UINT', 0), 'icon_id' => array('UINT', 0), 'topic_attachment' => array('BOOL', 0), 'topic_approved' => array('BOOL', 1), 'topic_reported' => array('BOOL', 0), 'topic_title' => array('XSTEXT_UNI', '', 'true_sort'), 'topic_poster' => array('UINT', 0), 'topic_time' => array('TIMESTAMP', 0), 'topic_time_limit' => array('TIMESTAMP', 0), 'topic_views' => array('UINT', 0), 'topic_replies' => array('UINT', 0), 'topic_replies_real' => array('UINT', 0), 'topic_status' => array('TINT:3', 0), 'topic_type' => array('TINT:3', 0), 'topic_first_post_id' => array('UINT', 0), 'topic_first_poster_name' => array('VCHAR_UNI', ''), 'topic_first_poster_colour' => array('VCHAR:6', ''), 'topic_last_post_id' => array('UINT', 0), 'topic_last_poster_id' => array('UINT', 0), 'topic_last_poster_name' => array('VCHAR_UNI', ''), 'topic_last_poster_colour' => array('VCHAR:6', ''), 'topic_last_post_subject' => array('XSTEXT_UNI', ''), 'topic_last_post_time' => array('TIMESTAMP', 0), 'topic_last_view_time' => array('TIMESTAMP', 0), 'topic_moved_id' => array('UINT', 0), 'topic_bumped' => array('BOOL', 0), 'topic_bumper' => array('UINT', 0), 'poll_title' => array('STEXT_UNI', ''), 'poll_start' => array('TIMESTAMP', 0), 'poll_length' => array('TIMESTAMP', 0), 'poll_max_options' => array('TINT:4', 1), 'poll_last_vote' => array('TIMESTAMP', 0), 'poll_vote_change' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'topic_id', 'KEYS' => array( 'forum_id' => array('INDEX', 'forum_id'), 'forum_id_type' => array('INDEX', array('forum_id', 'topic_type')), 'last_post_time' => array('INDEX', 'topic_last_post_time'), 'topic_approved' => array('INDEX', 'topic_approved'), 'forum_appr_last' => array('INDEX', array('forum_id', 'topic_approved', 'topic_last_post_id')), 'fid_time_moved' => array('INDEX', array('forum_id', 'topic_last_post_time', 'topic_moved_id')), ), ), $this->table_prefix . 'topics_track' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'topic_id' => array('UINT', 0), 'forum_id' => array('UINT', 0), 'mark_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => array('user_id', 'topic_id'), 'KEYS' => array( 'forum_id' => array('INDEX', 'forum_id'), ), ), $this->table_prefix . 'topics_posted' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'topic_id' => array('UINT', 0), 'topic_posted' => array('BOOL', 0), ), 'PRIMARY_KEY' => array('user_id', 'topic_id'), ), $this->table_prefix . 'topics_watch' => array( 'COLUMNS' => array( 'topic_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'notify_status' => array('BOOL', 0), ), 'KEYS' => array( 'topic_id' => array('INDEX', 'topic_id'), 'user_id' => array('INDEX', 'user_id'), 'notify_stat' => array('INDEX', 'notify_status'), ), ), $this->table_prefix . 'user_group' => array( 'COLUMNS' => array( 'group_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'group_leader' => array('BOOL', 0), 'user_pending' => array('BOOL', 1), ), 'KEYS' => array( 'group_id' => array('INDEX', 'group_id'), 'user_id' => array('INDEX', 'user_id'), 'group_leader' => array('INDEX', 'group_leader'), ), ), $this->table_prefix . 'users' => array( 'COLUMNS' => array( 'user_id' => array('UINT', NULL, 'auto_increment'), 'user_type' => array('TINT:2', 0), 'group_id' => array('UINT', 3), 'user_permissions' => array('MTEXT', ''), 'user_perm_from' => array('UINT', 0), 'user_ip' => array('VCHAR:40', ''), 'user_regdate' => array('TIMESTAMP', 0), 'username' => array('VCHAR_CI', ''), 'username_clean' => array('VCHAR_CI', ''), 'user_password' => array('VCHAR_UNI:40', ''), 'user_passchg' => array('TIMESTAMP', 0), 'user_pass_convert' => array('BOOL', 0), 'user_email' => array('VCHAR_UNI:100', ''), 'user_email_hash' => array('BINT', 0), 'user_birthday' => array('VCHAR:10', ''), 'user_lastvisit' => array('TIMESTAMP', 0), 'user_lastmark' => array('TIMESTAMP', 0), 'user_lastpost_time' => array('TIMESTAMP', 0), 'user_lastpage' => array('VCHAR_UNI:200', ''), 'user_last_confirm_key' => array('VCHAR:10', ''), 'user_last_search' => array('TIMESTAMP', 0), 'user_warnings' => array('TINT:4', 0), 'user_last_warning' => array('TIMESTAMP', 0), 'user_login_attempts' => array('TINT:4', 0), 'user_inactive_reason' => array('TINT:2', 0), 'user_inactive_time' => array('TIMESTAMP', 0), 'user_posts' => array('UINT', 0), 'user_lang' => array('VCHAR:30', ''), 'user_timezone' => array('DECIMAL', 0), 'user_dst' => array('BOOL', 0), 'user_dateformat' => array('VCHAR_UNI:30', 'd M Y H:i'), 'user_style' => array('USINT', 0), 'user_rank' => array('UINT', 0), 'user_colour' => array('VCHAR:6', ''), 'user_new_privmsg' => array('INT:4', 0), 'user_unread_privmsg' => array('INT:4', 0), 'user_last_privmsg' => array('TIMESTAMP', 0), 'user_message_rules' => array('BOOL', 0), 'user_full_folder' => array('INT:11', -3), 'user_emailtime' => array('TIMESTAMP', 0), 'user_topic_show_days' => array('USINT', 0), 'user_topic_sortby_type' => array('VCHAR:1', 't'), 'user_topic_sortby_dir' => array('VCHAR:1', 'd'), 'user_post_show_days' => array('USINT', 0), 'user_post_sortby_type' => array('VCHAR:1', 't'), 'user_post_sortby_dir' => array('VCHAR:1', 'a'), 'user_notify' => array('BOOL', 0), 'user_notify_pm' => array('BOOL', 1), 'user_notify_type' => array('TINT:4', 0), 'user_allow_pm' => array('BOOL', 1), 'user_allow_viewonline' => array('BOOL', 1), 'user_allow_viewemail' => array('BOOL', 1), 'user_allow_massemail' => array('BOOL', 1), 'user_options' => array('UINT:11', 895), 'user_avatar' => array('VCHAR', ''), 'user_avatar_type' => array('TINT:2', 0), 'user_avatar_width' => array('USINT', 0), 'user_avatar_height' => array('USINT', 0), 'user_sig' => array('MTEXT_UNI', ''), 'user_sig_bbcode_uid' => array('VCHAR:8', ''), 'user_sig_bbcode_bitfield' => array('VCHAR:255', ''), 'user_from' => array('VCHAR_UNI:100', ''), 'user_icq' => array('VCHAR:15', ''), 'user_aim' => array('VCHAR_UNI', ''), 'user_yim' => array('VCHAR_UNI', ''), 'user_msnm' => array('VCHAR_UNI', ''), 'user_jabber' => array('VCHAR_UNI', ''), 'user_website' => array('VCHAR_UNI:200', ''), 'user_occ' => array('TEXT_UNI', ''), 'user_interests' => array('TEXT_UNI', ''), 'user_actkey' => array('VCHAR:32', ''), 'user_newpasswd' => array('VCHAR_UNI:40', ''), 'user_form_salt' => array('VCHAR_UNI:32', ''), ), 'PRIMARY_KEY' => 'user_id', 'KEYS' => array( 'user_birthday' => array('INDEX', 'user_birthday'), 'user_email_hash' => array('INDEX', 'user_email_hash'), 'user_type' => array('INDEX', 'user_type'), 'username_clean' => array('UNIQUE', 'username_clean'), ), ), $this->table_prefix . 'warnings' => array( 'COLUMNS' => array( 'warning_id' => array('UINT', NULL, 'auto_increment'), 'user_id' => array('UINT', 0), 'post_id' => array('UINT', 0), 'log_id' => array('UINT', 0), 'warning_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => 'warning_id', ), $this->table_prefix . 'words' => array( 'COLUMNS' => array( 'word_id' => array('UINT', NULL, 'auto_increment'), 'word' => array('VCHAR_UNI', ''), 'replacement' => array('VCHAR_UNI', ''), ), 'PRIMARY_KEY' => 'word_id', ), $this->table_prefix . 'zebra' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'zebra_id' => array('UINT', 0), 'friend' => array('BOOL', 0), 'foe' => array('BOOL', 0), ), 'PRIMARY_KEY' => array('user_id', 'zebra_id'), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'attachments', $this->table_prefix . 'acl_groups', $this->table_prefix . 'acl_options', $this->table_prefix . 'acl_roles', $this->table_prefix . 'acl_roles_data', $this->table_prefix . 'acl_users', $this->table_prefix . 'banlist', $this->table_prefix . 'bbcodes', $this->table_prefix . 'bookmarks', $this->table_prefix . 'bots', $this->table_prefix . 'config', $this->table_prefix . 'confirm', $this->table_prefix . 'disallow', $this->table_prefix . 'drafts', $this->table_prefix . 'extensions', $this->table_prefix . 'extension_groups', $this->table_prefix . 'forums', $this->table_prefix . 'forums_access', $this->table_prefix . 'forums_track', $this->table_prefix . 'forums_watch', $this->table_prefix . 'groups', $this->table_prefix . 'icons', $this->table_prefix . 'lang', $this->table_prefix . 'log', $this->table_prefix . 'moderator_cache', $this->table_prefix . 'modules', $this->table_prefix . 'poll_options', $this->table_prefix . 'poll_votes', $this->table_prefix . 'posts', $this->table_prefix . 'privmsgs', $this->table_prefix . 'privmsgs_folder', $this->table_prefix . 'privmsgs_rules', $this->table_prefix . 'privmsgs_to', $this->table_prefix . 'profile_fields', $this->table_prefix . 'profile_fields_data', $this->table_prefix . 'profile_fields_lang', $this->table_prefix . 'profile_lang', $this->table_prefix . 'ranks', $this->table_prefix . 'reports', $this->table_prefix . 'reports_reasons', $this->table_prefix . 'search_results', $this->table_prefix . 'search_wordlist', $this->table_prefix . 'search_wordmatch', $this->table_prefix . 'sessions', $this->table_prefix . 'sessions_keys', $this->table_prefix . 'sitelist', $this->table_prefix . 'smilies', $this->table_prefix . 'styles', $this->table_prefix . 'styles_template', $this->table_prefix . 'styles_template_data', $this->table_prefix . 'styles_theme', $this->table_prefix . 'styles_imageset', $this->table_prefix . 'styles_imageset_data', $this->table_prefix . 'topics', $this->table_prefix . 'topics_track', $this->table_prefix . 'topics_posted', $this->table_prefix . 'topics_watch', $this->table_prefix . 'user_group', $this->table_prefix . 'users', $this->table_prefix . 'warnings', $this->table_prefix . 'words', $this->table_prefix . 'zebra', ), ); } } migration/data/v30x/release_3_0_8_rc1.php000077700000011057151514672100014051 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_8_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.8-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_7_pl1'); } public function update_data() { return array( array('custom', array(array(&$this, 'update_file_extension_group_names'))), array('custom', array(array(&$this, 'update_module_auth'))), array('custom', array(array(&$this, 'delete_orphan_shadow_topics'))), array('module.add', array( 'acp', 'ACP_MESSAGES', array( 'module_basename' => 'acp_board', 'modes' => array('post'), ), )), array('config.add', array('load_unreads_search', 1)), array('config.update_if_equals', array(600, 'queue_interval', 60)), array('config.update_if_equals', array(50, 'email_package_size', 20)), array('config.update', array('version', '3.0.8-RC1')), ); } public function update_file_extension_group_names() { // Update file extension group names to use language strings. $sql = 'SELECT lang_dir FROM ' . LANG_TABLE; $result = $this->db->sql_query($sql); $extension_groups_updated = array(); while ($lang_dir = $this->db->sql_fetchfield('lang_dir')) { $lang_dir = basename($lang_dir); // The language strings we need are either in language/.../acp/attachments.php // in the update package if we're updating to 3.0.8-RC1 or later, // or they are in language/.../install.php when we're updating from 3.0.7-PL1 or earlier. // On an already updated board, they can also already be in language/.../acp/attachments.php // in the board root. $lang_files = array( "{$this->phpbb_root_path}install/update/new/language/$lang_dir/acp/attachments.{$this->php_ext}", "{$this->phpbb_root_path}language/$lang_dir/install.{$this->php_ext}", "{$this->phpbb_root_path}language/$lang_dir/acp/attachments.{$this->php_ext}", ); foreach ($lang_files as $lang_file) { if (!file_exists($lang_file)) { continue; } $lang = array(); include($lang_file); foreach($lang as $lang_key => $lang_val) { if (isset($extension_groups_updated[$lang_key]) || strpos($lang_key, 'EXT_GROUP_') !== 0) { continue; } $sql_ary = array( 'group_name' => substr($lang_key, 10), // Strip off 'EXT_GROUP_' ); $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . " WHERE group_name = '" . $this->db->sql_escape($lang_val) . "'"; $this->sql_query($sql); $extension_groups_updated[$lang_key] = true; } } } $this->db->sql_freeresult($result); } public function update_module_auth() { $sql = 'UPDATE ' . MODULES_TABLE . ' SET module_auth = \'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)\' WHERE module_class = \'ucp\' AND module_basename = \'profile\' AND module_mode = \'avatar\''; $this->sql_query($sql); } public function delete_orphan_shadow_topics() { // Delete shadow topics pointing to not existing topics $batch_size = 500; // Set of affected forums we have to resync $sync_forum_ids = array(); $sql_array = array( 'SELECT' => 't1.topic_id, t1.forum_id', 'FROM' => array( TOPICS_TABLE => 't1', ), 'LEFT_JOIN' => array( array( 'FROM' => array(TOPICS_TABLE => 't2'), 'ON' => 't1.topic_moved_id = t2.topic_id', ), ), 'WHERE' => 't1.topic_moved_id <> 0 AND t2.topic_id IS NULL', ); $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query_limit($sql, $batch_size); $topic_ids = array(); while ($row = $this->db->sql_fetchrow($result)) { $topic_ids[] = (int) $row['topic_id']; $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; } $this->db->sql_freeresult($result); if (!empty($topic_ids)) { $sql = 'DELETE FROM ' . TOPICS_TABLE . ' WHERE ' . $this->db->sql_in_set('topic_id', $topic_ids); $this->db->sql_query($sql); // Sync the forums we have deleted shadow topics from. sync('forum', 'forum_id', $sync_forum_ids, true, true); return false; } } } migration/data/v30x/release_3_0_4_rc1.php000077700000007026151514672100014046 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_4_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.4-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_3'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_profile' => array('BOOL', 0), ), ), 'change_columns' => array( $this->table_prefix . 'styles' => array( 'style_id' => array('UINT', NULL, 'auto_increment'), 'template_id' => array('UINT', 0), 'theme_id' => array('UINT', 0), 'imageset_id' => array('UINT', 0), ), $this->table_prefix . 'styles_imageset' => array( 'imageset_id' => array('UINT', NULL, 'auto_increment'), ), $this->table_prefix . 'styles_imageset_data' => array( 'image_id' => array('UINT', NULL, 'auto_increment'), 'imageset_id' => array('UINT', 0), ), $this->table_prefix . 'styles_theme' => array( 'theme_id' => array('UINT', NULL, 'auto_increment'), ), $this->table_prefix . 'styles_template' => array( 'template_id' => array('UINT', NULL, 'auto_increment'), ), $this->table_prefix . 'styles_template_data' => array( 'template_id' => array('UINT', 0), ), $this->table_prefix . 'forums' => array( 'forum_style' => array('UINT', 0), ), $this->table_prefix . 'users' => array( 'user_style' => array('UINT', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_profile', ), ), ); } public function update_data() { return array( array('custom', array(array(&$this, 'update_custom_profile_fields'))), array('config.update', array('version', '3.0.4-RC1')), ); } public function update_custom_profile_fields() { // Update the Custom Profile Fields based on previous settings to the new \format $sql = 'SELECT field_id, field_required, field_show_on_reg, field_hide FROM ' . PROFILE_FIELDS_TABLE; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $sql_ary = array( 'field_required' => 0, 'field_show_on_reg' => 0, 'field_hide' => 0, 'field_show_profile'=> 0, ); if ($row['field_required']) { $sql_ary['field_required'] = $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; } else if ($row['field_show_on_reg']) { $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; } else if ($row['field_hide']) { // Only administrators and moderators can see this CPF, if the view is enabled, they can see it, otherwise just admins in the acp_users module $sql_ary['field_hide'] = 1; } else { // equivelant to "none", which is the "Display in user control panel" option $sql_ary['field_show_profile'] = 1; } $this->sql_query('UPDATE ' . $this->table_prefix . 'profile_fields SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE field_id = ' . $row['field_id'], $errored, $error_ary); } $this->db->sql_freeresult($result); } } migration/data/v30x/release_3_0_7.php000077700000001326151514672100013301 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_7 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.7', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_7_rc2'); } public function update_data() { return array( array('config.update', array('version', '3.0.7')), ); } } migration/data/v30x/release_3_0_14_rc1.php000077700000001615151514672100014125 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_14_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.14-RC1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_13'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.14-RC1', '<'), array('config.update', array('version', '3.0.14-RC1')), )), ); } } migration/data/v30x/release_3_0_10_rc1.php000077700000001435151514672100014121 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_10_rc1 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.10-RC1', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_9'); } public function update_data() { return array( array('config.add', array('email_max_chunk_size', 50)), array('config.update', array('version', '3.0.10-RC1')), ); } } migration/data/v30x/release_3_0_6_rc2.php000077700000001342151514672100014044 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_6_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.6-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_6_rc1'); } public function update_data() { return array( array('config.update', array('version', '3.0.6-RC2')), ); } } migration/data/v30x/release_3_0_2_rc2.php000077700000003710151514672100014041 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_2_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.2-RC2', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_2_rc1'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'drafts' => array( 'draft_subject' => array('STEXT_UNI', ''), ), $this->table_prefix . 'forums' => array( 'forum_last_post_subject' => array('STEXT_UNI', ''), ), $this->table_prefix . 'posts' => array( 'post_subject' => array('STEXT_UNI', '', 'true_sort'), ), $this->table_prefix . 'privmsgs' => array( 'message_subject' => array('STEXT_UNI', ''), ), $this->table_prefix . 'topics' => array( 'topic_title' => array('STEXT_UNI', '', 'true_sort'), 'topic_last_post_subject' => array('STEXT_UNI', ''), ), ), 'drop_keys' => array( $this->table_prefix . 'sessions' => array( 'session_forum_id', ), ), 'add_index' => array( $this->table_prefix . 'sessions' => array( 'session_fid' => array('session_forum_id'), ), ), ); } public function revert_schema() { return array( 'add_index' => array( $this->table_prefix . 'sessions' => array( 'session_forum_id' => array( 'session_forum_id', ), ), ), 'drop_keys' => array( $this->table_prefix . 'sessions' => array( 'session_fid', ), ), ); } public function update_data() { return array( array('config.update', array('version', '3.0.2-RC2')), ); } } migration/data/v30x/release_3_0_10.php000077700000001332151514672100013350 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_10 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.10', '>='); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_10_rc3'); } public function update_data() { return array( array('config.update', array('version', '3.0.10')), ); } } migration/data/v30x/release_3_0_12_rc2.php000077700000001621151514672100014121 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v30x; class release_3_0_12_rc2 extends \phpbb\db\migration\migration { public function effectively_installed() { return phpbb_version_compare($this->config['version'], '3.0.12-RC2', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_12_rc1'); } public function update_data() { return array( array('if', array( phpbb_version_compare($this->config['version'], '3.0.12-RC2', '<'), array('config.update', array('version', '3.0.12-RC2')), )), ); } } migration/data/v31x/style_update.php000077700000006505151514672100013501 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class style_update extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\gold'); } public function update_data() { return array( array('custom', array(array($this, 'update_installed_styles'))), ); } public function update_installed_styles() { // Get all currently available styles $styles = $this->find_style_dirs(); $style_paths = $style_ids = array(); $sql = 'SELECT style_path, style_id FROM ' . $this->table_prefix . 'styles'; $result = $this->db->sql_query($sql); while ($styles_row = $this->db->sql_fetchrow()) { if (in_array($styles_row['style_path'], $styles)) { $style_paths[] = $styles_row['style_path']; $style_ids[] = $styles_row['style_id']; } } $this->db->sql_freeresult($result); // Install prosilver if no style is available and prosilver can be installed if (empty($style_paths) && in_array('prosilver', $styles)) { // Try to parse config file $cfg = parse_cfg_file($this->phpbb_root_path . 'styles/prosilver/style.cfg'); // Stop running this if prosilver cfg file can't be read if (empty($cfg)) { throw new \RuntimeException('No styles available and could not fall back to prosilver.'); } $style = array( 'style_name' => 'prosilver', 'style_copyright' => '© phpBB Limited', 'style_active' => 1, 'style_path' => 'prosilver', 'bbcode_bitfield' => 'kNg=', 'style_parent_id' => 0, 'style_parent_tree' => '', ); // Add to database $this->db->sql_transaction('begin'); $sql = 'INSERT INTO ' . $this->table_prefix . 'styles ' . $this->db->sql_build_array('INSERT', $style); $this->db->sql_query($sql); $style_id = $this->db->sql_nextid(); $style_ids[] = $style_id; $this->db->sql_transaction('commit'); // Set prosilver to default style $this->config->set('default_style', $style_id); } else if (empty($styles) && empty($available_styles)) { throw new \RuntimeException('No valid styles available'); } // Make sure default style is available if (!in_array($this->config['default_style'], $style_ids)) { $this->config->set('default_style', array_pop($style_ids)); } // Reset users to default style if their user_style is nonexistent $sql = 'UPDATE ' . $this->table_prefix . "users SET user_style = {$this->config['default_style']} WHERE " . $this->db->sql_in_set('user_style', $style_ids, true, true); $this->db->sql_query($sql); } /** * Find all directories that have styles * Copied from acp_styles * * @return array Directory names */ protected function find_style_dirs() { $styles = array(); $styles_path = $this->phpbb_root_path . 'styles/'; $dp = @opendir($styles_path); if ($dp) { while (($file = readdir($dp)) !== false) { $dir = $styles_path . $file; if ($file[0] == '.' || !is_dir($dir)) { continue; } if (file_exists("{$dir}/style.cfg")) { $styles[] = $file; } } closedir($dp); } return $styles; } } migration/data/v31x/m_softdelete_global.php000077700000001302151514672100014757 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class m_softdelete_global extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v31x\v311'); } public function update_data() { return array( // Make m_softdelete global. The add method will take care of updating // it if it already exists. array('permission.add', array('m_softdelete', true)), ); } } migration/data/v31x/profilefield_remove_underscore_from_alpha.php000077700000002522151514672100021434 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class profilefield_remove_underscore_from_alpha extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v31x\v311'); } public function update_data() { return array( array('custom', array(array($this, 'remove_underscore_from_alpha_validations'))), ); } public function remove_underscore_from_alpha_validations() { $this->update_validation_rule('[\w]+', '[a-zA-Z0-9]+'); $this->update_validation_rule('[\w_]+', '[\w]+'); $this->update_validation_rule('[\w.]+', '[a-zA-Z0-9.]+'); $this->update_validation_rule('[\w\x20_+\-\[\]]+', '[\w\x20+\-\[\]]+'); $this->update_validation_rule('[a-zA-Z][\w\.,\-_]+', '[a-zA-Z][\w\.,\-]+'); } public function update_validation_rule($old_validation, $new_validation) { $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " SET field_validation = '" . $this->db->sql_escape($new_validation) . "' WHERE field_validation = '" . $this->db->sql_escape($old_validation) . "'"; $this->db->sql_query($sql); } } migration/data/v31x/v313rc1.php000077700000001564151514672100012101 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v313rc1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v30x\release_3_0_13_rc1', '\phpbb\db\migration\data\v31x\plupload_last_gc_dynamic', '\phpbb\db\migration\data\v31x\profilefield_remove_underscore_from_alpha', '\phpbb\db\migration\data\v31x\profilefield_yahoo_update_url', '\phpbb\db\migration\data\v31x\update_custom_bbcodes_with_idn', ); } public function update_data() { return array( array('config.update', array('version', '3.1.3-RC1')), ); } } migration/data/v31x/v315rc1.php000077700000001126151514672100012075 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v315rc1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v314', ); } public function update_data() { return array( array('config.update', array('version', '3.1.5-RC1')), ); } } migration/data/v31x/v311.php000077700000001200151514672100011454 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v311 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\gold', '\phpbb\db\migration\data\v31x\style_update', ); } public function update_data() { return array( array('config.update', array('version', '3.1.1')), ); } } migration/data/v31x/v314rc2.php000077700000001220151514672100012070 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v314rc2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v30x\release_3_0_14_rc1', '\phpbb\db\migration\data\v31x\v314rc1', ); } public function update_data() { return array( array('config.update', array('version', '3.1.4-RC2')), ); } } migration/data/v31x/v315.php000077700000001122151514672100011463 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v315 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v315rc1', ); } public function update_data() { return array( array('config.update', array('version', '3.1.5')), ); } } migration/data/v31x/v314rc1.php000077700000001126151514672100012074 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v314rc1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v313', ); } public function update_data() { return array( array('config.update', array('version', '3.1.4-RC1')), ); } } migration/data/v31x/v312.php000077700000001122151514672100011460 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v312 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v312rc1', ); } public function update_data() { return array( array('config.update', array('version', '3.1.2')), ); } } migration/data/v31x/update_custom_bbcodes_with_idn.php000077700000003356151514672100017222 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class update_custom_bbcodes_with_idn extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v312', ); } public function update_data() { return array( array('custom', array(array($this, 'update_bbcodes_table'))), ); } public function update_bbcodes_table() { if (!class_exists('acp_bbcodes')) { include($this->phpbb_root_path . 'includes/acp/acp_bbcodes.' . $this->php_ext); } $bbcodes = new \acp_bbcodes(); $sql = 'SELECT bbcode_id, bbcode_match, bbcode_tpl FROM ' . BBCODES_TABLE; $result = $this->sql_query($sql); $sql_ary = array(); while ($row = $this->db->sql_fetchrow($result)) { $data = array(); if (preg_match('/(URL|LOCAL_URL|RELATIVE_URL)/', $row['bbcode_match'])) { $data = $bbcodes->build_regexp($row['bbcode_match'], $row['bbcode_tpl']); $sql_ary[$row['bbcode_id']] = array( 'first_pass_match' => $data['first_pass_match'], 'first_pass_replace' => $data['first_pass_replace'], 'second_pass_match' => $data['second_pass_match'], 'second_pass_replace' => $data['second_pass_replace'] ); } } $this->db->sql_freeresult($result); foreach ($sql_ary as $bbcode_id => $bbcode_data) { $sql = 'UPDATE ' . BBCODES_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . ' WHERE bbcode_id = ' . (int) $bbcode_id; $this->sql_query($sql); } } } migration/data/v31x/profilefield_yahoo_update_url.php000077700000001635151514672100017065 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class profilefield_yahoo_update_url extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v31x\v312'); } public function update_data() { return array( array('custom', array(array($this, 'update_contact_url'))), ); } public function update_contact_url() { $sql = 'UPDATE ' . $this->table_prefix . "profile_fields SET field_contact_url = 'ymsgr:sendim?%s' WHERE field_name = 'phpbb_yahoo' AND field_contact_url = 'http://edit.yahoo.com/config/send_webmesg?.target=%s&.src=pg'"; $this->sql_query($sql); } } migration/data/v31x/plupload_last_gc_dynamic.php000077700000001271151514672100016012 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class plupload_last_gc_dynamic extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v31x\v312'); } public function update_data() { return array( // Make plupload_last_gc dynamic. array('config.remove', array('plupload_last_gc')), array('config.add', array('plupload_last_gc', 0, 1)), ); } } migration/data/v31x/v313.php000077700000001122151514672100011461 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v313 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v313rc2', ); } public function update_data() { return array( array('config.update', array('version', '3.1.3')), ); } } migration/data/v31x/v314.php000077700000001205151514672100011464 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v314 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v30x\release_3_0_14', '\phpbb\db\migration\data\v31x\v314rc2', ); } public function update_data() { return array( array('config.update', array('version', '3.1.4')), ); } } migration/data/v31x/v313rc2.php000077700000001220151514672100012067 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v313rc2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v30x\release_3_0_13_pl1', '\phpbb\db\migration\data\v31x\v313rc1', ); } public function update_data() { return array( array('config.update', array('version', '3.1.3-RC2')), ); } } migration/data/v31x/v312rc1.php000077700000001216151514672100012072 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v31x; class v312rc1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v31x\v311', '\phpbb\db\migration\data\v31x\m_softdelete_global', ); } public function update_data() { return array( array('config.update', array('version', '3.1.2-RC1')), ); } } migration/data/v310/profilefield_website_cleanup.php000077700000002002151514672100016550 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_website_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_website'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_website', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_website', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_website' => array('VCHAR_UNI:200', ''), ), ), ); } } migration/data/v310/remove_acp_styles_cache.php000077700000002201151514672100015522 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class remove_acp_styles_cache extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_langname = 'ACP_STYLES_CACHE'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); return !$module_id; } static public function depends_on() { return array('\phpbb\db\migration\data\v310\rc4'); } public function update_data() { return array( array('module.remove', array( 'acp', 'ACP_STYLE_MANAGEMENT', array( 'module_basename' => 'acp_styles', 'module_langname' => 'ACP_STYLES_CACHE', 'module_mode' => 'cache', 'module_auth' => 'acl_a_styles', ), )), ); } } migration/data/v310/migrations_table.php000077700000002323151514672100014204 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class migrations_table extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'migrations'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'migrations' => array( 'COLUMNS' => array( 'migration_name' => array('VCHAR', ''), 'migration_depends_on' => array('TEXT', ''), 'migration_schema_done' => array('BOOL', 0), 'migration_data_done' => array('BOOL', 0), 'migration_data_state' => array('TEXT', ''), 'migration_start_time' => array('TIMESTAMP', 0), 'migration_end_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => 'migration_name', ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'migrations', ), ); } } migration/data/v310/jquery_update2.php000077700000001475151514672100013633 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class jquery_update2 extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->config['load_jquery_url'] !== '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'; } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\jquery_update', ); } public function update_data() { return array( array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js')), ); } } migration/data/v310/reset_missing_captcha_plugin.php000077700000001722151514672100016577 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; /** * Class captcha_plugin * * Reset the captcha setting to the default plugin if the defined 'captcha_plugin' is missing. */ class reset_missing_captcha_plugin extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('if', array( (is_dir($this->phpbb_root_path . 'includes/captcha/plugins/') && !is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)), array('config.update', array('captcha_plugin', 'phpbb_captcha_nogd')), )), ); } } migration/data/v310/alpha3.php000077700000001354151514672100012034 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class alpha3 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\alpha2', '\phpbb\db\migration\data\v310\avatar_types', '\phpbb\db\migration\data\v310\passwords', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-a3')), ); } } migration/data/v310/softdelete_mcp_modules.php000077700000002442151514672100015410 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class softdelete_mcp_modules extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'mcp' AND module_basename = 'mcp_queue' AND module_mode = 'deleted_topics'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); return $module_id !== false; } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', '\phpbb\db\migration\data\v310\softdelete_p2', ); } public function update_data() { return array( array('module.add', array( 'mcp', 'MCP_QUEUE', array( 'module_basename' => 'mcp_queue', 'modes' => array('deleted_topics'), ), )), array('module.add', array( 'mcp', 'MCP_QUEUE', array( 'module_basename' => 'mcp_queue', 'modes' => array('deleted_posts'), ), )), ); } } migration/data/v310/profilefield_facebook.php000077700000003111151514672100015152 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_facebook extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), ); } protected $profilefield_name = 'phpbb_facebook'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_facebook', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_facebook', 'field_length' => '20', 'field_minlen' => '5', 'field_maxlen' => '50', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[\w.]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VIEW_FACEBOOK_PROFILE', 'field_contact_url' => 'http://facebook.com/%s/', ); } migration/data/v310/profilefield_aol_cleanup.php000077700000001752151514672100015674 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_aol_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_aim'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_aol', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_aim', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_aim' => array('VCHAR_UNI', ''), ), ), ); } } migration/data/v310/style_update_p1.php000077700000013317151514672100013770 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class style_update_p1 extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_table_exists($this->table_prefix . 'styles_imageset'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'styles' => array( 'style_path' => array('VCHAR:100', ''), 'bbcode_bitfield' => array('VCHAR:255', 'kNg='), 'style_parent_id' => array('UINT', 0), 'style_parent_tree' => array('TEXT', ''), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'styles' => array( 'style_path', 'bbcode_bitfield', 'style_parent_id', 'style_parent_tree', ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'styles_update'))), ); } public function styles_update() { // Get list of valid 3.1 styles $available_styles = array('prosilver'); $iterator = new \DirectoryIterator($this->phpbb_root_path . 'styles'); $skip_dirs = array('.', '..', 'prosilver'); foreach ($iterator as $fileinfo) { if ($fileinfo->isDir() && !in_array($fileinfo->getFilename(), $skip_dirs) && file_exists($fileinfo->getPathname() . '/style.cfg')) { $style_cfg = parse_cfg_file($fileinfo->getPathname() . '/style.cfg'); if (isset($style_cfg['phpbb_version']) && version_compare($style_cfg['phpbb_version'], '3.1.0-dev', '>=')) { // 3.1 style $available_styles[] = $fileinfo->getFilename(); } } } // Get all installed styles if ($this->db_tools->sql_table_exists($this->table_prefix . 'styles_imageset')) { $sql = 'SELECT s.style_id, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_id, i.imageset_path FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . 'styles_theme c, ' . $this->table_prefix . "styles_imageset i WHERE t.template_id = s.template_id AND c.theme_id = s.theme_id AND i.imageset_id = s.imageset_id"; } else { $sql = 'SELECT s.style_id, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_id FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "styles_theme c WHERE t.template_id = s.template_id AND c.theme_id = s.theme_id"; } $result = $this->db->sql_query($sql); $styles = array(); while ($row = $this->db->sql_fetchrow($result)) { $styles[] = $row; } $this->db->sql_freeresult($result); // Decide which styles to keep, all others will be deleted $valid_styles = array(); foreach ($styles as $style_row) { if ( // Delete styles with parent style (not supported yet) $style_row['template_inherits_id'] == 0 && // Check if components match $style_row['template_path'] == $style_row['theme_path'] && (!isset($style_row['imageset_path']) || $style_row['template_path'] == $style_row['imageset_path']) && // Check if components are valid in_array($style_row['template_path'], $available_styles) ) { // Valid style. Keep it $sql_ary = array( 'style_path' => $style_row['template_path'], 'bbcode_bitfield' => $style_row['bbcode_bitfield'], 'style_parent_id' => 0, 'style_parent_tree' => '', ); $this->sql_query('UPDATE ' . STYLES_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE style_id = ' . $style_row['style_id']); $valid_styles[] = (int) $style_row['style_id']; } } // Remove old entries from styles table if (!sizeof($valid_styles)) { // No valid styles: remove everything and add prosilver $this->sql_query('DELETE FROM ' . STYLES_TABLE); $sql_ary = array( 'style_name' => 'prosilver', 'style_copyright' => '© phpBB Limited', 'style_active' => 1, 'style_path' => 'prosilver', 'bbcode_bitfield' => 'lNg=', 'style_parent_id' => 0, 'style_parent_tree' => '', // Will be removed in the next step 'imageset_id' => 0, 'template_id' => 0, 'theme_id' => 0, ); $sql = 'INSERT INTO ' . STYLES_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary); $this->sql_query($sql); $sql = 'SELECT style_id FROM ' . STYLES_TABLE . " WHERE style_name = 'prosilver'"; $result = $this->sql_query($sql); $default_style = $this->db->sql_fetchfield($result); $this->db->sql_freeresult($result); $this->config->set('default_style', $default_style); $sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = 0'; $this->sql_query($sql); } else { // There are valid styles in styles table. Remove styles that are outdated $this->sql_query('DELETE FROM ' . STYLES_TABLE . ' WHERE ' . $this->db->sql_in_set('style_id', $valid_styles, true)); // Change default style if (!in_array($this->config['default_style'], $valid_styles)) { $this->sql_query('UPDATE ' . CONFIG_TABLE . " SET config_value = '" . $valid_styles[0] . "' WHERE config_name = 'default_style'"); } // Reset styles for users $this->sql_query('UPDATE ' . USERS_TABLE . ' SET user_style = 0 WHERE ' . $this->db->sql_in_set('user_style', $valid_styles, true)); } } } migration/data/v310/timezone_p2.php000077700000001710151514672100013113 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class timezone_p2 extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_dst'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\timezone'); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_dst', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_dst' => array('BOOL', 0), ), ), ); } } migration/data/v310/live_searches_config.php000077700000001140151514672100015016 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class live_searches_config extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['allow_live_searches']); } public function update_data() { return array( array('config.add', array('allow_live_searches', '1')), ); } } migration/data/v310/profilefield_yahoo.php000077700000002664151514672100014534 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_yahoo extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_wlm_cleanup', ); } protected $profilefield_name = 'phpbb_yahoo'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_yahoo', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_yahoo', 'field_length' => '40', 'field_minlen' => '5', 'field_maxlen' => '255', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_on_ml' => 0, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'SEND_YIM_MESSAGE', 'field_contact_url' => 'http://edit.yahoo.com/config/send_webmesg?.target=%s&.src=pg', ); protected $user_column_name = 'user_yim'; } migration/data/v310/signature_module_auth.php000077700000002473151514672100015256 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class signature_module_auth extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_auth FROM ' . MODULES_TABLE . " WHERE module_class = 'ucp' AND module_basename = 'ucp_profile' AND module_mode = 'signature'"; $result = $this->db->sql_query($sql); $module_auth = $this->db->sql_fetchfield('module_auth'); $this->db->sql_freeresult($result); return $module_auth === 'acl_u_sig' || $module_auth === false; } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('custom', array( array($this, 'update_signature_module_auth'), ), ), ); } public function update_signature_module_auth() { $sql = 'UPDATE ' . MODULES_TABLE . " SET module_auth = 'acl_u_sig' WHERE module_class = 'ucp' AND module_basename = 'ucp_profile' AND module_mode = 'signature' AND module_auth = ''"; $this->db->sql_query($sql); } } migration/data/v310/profilefield_website.php000077700000002672151514672100015056 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_website extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_on_memberlist', '\phpbb\db\migration\data\v310\profilefield_icq_cleanup', ); } protected $profilefield_name = 'phpbb_website'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_website', 'field_type' => 'profilefields.type.url', 'field_ident' => 'phpbb_website', 'field_length' => '40', 'field_minlen' => '12', 'field_maxlen' => '255', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_on_ml' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VISIT_WEBSITE', 'field_contact_url' => '%s', ); protected $user_column_name = 'user_website'; } migration/data/v310/profilefield_icq.php000077700000002563151514672100014167 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_icq extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', ); } protected $profilefield_name = 'phpbb_icq'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_icq', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_icq', 'field_length' => '20', 'field_minlen' => '3', 'field_maxlen' => '15', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[0-9]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'SEND_ICQ_MESSAGE', 'field_contact_url' => 'https://www.icq.com/people/%s/', ); protected $user_column_name = 'user_icq'; } migration/data/v310/profilefield_occupation.php000077700000002402151514672100015547 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_occupation extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_interests', ); } protected $profilefield_name = 'phpbb_occupation'; protected $profilefield_database_type = array('MTEXT', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_occupation', 'field_type' => 'profilefields.type.text', 'field_ident' => 'phpbb_occupation', 'field_length' => '3|30', 'field_minlen' => '2', 'field_maxlen' => '500', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 0, 'field_show_on_vt' => 0, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, ); protected $user_column_name = 'user_occ'; } migration/data/v310/profilefield_location.php000077700000002466151514672100015225 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_location extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_types', '\phpbb\db\migration\data\v310\profilefield_on_memberlist', ); } protected $profilefield_name = 'phpbb_location'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_location', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_location', 'field_length' => '20', 'field_minlen' => '2', 'field_maxlen' => '100', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, ); protected $user_column_name = 'user_from'; } migration/data/v310/topic_sort_username.php000077700000001627151514672100014753 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class topic_sort_username extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'topics' => array( 'topic_first_poster_name' => array('VCHAR_UNI:255', '', 'true_sort'), ), ), ); } public function revert_schema() { return array( 'change_columns' => array( $this->table_prefix . 'topics' => array( 'topic_first_poster_name' => array('VCHAR_UNI:255', ''), ), ), ); } } migration/data/v310/search_type.php000077700000001413151514672100013166 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class search_type extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_data() { return array( array('if', array( (is_file($this->phpbb_root_path . 'phpbb/search/' . $this->config['search_type'] . $this->php_ext)), array('config.update', array('search_type', '\\phpbb\\search\\' . $this->config['search_type'])), )), ); } } migration/data/v310/contact_admin_form.php000077700000002220151514672100014503 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class contact_admin_form extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['contact_admin_form_enable']); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\config_db_text'); } public function update_data() { return array( array('config.add', array('contact_admin_form_enable', 1)), array('custom', array(array($this, 'contact_admin_info'))), ); } public function contact_admin_info() { $text_config = new \phpbb\config\db_text($this->db, $this->table_prefix . 'config_text'); $text_config->set_array(array( 'contact_admin_info' => '', 'contact_admin_info_uid' => '', 'contact_admin_info_bitfield' => '', 'contact_admin_info_flags' => OPTION_FLAG_BBCODE + OPTION_FLAG_SMILIES + OPTION_FLAG_LINKS, )); } } migration/data/v310/mysql_fulltext_drop.php000077700000003365151514672100015010 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class mysql_fulltext_drop extends \phpbb\db\migration\migration { protected $indexes; public function effectively_installed() { // This migration is irrelevant for all non-MySQL DBMSes. if (strpos($this->db->get_sql_layer(), 'mysql') === false) { return true; } $this->find_indexes_to_drop(); return empty($this->indexes); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_schema() { if (empty($this->indexes)) { return array(); } /* * Drop FULLTEXT indexes related to MySQL fulltext search. * Doing so is equivalent to dropping the search index from the ACP. * Possibly time-consuming recreation of the search index (i.e. * FULLTEXT indexes) is left as a task to the admin to not * unnecessarily stall the upgrade process. The new search index will * then require about 40% less table space (also see PHPBB3-11621). */ return array( 'drop_keys' => array( $this->table_prefix . 'posts' => $this->indexes, ), ); } public function find_indexes_to_drop() { if ($this->indexes !== null) { return $this->indexes; } $this->indexes = array(); $potential_keys = array('post_subject', 'post_text', 'post_content'); foreach ($potential_keys as $key) { if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key)) { $this->indexes[] = $key; } } return $this->indexes; } } migration/data/v310/acp_prune_users_module.php000077700000004471151514672100015431 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class acp_prune_users_module extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_langname = 'ACP_CAT_USERS'"; $result = $this->db->sql_query($sql); $acp_cat_users_id = (int) $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); $sql = 'SELECT parent_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_basename = 'acp_prune' AND module_mode = 'users'"; $result = $this->db->sql_query($sql); $acp_prune_users_parent = (int) $this->db->sql_fetchfield('parent_id'); $this->db->sql_freeresult($result); // Skip migration if "Users" category has been deleted // or the module has already been moved to that category return !$acp_cat_users_id || $acp_cat_users_id === $acp_prune_users_parent; } static public function depends_on() { return array('\phpbb\db\migration\data\v310\beta1'); } public function update_data() { return array( array('custom', array(array($this, 'move_prune_users_module'))), ); } public function move_prune_users_module() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_basename = 'acp_prune' AND module_mode = 'users'"; $result = $this->db->sql_query($sql); $acp_prune_users_id = (int) $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_langname = 'ACP_CAT_USERS'"; $result = $this->db->sql_query($sql); $acp_cat_users_id = (int) $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); if (!class_exists('\acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); } $module_manager = new \acp_modules(); $module_manager->module_class = 'acp'; $module_manager->move_module($acp_prune_users_id, $acp_cat_users_id); } } migration/data/v310/avatar_types.php000077700000002663151514672100013372 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class avatar_types extends \phpbb\db\migration\migration { /** * @var avatar type map */ protected $avatar_type_map = array( AVATAR_UPLOAD => 'avatar.driver.upload', AVATAR_REMOTE => 'avatar.driver.remote', AVATAR_GALLERY => 'avatar.driver.local', ); static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', '\phpbb\db\migration\data\v310\avatars', ); } public function update_data() { return array( array('custom', array(array($this, 'update_user_avatar_type'))), array('custom', array(array($this, 'update_group_avatar_type'))), ); } public function update_user_avatar_type() { foreach ($this->avatar_type_map as $old => $new) { $sql = 'UPDATE ' . $this->table_prefix . "users SET user_avatar_type = '$new' WHERE user_avatar_type = '$old'"; $this->db->sql_query($sql); } } public function update_group_avatar_type() { foreach ($this->avatar_type_map as $old => $new) { $sql = 'UPDATE ' . $this->table_prefix . "groups SET group_avatar_type = '$new' WHERE group_avatar_type = '$old'"; $this->db->sql_query($sql); } } } migration/data/v310/beta2.php000077700000001321151514672100011653 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class beta2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\beta1', '\phpbb\db\migration\data\v310\acp_prune_users_module', '\phpbb\db\migration\data\v310\profilefield_location_cleanup', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-b2')), ); } } migration/data/v310/rc6.php000077700000001121151514672100011346 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc6 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc5', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC6')), ); } } migration/data/v310/profilefield_show_novalue.php000077700000002023151514672100016113 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_show_novalue extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'profile_fields', 'field_show_novalue'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\profilefield_types'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_novalue' => array('BOOL', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_novalue', ), ), ); } } migration/data/v310/captcha_plugins.php000077700000002437151514672100014033 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class captcha_plugins extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc2', ); } public function update_data() { $captcha_plugin = $this->config['captcha_plugin']; if (strpos($captcha_plugin, 'phpbb_captcha_') === 0) { $captcha_plugin = substr($captcha_plugin, strlen('phpbb_captcha_')); } else if (strpos($captcha_plugin, 'phpbb_') === 0) { $captcha_plugin = substr($captcha_plugin, strlen('phpbb_')); } return array( array('if', array( (is_file($this->phpbb_root_path . 'phpbb/captcha/plugins/' . $captcha_plugin . '.' . $this->php_ext)), array('config.update', array('captcha_plugin', 'core.captcha.plugins.' . $captcha_plugin)), )), array('if', array( (!is_file($this->phpbb_root_path . 'phpbb/captcha/plugins/' . $captcha_plugin . '.' . $this->php_ext)), array('config.update', array('captcha_plugin', 'core.captcha.plugins.nogd')), )), ); } } migration/data/v310/rc1.php000077700000002037151514672100011350 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\beta4', '\phpbb\db\migration\data\v310\contact_admin_acp_module', '\phpbb\db\migration\data\v310\contact_admin_form', '\phpbb\db\migration\data\v310\passwords_convert_p2', '\phpbb\db\migration\data\v310\profilefield_facebook', '\phpbb\db\migration\data\v310\profilefield_googleplus', '\phpbb\db\migration\data\v310\profilefield_skype', '\phpbb\db\migration\data\v310\profilefield_twitter', '\phpbb\db\migration\data\v310\profilefield_youtube', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC1')), ); } } migration/data/v310/profilefield_field_validation_length.php000077700000004353151514672100020250 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_field_validation_length extends \phpbb\db\migration\migration { protected $validation_options_old = array( 'ALPHA_SPACERS' => '[\w_\+\. \-\[\]]+', ); protected $validation_options_new = array( 'ALPHA_SPACERS' => '[\w\x20_+\-\[\]]+', ); static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc3', ); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_validation' => array('VCHAR_UNI:64', ''), ), ), ); } public function revert_schema() { return array( 'change_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_validation' => array('VCHAR_UNI:20', ''), ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'update_profile_fields_validation'))), ); } public function revert_data() { return array( array('custom', array(array($this, 'revert_profile_fields_validation'))), ); } public function update_profile_fields_validation() { foreach ($this->validation_options_new as $validation_type => $regex) { $sql = 'UPDATE ' . $this->table_prefix . "profile_fields SET field_validation = '" . $this->db->sql_escape($this->validation_options_new[$validation_type]) . "' WHERE field_validation = '" . $this->db->sql_escape($this->validation_options_old[$validation_type]) . "'"; $this->sql_query($sql); } } public function revert_profile_fields_validation() { foreach ($this->validation_options_new as $validation_type => $regex) { $sql = 'UPDATE ' . $this->table_prefix . "profile_fields SET field_validation = '" . $this->db->sql_escape($this->validation_options_old[$validation_type]) . "' WHERE field_validation = '" . $this->db->sql_escape($this->validation_options_new[$validation_type]) . "'"; $this->sql_query($sql); } } } migration/data/v310/teampage.php000077700000005101151514672100012441 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class teampage extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'teampage'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'teampage' => array( 'COLUMNS' => array( 'teampage_id' => array('UINT', null, 'auto_increment'), 'group_id' => array('UINT', 0), 'teampage_name' => array('VCHAR_UNI:255', ''), 'teampage_position' => array('UINT', 0), 'teampage_parent' => array('UINT', 0), ), 'PRIMARY_KEY' => 'teampage_id', ), ), 'drop_columns' => array( $this->table_prefix . 'groups' => array( 'group_teampage', ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'teampage', ), 'add_columns' => array( $this->table_prefix . 'groups' => array( 'group_teampage' => array('UINT', 0, 'after' => 'group_legend'), ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'add_groups_teampage'))), ); } public function add_groups_teampage() { $sql = 'SELECT teampage_id FROM ' . TEAMPAGE_TABLE; $result = $this->db->sql_query_limit($sql, 1); $added_groups_teampage = (bool) $this->db->sql_fetchfield('teampage_id'); $this->db->sql_freeresult($result); if (!$added_groups_teampage) { $sql = 'SELECT * FROM ' . GROUPS_TABLE . ' WHERE group_type = ' . GROUP_SPECIAL . " AND (group_name = 'ADMINISTRATORS' OR group_name = 'GLOBAL_MODERATORS') ORDER BY group_name ASC"; $result = $this->db->sql_query($sql); $teampage_entries = array(); while ($row = $this->db->sql_fetchrow($result)) { $teampage_entries[] = array( 'group_id' => (int) $row['group_id'], 'teampage_name' => '', 'teampage_position' => sizeof($teampage_entries) + 1, 'teampage_parent' => 0, ); } $this->db->sql_freeresult($result); if (sizeof($teampage_entries)) { $this->db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_entries); } unset($teampage_entries); } } } migration/data/v310/softdelete_p1.php000077700000015031151514672100013417 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class softdelete_p1 extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_visibility'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'forums' => array( 'forum_posts_approved' => array('UINT', 0), 'forum_posts_unapproved' => array('UINT', 0), 'forum_posts_softdeleted' => array('UINT', 0), 'forum_topics_approved' => array('UINT', 0), 'forum_topics_unapproved' => array('UINT', 0), 'forum_topics_softdeleted' => array('UINT', 0), ), $this->table_prefix . 'posts' => array( 'post_visibility' => array('TINT:3', 0), 'post_delete_time' => array('TIMESTAMP', 0), 'post_delete_reason' => array('STEXT_UNI', ''), 'post_delete_user' => array('UINT', 0), ), $this->table_prefix . 'topics' => array( 'topic_visibility' => array('TINT:3', 0), 'topic_delete_time' => array('TIMESTAMP', 0), 'topic_delete_reason' => array('STEXT_UNI', ''), 'topic_delete_user' => array('UINT', 0), 'topic_posts_approved' => array('UINT', 0), 'topic_posts_unapproved' => array('UINT', 0), 'topic_posts_softdeleted' => array('UINT', 0), ), ), 'add_index' => array( $this->table_prefix . 'posts' => array( 'post_visibility' => array('post_visibility'), ), $this->table_prefix . 'topics' => array( 'topic_visibility' => array('topic_visibility'), 'forum_vis_last' => array('forum_id', 'topic_visibility', 'topic_last_post_id'), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'forums' => array( 'forum_posts_approved', 'forum_posts_unapproved', 'forum_posts_softdeleted', 'forum_topics_approved', 'forum_topics_unapproved', 'forum_topics_softdeleted', ), $this->table_prefix . 'posts' => array( 'post_visibility', 'post_delete_time', 'post_delete_reason', 'post_delete_user', ), $this->table_prefix . 'topics' => array( 'topic_visibility', 'topic_delete_time', 'topic_delete_reason', 'topic_delete_user', 'topic_posts_approved', 'topic_posts_unapproved', 'topic_posts_softdeleted', ), ), 'drop_keys' => array( $this->table_prefix . 'posts' => array('post_visibility'), $this->table_prefix . 'topics' => array('topic_visibility', 'forum_vis_last'), ), ); } public function update_data() { return array( array('custom', array(array($this, 'update_post_visibility'))), array('custom', array(array($this, 'update_topic_visibility'))), array('custom', array(array($this, 'update_topics_post_counts'))), array('custom', array(array($this, 'update_forums_topic_and_post_counts'))), array('permission.add', array('f_softdelete', false)), array('permission.add', array('m_softdelete', false)), ); } public function update_post_visibility() { $sql = 'UPDATE ' . $this->table_prefix . 'posts SET post_visibility = post_approved'; $this->sql_query($sql); } public function update_topic_visibility() { $sql = 'UPDATE ' . $this->table_prefix . 'topics SET topic_visibility = topic_approved'; $this->sql_query($sql); } public function update_topics_post_counts() { /* * Using sql_case here to avoid "BIGINT UNSIGNED value is out of range" errors. * As we update all topics in 2 queries, one broken topic would stop the conversion * for all topics and the surpressed error will cause the admin to not even notice it. */ $sql = 'UPDATE ' . $this->table_prefix . 'topics SET topic_posts_approved = topic_replies + 1, topic_posts_unapproved = ' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ' WHERE topic_visibility = ' . ITEM_APPROVED; $this->sql_query($sql); $sql = 'UPDATE ' . $this->table_prefix . 'topics SET topic_posts_approved = 0, topic_posts_unapproved = (' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ') + 1 WHERE topic_visibility = ' . ITEM_UNAPPROVED; $this->sql_query($sql); } public function update_forums_topic_and_post_counts($start) { $start = (int) $start; $limit = 10; $converted_forums = 0; if (!$start) { // Preserve the forum_posts value for link forums as it represents redirects. $sql = 'UPDATE ' . $this->table_prefix . 'forums SET forum_posts_approved = forum_posts WHERE forum_type = ' . FORUM_LINK; $this->db->sql_query($sql); } $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS sum_topics, SUM(topic_posts_approved) AS sum_posts_approved, SUM(topic_posts_unapproved) AS sum_posts_unapproved FROM ' . $this->table_prefix . 'topics GROUP BY forum_id, topic_visibility ORDER BY forum_id, topic_visibility'; $result = $this->db->sql_query_limit($sql, $limit, $start); $update_forums = array(); while ($row = $this->db->sql_fetchrow($result)) { $converted_forums++; $forum_id = (int) $row['forum_id']; if (!isset($update_forums[$forum_id])) { $update_forums[$forum_id] = array( 'forum_posts_approved' => 0, 'forum_posts_unapproved' => 0, 'forum_topics_approved' => 0, 'forum_topics_unapproved' => 0, ); } $update_forums[$forum_id]['forum_posts_approved'] += (int) $row['sum_posts_approved']; $update_forums[$forum_id]['forum_posts_unapproved'] += (int) $row['sum_posts_unapproved']; $update_forums[$forum_id][(($row['topic_visibility'] == ITEM_APPROVED) ? 'forum_topics_approved' : 'forum_topics_unapproved')] += (int) $row['sum_topics']; } $this->db->sql_freeresult($result); foreach ($update_forums as $forum_id => $forum_data) { $sql = 'UPDATE ' . FORUMS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $forum_data) . ' WHERE forum_id = ' . $forum_id; $this->sql_query($sql); } if ($converted_forums < $limit) { // There are no more topics, we are done return; } // There are still more topics to query, return the next start value return $start + $limit; } } migration/data/v310/board_contact_name.php000077700000001276151514672100014471 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class board_contact_name extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['board_contact_name']); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\beta2'); } public function update_data() { return array( array('config.add', array('board_contact_name', '')), ); } } migration/data/v310/contact_admin_acp_module.php000077700000001162151514672100015654 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class contact_admin_acp_module extends \phpbb\db\migration\migration { public function update_data() { return array( array('module.add', array( 'acp', 'ACP_BOARD_CONFIGURATION', array( 'module_basename' => 'acp_contact', 'modes' => array('contact'), ), )), ); } } migration/data/v310/alpha2.php000077700000001220151514672100012023 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class alpha2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\alpha1', '\phpbb\db\migration\data\v310\notifications_cron_p2', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-a2')), ); } } migration/data/v310/avatars.php000077700000004622151514672100012326 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class avatars extends \phpbb\db\migration\migration { public function effectively_installed() { // Get current avatar type of guest user $sql = 'SELECT user_avatar_type FROM ' . $this->table_prefix . 'users WHERE user_id = ' . ANONYMOUS; $result = $this->db->sql_query($sql); $backup_type = $this->db->sql_fetchfield('user_avatar_type'); $this->db->sql_freeresult($result); // Try to set avatar type to string $sql = 'UPDATE ' . $this->table_prefix . "users SET user_avatar_type = 'avatar.driver.upload' WHERE user_id = " . ANONYMOUS; $this->db->sql_return_on_error(true); $effectively_installed = $this->db->sql_query($sql); $this->db->sql_return_on_error(); // Restore avatar type of guest user to previous state $sql = 'UPDATE ' . $this->table_prefix . "users SET user_avatar_type = '{$backup_type}' WHERE user_id = " . ANONYMOUS; $this->db->sql_query($sql); return $effectively_installed !== false; } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_avatar_type' => array('VCHAR:255', ''), ), $this->table_prefix . 'groups' => array( 'group_avatar_type' => array('VCHAR:255', ''), ), ), ); } public function revert_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_avatar_type' => array('TINT:2', ''), ), $this->table_prefix . 'groups' => array( 'group_avatar_type' => array('TINT:2', ''), ), ), ); } public function update_data() { return array( array('config.add', array('allow_avatar_gravatar', 0)), array('custom', array(array($this, 'update_module_auth'))), ); } public function update_module_auth() { $sql = 'UPDATE ' . $this->table_prefix . "modules SET module_auth = 'cfg_allow_avatar' WHERE module_class = 'ucp' AND module_basename = 'ucp_profile' AND module_mode = 'avatar'"; $this->db->sql_query($sql); } } migration/data/v310/notifications.php000077700000005263151514672100013540 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notifications extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'notifications'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'notification_types' => array( 'COLUMNS' => array( 'notification_type' => array('VCHAR:255', ''), 'notification_type_enabled' => array('BOOL', 1), ), 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'), ), $this->table_prefix . 'notifications' => array( 'COLUMNS' => array( 'notification_id' => array('UINT', null, 'auto_increment'), 'item_type' => array('VCHAR:255', ''), 'item_id' => array('UINT', 0), 'item_parent_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'notification_read' => array('BOOL', 0), 'notification_time' => array('TIMESTAMP', 1), 'notification_data' => array('TEXT_UNI', ''), ), 'PRIMARY_KEY' => 'notification_id', 'KEYS' => array( 'item_ident' => array('INDEX', array('item_type', 'item_id')), 'user' => array('INDEX', array('user_id', 'notification_read')), ), ), $this->table_prefix . 'user_notifications' => array( 'COLUMNS' => array( 'item_type' => array('VCHAR:255', ''), 'item_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'method' => array('VCHAR:255', ''), 'notify' => array('BOOL', 1), ), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'notification_types', $this->table_prefix . 'notifications', $this->table_prefix . 'user_notifications', ), ); } public function update_data() { return array( array('module.add', array( 'ucp', 'UCP_MAIN', array( 'module_basename' => 'ucp_notifications', 'modes' => array('notification_list'), ), )), array('module.add', array( 'ucp', 'UCP_PREFS', array( 'module_basename' => 'ucp_notifications', 'modes' => array('notification_options'), ), )), array('config.add', array('load_notifications', 1)), ); } } migration/data/v310/passwords_convert_p1.php000077700000004111151514672100015043 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class passwords_convert_p1 extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\passwords_p2'); } public function update_data() { return array( array('custom', array(array($this, 'update_passwords'))), ); } public function update_passwords($start) { // Nothing to do if user_pass_convert column doesn't exist if (!$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_pass_convert')) { return; } $start = (int) $start; $limit = 1000; $converted_users = 0; $sql = 'SELECT user_password, user_id FROM ' . $this->table_prefix . 'users WHERE user_pass_convert = 1 ORDER BY user_id'; $result = $this->db->sql_query_limit($sql, $limit, $start); $update_users = array(); while ($row = $this->db->sql_fetchrow($result)) { $converted_users++; $user_id = (int) $row['user_id']; // Only prefix passwords without proper prefix if (!isset($update_users[$user_id]) && !preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $row['user_password'])) { // Use $CP$ prefix for passwords that need to // be converted and set pass convert to false. $update_users[$user_id] = array( 'user_password' => '$CP$' . $row['user_password'], 'user_pass_convert' => 0, ); } } $this->db->sql_freeresult($result); foreach ($update_users as $user_id => $user_data) { $sql = 'UPDATE ' . $this->table_prefix . 'users SET ' . $this->db->sql_build_array('UPDATE', $user_data) . ' WHERE user_id = ' . $user_id; $this->sql_query($sql); } if ($converted_users < $limit) { // There are no more users to be converted return; } // There are still more users to query, return the next start value return $start + $limit; } } migration/data/v310/profilefield_cleanup.php000077700000002305151514672100015034 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_occ') && !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_interests'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_interests', '\phpbb\db\migration\data\v310\profilefield_occupation', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_occ', 'user_interests', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_occ' => array('MTEXT', ''), 'user_interests' => array('MTEXT', ''), ), ), ); } } migration/data/v310/timezone.php000077700000015435151514672100012523 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class timezone extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_dst'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_timezone' => array('VCHAR:100', ''), ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'update_timezones'))), ); } public function update_timezones($start) { $start = (int) $start; $limit = 500; $converted = 0; $update_blocks = array(); $sql = 'SELECT user_id, user_timezone, user_dst FROM ' . $this->table_prefix . 'users ORDER BY user_id ASC'; $result = $this->db->sql_query_limit($sql, $limit, $start); while ($row = $this->db->sql_fetchrow($result)) { $converted++; // In case this is somehow run twice on a row. // Otherwise it would just end up as UTC on the second run if (is_numeric($row['user_timezone'])) { $update_blocks[$row['user_timezone'] . ':' . $row['user_dst']][] = (int) $row['user_id']; } } $this->db->sql_freeresult($result); // Update blocks of users who share the same timezone/dst foreach ($update_blocks as $timezone => $user_ids) { $timezone = explode(':', $timezone); $converted_timezone = $this->convert_phpbb30_timezone($timezone[0], $timezone[1]); $sql = 'UPDATE ' . $this->table_prefix . "users SET user_timezone = '" . $this->db->sql_escape($converted_timezone) . "' WHERE " . $this->db->sql_in_set('user_id', $user_ids); $this->sql_query($sql); } if ($converted == $limit) { // There are still more to convert return $start + $limit; } // Update board default timezone $sql = 'UPDATE ' . $this->table_prefix . "config SET config_value = '" . $this->convert_phpbb30_timezone($this->config['board_timezone'], $this->config['board_dst']) . "' WHERE config_name = 'board_timezone'"; $this->sql_query($sql); } /** * Determine the new timezone for a given phpBB 3.0 timezone and * "Daylight Saving Time" option * * @param $timezone float Users timezone in 3.0 * @param $dst int Users daylight saving time * @return string Users new php Timezone which is used since 3.1 */ public function convert_phpbb30_timezone($timezone, $dst) { $offset = $timezone + $dst; switch ($timezone) { case '-12': return 'Etc/GMT+' . abs($offset); //'[UTC - 12] Baker Island Time' case '-11': return 'Etc/GMT+' . abs($offset); //'[UTC - 11] Niue Time, Samoa Standard Time' case '-10': return 'Etc/GMT+' . abs($offset); //'[UTC - 10] Hawaii-Aleutian Standard Time, Cook Island Time' case '-9.5': return 'Pacific/Marquesas'; //'[UTC - 9:30] Marquesas Islands Time' case '-9': return 'Etc/GMT+' . abs($offset); //'[UTC - 9] Alaska Standard Time, Gambier Island Time' case '-8': return 'Etc/GMT+' . abs($offset); //'[UTC - 8] Pacific Standard Time' case '-7': return 'Etc/GMT+' . abs($offset); //'[UTC - 7] Mountain Standard Time' case '-6': return 'Etc/GMT+' . abs($offset); //'[UTC - 6] Central Standard Time' case '-5': return 'Etc/GMT+' . abs($offset); //'[UTC - 5] Eastern Standard Time' case '-4.5': return 'America/Caracas'; //'[UTC - 4:30] Venezuelan Standard Time' case '-4': return 'Etc/GMT+' . abs($offset); //'[UTC - 4] Atlantic Standard Time' case '-3.5': return 'America/St_Johns'; //'[UTC - 3:30] Newfoundland Standard Time' case '-3': return 'Etc/GMT+' . abs($offset); //'[UTC - 3] Amazon Standard Time, Central Greenland Time' case '-2': return 'Etc/GMT+' . abs($offset); //'[UTC - 2] Fernando de Noronha Time, South Georgia & the South Sandwich Islands Time' case '-1': return 'Etc/GMT+' . abs($offset); //'[UTC - 1] Azores Standard Time, Cape Verde Time, Eastern Greenland Time' case '0': return (!$dst) ? 'UTC' : 'Etc/GMT-1'; //'[UTC] Western European Time, Greenwich Mean Time' case '1': return 'Etc/GMT-' . $offset; //'[UTC + 1] Central European Time, West African Time' case '2': return 'Etc/GMT-' . $offset; //'[UTC + 2] Eastern European Time, Central African Time' case '3': return 'Etc/GMT-' . $offset; //'[UTC + 3] Moscow Standard Time, Eastern African Time' case '3.5': return 'Asia/Tehran'; //'[UTC + 3:30] Iran Standard Time' case '4': return 'Etc/GMT-' . $offset; //'[UTC + 4] Gulf Standard Time, Samara Standard Time' case '4.5': return 'Asia/Kabul'; //'[UTC + 4:30] Afghanistan Time' case '5': return 'Etc/GMT-' . $offset; //'[UTC + 5] Pakistan Standard Time, Yekaterinburg Standard Time' case '5.5': return 'Asia/Kolkata'; //'[UTC + 5:30] Indian Standard Time, Sri Lanka Time' case '5.75': return 'Asia/Kathmandu'; //'[UTC + 5:45] Nepal Time' case '6': return 'Etc/GMT-' . $offset; //'[UTC + 6] Bangladesh Time, Bhutan Time, Novosibirsk Standard Time' case '6.5': return 'Indian/Cocos'; //'[UTC + 6:30] Cocos Islands Time, Myanmar Time' case '7': return 'Etc/GMT-' . $offset; //'[UTC + 7] Indochina Time, Krasnoyarsk Standard Time' case '8': return 'Etc/GMT-' . $offset; //'[UTC + 8] Chinese Standard Time, Australian Western Standard Time, Irkutsk Standard Time' case '8.75': return 'Australia/Eucla'; //'[UTC + 8:45] Southeastern Western Australia Standard Time' case '9': return 'Etc/GMT-' . $offset; //'[UTC + 9] Japan Standard Time, Korea Standard Time, Chita Standard Time' case '9.5': return 'Australia/ACT'; //'[UTC + 9:30] Australian Central Standard Time' case '10': return 'Etc/GMT-' . $offset; //'[UTC + 10] Australian Eastern Standard Time, Vladivostok Standard Time' case '10.5': return 'Australia/Lord_Howe'; //'[UTC + 10:30] Lord Howe Standard Time' case '11': return 'Etc/GMT-' . $offset; //'[UTC + 11] Solomon Island Time, Magadan Standard Time' case '11.5': return 'Pacific/Norfolk'; //'[UTC + 11:30] Norfolk Island Time' case '12': return 'Etc/GMT-12'; //'[UTC + 12] New Zealand Time, Fiji Time, Kamchatka Standard Time' case '12.75': return 'Pacific/Chatham'; //'[UTC + 12:45] Chatham Islands Time' case '13': return 'Pacific/Tongatapu'; //'[UTC + 13] Tonga Time, Phoenix Islands Time' case '14': return 'Pacific/Kiritimati'; //'[UTC + 14] Line Island Time' default: return 'UTC'; } } } migration/data/v310/beta4.php000077700000001341151514672100011657 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class beta4 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\beta3', '\phpbb\db\migration\data\v310\extensions_version_check_force_unstable', '\phpbb\db\migration\data\v310\reset_missing_captcha_plugin', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-b4')), ); } } migration/data/v310/extensions_version_check_force_unstable.php000077700000001165151514672100021040 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class extensions_version_check_force_unstable extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('config.add', array('extension_force_unstable', false)), ); } } migration/data/v310/beta3.php000077700000001550151514672100011660 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class beta3 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\beta2', '\phpbb\db\migration\data\v310\auth_provider_oauth2', '\phpbb\db\migration\data\v310\board_contact_name', '\phpbb\db\migration\data\v310\jquery_update2', '\phpbb\db\migration\data\v310\live_searches_config', '\phpbb\db\migration\data\v310\prune_shadow_topics', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-b3')), ); } } migration/data/v310/prune_shadow_topics.php000077700000002063151514672100014741 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class prune_shadow_topics extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'forums' => array( 'enable_shadow_prune' => array('BOOL', 0), 'prune_shadow_days' => array('UINT', 7), 'prune_shadow_freq' => array('UINT', 1), 'prune_shadow_next' => array('INT:11', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'forums' => array( 'enable_shadow_prune', 'prune_shadow_days', 'prune_shadow_freq', 'prune_shadow_next', ), ), ); } } migration/data/v310/profilefield_contact_field.php000077700000002272151514672100016206 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_contact_field extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'profile_fields', 'field_is_contact'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_on_memberlist', ); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_is_contact' => array('BOOL', 0), 'field_contact_desc' => array('VCHAR', ''), 'field_contact_url' => array('VCHAR', ''), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_is_contact', 'field_contact_desc', 'field_contact_url', ), ), ); } } migration/data/v310/profilefield_wlm.php000077700000002541151514672100014206 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_wlm extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_website_cleanup', ); } protected $profilefield_name = 'phpbb_wlm'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_wlm', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_wlm', 'field_length' => '40', 'field_minlen' => '5', 'field_maxlen' => '255', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_on_ml' => 0, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => '', 'field_contact_url' => '', ); protected $user_column_name = 'user_msnm'; } migration/data/v310/rc4.php000077700000001221151514672100011345 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc4 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc3', '\phpbb\db\migration\data\v310\notifications_use_full_name', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC4')), ); } } migration/data/v310/rc3.php000077700000001451151514672100011351 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc3 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc2', '\phpbb\db\migration\data\v310\captcha_plugins', '\phpbb\db\migration\data\v310\rename_too_long_indexes', '\phpbb\db\migration\data\v310\search_type', '\phpbb\db\migration\data\v310\topic_sort_username', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC3')), ); } } migration/data/v310/gold.php000077700000001175151514672100011612 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class gold extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc6', '\phpbb\db\migration\data\v310\bot_update', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0')), ); } } migration/data/v310/passwords_p2.php000077700000001556151514672100013316 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class passwords_p2 extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\passwords'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_newpasswd' => array('VCHAR:255', ''), ), ), ); } public function revert_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_newpasswd' => array('VCHAR:40', ''), ), ), ); } } migration/data/v310/auth_provider_oauth.php000077700000003463151514672100014742 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class auth_provider_oauth extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'auth_provider_oauth'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'oauth_tokens' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), // phpbb_users.user_id 'session_id' => array('CHAR:32', ''), // phpbb_sessions.session_id used only when user_id not set 'provider' => array('VCHAR', ''), // Name of the OAuth provider 'oauth_token' => array('MTEXT', ''), // Serialized token ), 'KEYS' => array( 'user_id' => array('INDEX', 'user_id'), 'provider' => array('INDEX', 'provider'), ), ), $this->table_prefix . 'oauth_accounts' => array( 'COLUMNS' => array( 'user_id' => array('UINT', 0), 'provider' => array('VCHAR', ''), 'oauth_provider_id' => array('TEXT_UNI', ''), ), 'PRIMARY_KEY' => array( 'user_id', 'provider', ), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'oauth_tokens', $this->table_prefix . 'oauth_accounts', ), ); } public function update_data() { return array( array('module.add', array( 'ucp', 'UCP_PROFILE', array( 'module_basename' => 'ucp_auth_link', 'modes' => array('auth_link'), ), )), ); } } migration/data/v310/notifications_cron.php000077700000001434151514672100014555 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notifications_cron extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\notifications'); } public function update_data() { return array( array('config.add', array('read_notification_expire_days', 30)), array('config.add', array('read_notification_last_gc', 0)), // last run array('config.add', array('read_notification_gc', (60 * 60 * 24))), // seconds between run; 1 day ); } } migration/data/v310/postgres_fulltext_drop.php000077700000003405151514672100015504 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class postgres_fulltext_drop extends \phpbb\db\migration\migration { protected $indexes; public function effectively_installed() { // This migration is irrelevant for all non-PostgreSQL DBMSes. if (strpos($this->db->get_sql_layer(), 'postgres') === false) { return true; } $this->find_indexes_to_drop(); return empty($this->indexes); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_schema() { if (empty($this->indexes)) { return array(); } /* * Drop FULLTEXT indexes related to PostgreSQL fulltext search. * Doing so is equivalent to dropping the search index from the ACP. * Possibly time-consuming recreation of the search index (i.e. * FULLTEXT indexes) is left as a task to the admin to not * unnecessarily stall the upgrade process. The new search index will * then require about 40% less table space (also see PHPBB3-11040). */ return array( 'drop_keys' => array( $this->table_prefix . 'posts' => $this->indexes, ), ); } public function find_indexes_to_drop() { if ($this->indexes !== null) { return $this->indexes; } $this->indexes = array(); $potential_keys = array('post_subject', 'post_text', 'post_content'); foreach ($potential_keys as $key) { if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key)) { $this->indexes[] = $key; } } return $this->indexes; } } migration/data/v310/namespaces.php000077700000001402151514672100012775 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class namespaces extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_data() { return array( array('if', array( (preg_match('#^phpbb_search_#', $this->config['search_type'])), array('config.update', array('search_type', str_replace('phpbb_search_', '\\phpbb\\search\\', $this->config['search_type']))), )), ); } } migration/data/v310/softdelete_p2.php000077700000004117151514672100013423 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class softdelete_p2 extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_approved'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', '\phpbb\db\migration\data\v310\softdelete_p1', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'forums' => array('forum_posts', 'forum_topics', 'forum_topics_real'), $this->table_prefix . 'posts' => array('post_approved'), $this->table_prefix . 'topics' => array('topic_approved', 'topic_replies', 'topic_replies_real'), ), 'drop_keys' => array( $this->table_prefix . 'posts' => array('post_approved'), $this->table_prefix . 'topics' => array( 'forum_appr_last', 'topic_approved', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'forums' => array( 'forum_posts' => array('UINT', 0), 'forum_topics' => array('UINT', 0), 'forum_topics_real' => array('UINT', 0), ), $this->table_prefix . 'posts' => array( 'post_approved' => array('BOOL', 1), ), $this->table_prefix . 'topics' => array( 'topic_approved' => array('BOOL', 1), 'topic_replies' => array('UINT', 0), 'topic_replies_real' => array('UINT', 0), ), ), 'add_index' => array( $this->table_prefix . 'posts' => array( 'post_approved' => array('post_approved'), ), $this->table_prefix . 'topics' => array( 'forum_appr_last' => array('forum_id', 'topic_approved', 'topic_last_post_id'), 'topic_approved' => array('topic_approved'), ), ), ); } } migration/data/v310/profilefield_types.php000077700000005535151514672100014561 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_types extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\alpha2', ); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_type' => array('VCHAR:100', ''), ), $this->table_prefix . 'profile_fields_lang' => array( 'field_type' => array('VCHAR:100', ''), ), ), ); } public function update_data() { return array( array('custom', array(array($this, 'update_profile_fields_type'))), array('custom', array(array($this, 'update_profile_fields_lang_type'))), ); } public function update_profile_fields_type() { // Update profile field types $sql = 'SELECT field_type FROM ' . $this->table_prefix . 'profile_fields GROUP BY field_type'; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $sql = 'UPDATE ' . $this->table_prefix . "profile_fields SET field_type = '" . $this->db->sql_escape($this->convert_phpbb30_field_type($row['field_type'])) . "' WHERE field_type = '" . $this->db->sql_escape($row['field_type']) . "'"; $this->sql_query($sql); } $this->db->sql_freeresult($result); } public function update_profile_fields_lang_type() { // Update profile field language types $sql = 'SELECT field_type FROM ' . $this->table_prefix . 'profile_fields_lang GROUP BY field_type'; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $sql = 'UPDATE ' . $this->table_prefix . "profile_fields_lang SET field_type = '" . $this->db->sql_escape($this->convert_phpbb30_field_type($row['field_type'])) . "' WHERE field_type = '" . $this->db->sql_escape($row['field_type']) . "'"; $this->sql_query($sql); } $this->db->sql_freeresult($result); } /** * Determine the new field type for a given phpBB 3.0 field type * * @param $field_type string Field type in 3.0 * @return string Field new type which is used since 3.1 */ public function convert_phpbb30_field_type($field_type) { switch ($field_type) { case FIELD_INT: return 'profilefields.type.int'; case FIELD_STRING: return 'profilefields.type.string'; case FIELD_TEXT: return 'profilefields.type.text'; case FIELD_BOOL: return 'profilefields.type.bool'; case FIELD_DROPDOWN: return 'profilefields.type.dropdown'; case FIELD_DATE: return 'profilefields.type.date'; default: return $field_type; } } } migration/data/v310/ucp_popuppm_module.php000077700000001725151514672100014602 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class ucp_popuppm_module extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'ucp' AND module_langname = 'UCP_PM_POPUP_TITLE'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); return $module_id == false; } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('module.remove', array( 'ucp', 'UCP_PM', 'UCP_PM_POPUP_TITLE', )), ); } } migration/data/v310/profilefield_googleplus.php000077700000003131151514672100015563 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_googleplus extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), ); } protected $profilefield_name = 'phpbb_googleplus'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_googleplus', 'field_type' => 'profilefields.type.googleplus', 'field_ident' => 'phpbb_googleplus', 'field_length' => '20', 'field_minlen' => '3', 'field_maxlen' => '255', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[\w]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VIEW_GOOGLEPLUS_PROFILE', 'field_contact_url' => 'http://plus.google.com/%s', ); } migration/data/v310/forgot_password.php000077700000001307151514672100014104 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class forgot_password extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['allow_password_reset']); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_data() { return array( array('config.add', array('allow_password_reset', 1)), ); } } migration/data/v310/notifications_schema_fix.php000077700000006107151514672100015724 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notifications_schema_fix extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\notifications'); } public function update_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'notification_types', $this->table_prefix . 'notifications', ), 'add_tables' => array( $this->table_prefix . 'notification_types' => array( 'COLUMNS' => array( 'notification_type_id' => array('USINT', null, 'auto_increment'), 'notification_type_name' => array('VCHAR:255', ''), 'notification_type_enabled' => array('BOOL', 1), ), 'PRIMARY_KEY' => array('notification_type_id'), 'KEYS' => array( 'type' => array('UNIQUE', array('notification_type_name')), ), ), $this->table_prefix . 'notifications' => array( 'COLUMNS' => array( 'notification_id' => array('UINT:10', null, 'auto_increment'), 'notification_type_id' => array('USINT', 0), 'item_id' => array('UINT', 0), 'item_parent_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'notification_read' => array('BOOL', 0), 'notification_time' => array('TIMESTAMP', 1), 'notification_data' => array('TEXT_UNI', ''), ), 'PRIMARY_KEY' => 'notification_id', 'KEYS' => array( 'item_ident' => array('INDEX', array('notification_type_id', 'item_id')), 'user' => array('INDEX', array('user_id', 'notification_read')), ), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'notification_types', $this->table_prefix . 'notifications', ), 'add_tables' => array( $this->table_prefix . 'notification_types' => array( 'COLUMNS' => array( 'notification_type' => array('VCHAR:255', ''), 'notification_type_enabled' => array('BOOL', 1), ), 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'), ), $this->table_prefix . 'notifications' => array( 'COLUMNS' => array( 'notification_id' => array('UINT', null, 'auto_increment'), 'item_type' => array('VCHAR:255', ''), 'item_id' => array('UINT', 0), 'item_parent_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'notification_read' => array('BOOL', 0), 'notification_time' => array('TIMESTAMP', 1), 'notification_data' => array('TEXT_UNI', ''), ), 'PRIMARY_KEY' => 'notification_id', 'KEYS' => array( 'item_ident' => array('INDEX', array('item_type', 'item_id')), 'user' => array('INDEX', array('user_id', 'notification_read')), ), ), ), ); } } migration/data/v310/notifications_cron_p2.php000077700000001337151514672100015160 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notifications_cron_p2 extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\notifications_cron'); } public function update_data() { return array( // Make read_notification_last_gc dynamic. array('config.remove', array('read_notification_last_gc')), array('config.add', array('read_notification_last_gc', 0, 1)), ); } } migration/data/v310/config_db_text.php000077700000002045151514672100013640 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class config_db_text extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'config_text'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'config_text' => array( 'COLUMNS' => array( 'config_name' => array('VCHAR', ''), 'config_value' => array('MTEXT', ''), ), 'PRIMARY_KEY' => 'config_name', ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'config_text', ), ); } } migration/data/v310/bot_update.php000077700000007540151514672100013015 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class bot_update extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\rc6'); } public function update_data() { return array( array('custom', array(array(&$this, 'update_bing_bot'))), array('custom', array(array(&$this, 'update_bots'))), ); } public function update_bing_bot() { $bot_name = 'Bing [Bot]'; $bot_name_clean = utf8_clean_string($bot_name); $sql = 'SELECT user_id FROM ' . USERS_TABLE . " WHERE username_clean = '" . $this->db->sql_escape($bot_name_clean) . "'"; $result = $this->db->sql_query($sql); $bing_already_added = (bool) $this->db->sql_fetchfield('user_id'); $this->db->sql_freeresult($result); if (!$bing_already_added) { $bot_agent = 'bingbot/'; $bot_ip = ''; $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'"; $result = $this->db->sql_query($sql); $group_row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); if (!$group_row) { // default fallback, should never get here $group_row['group_id'] = 6; $group_row['group_colour'] = '9E8DA7'; } if (!function_exists('user_add')) { include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); } $user_row = array( 'user_type' => USER_IGNORE, 'group_id' => $group_row['group_id'], 'username' => $bot_name, 'user_regdate' => time(), 'user_password' => '', 'user_colour' => $group_row['group_colour'], 'user_email' => '', 'user_lang' => $this->config['default_lang'], 'user_style' => $this->config['default_style'], 'user_timezone' => 0, 'user_dateformat' => $this->config['default_dateformat'], 'user_allow_massemail' => 0, ); $user_id = user_add($user_row); $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', array( 'bot_active' => 1, 'bot_name' => (string) $bot_name, 'user_id' => (int) $user_id, 'bot_agent' => (string) $bot_agent, 'bot_ip' => (string) $bot_ip, )); $this->sql_query($sql); } } public function update_bots() { // Update bots if (!function_exists('user_delete')) { include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); } $bots_updates = array( // Bot Deletions 'NG-Search [Bot]' => false, 'Nutch/CVS [Bot]' => false, 'OmniExplorer [Bot]' => false, 'Seekport [Bot]' => false, 'Synoo [Bot]' => false, 'WiseNut [Bot]' => false, // Bot Updates // Bot name to bot user agent map 'Baidu [Spider]' => 'Baiduspider', 'Exabot [Bot]' => 'Exabot', 'Voyager [Bot]' => 'voyager/', 'W3C [Validator]' => 'W3C_Validator', ); foreach ($bots_updates as $bot_name => $bot_agent) { $sql = 'SELECT user_id FROM ' . USERS_TABLE . ' WHERE user_type = ' . USER_IGNORE . " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($bot_name)) . "'"; $result = $this->db->sql_query($sql); $bot_user_id = (int) $this->db->sql_fetchfield('user_id'); $this->db->sql_freeresult($result); if ($bot_user_id) { if ($bot_agent === false) { $sql = 'DELETE FROM ' . BOTS_TABLE . " WHERE user_id = $bot_user_id"; $this->sql_query($sql); user_delete('retain', $bot_user_id); } else { $sql = 'UPDATE ' . BOTS_TABLE . " SET bot_agent = '" . $this->db->sql_escape($bot_agent) . "' WHERE user_id = $bot_user_id"; $this->sql_query($sql); } } } } } migration/data/v310/acp_style_components_module.php000077700000001737151514672100016466 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class acp_style_components_module extends \phpbb\db\migration\migration { public function effectively_installed() { $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_class = 'acp' AND module_langname = 'ACP_STYLE_COMPONENTS'"; $result = $this->db->sql_query($sql); $module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); return $module_id == false; } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('module.remove', array( 'acp', false, 'ACP_STYLE_COMPONENTS', )), ); } } migration/data/v310/alpha1.php000077700000002733151514672100012034 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class alpha1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v30x\local_url_bbcode', '\phpbb\db\migration\data\v30x\release_3_0_12', '\phpbb\db\migration\data\v310\acp_style_components_module', '\phpbb\db\migration\data\v310\allow_cdn', '\phpbb\db\migration\data\v310\auth_provider_oauth', '\phpbb\db\migration\data\v310\avatars', '\phpbb\db\migration\data\v310\boardindex', '\phpbb\db\migration\data\v310\config_db_text', '\phpbb\db\migration\data\v310\forgot_password', '\phpbb\db\migration\data\v310\mod_rewrite', '\phpbb\db\migration\data\v310\mysql_fulltext_drop', '\phpbb\db\migration\data\v310\namespaces', '\phpbb\db\migration\data\v310\notifications_cron', '\phpbb\db\migration\data\v310\notification_options_reconvert', '\phpbb\db\migration\data\v310\plupload', '\phpbb\db\migration\data\v310\signature_module_auth', '\phpbb\db\migration\data\v310\softdelete_mcp_modules', '\phpbb\db\migration\data\v310\teampage', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-a1')), ); } } migration/data/v310/notifications_use_full_name.php000077700000012754151514672100016441 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notifications_use_full_name extends \phpbb\db\migration\migration { protected $notification_types = array( 'admin_activate_user', 'approve_post', 'approve_topic', 'bookmark', 'disapprove_post', 'disapprove_topic', 'group_request', 'group_request_approved', 'pm', 'post', 'post_in_queue', 'quote', 'report_pm', 'report_pm_closed', 'report_post', 'report_post_closed', 'topic', 'topic_in_queue'); protected $notification_methods = array( 'email', 'jabber', ); static public function depends_on() { return array('\phpbb\db\migration\data\v310\rc3'); } public function update_data() { return array( array('custom', array(array($this, 'update_notifications_name'))), array('custom', array(array($this, 'update_notifications_method_name'))), ); } public function revert_data() { return array( array('custom', array(array($this, 'revert_notifications_name'))), array('custom', array(array($this, 'revert_notifications_method_name'))), ); } public function update_notifications_method_name() { foreach ($this->notification_methods as $notification_method) { $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET method = 'notification.method.{$notification_method}' WHERE method = '{$notification_method}'"; $this->db->sql_query($sql); } } public function revert_notifications_method_name() { foreach ($this->notification_methods as $notification_method) { $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET method = '{$notification_method}' WHERE method = 'notification.method.{$notification_method}'"; $this->db->sql_query($sql); } } public function update_notifications_name() { $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . ' SET notification_type_enabled = 0 WHERE ' . $this->db->sql_in_set('notification_type_name', $this->notification_types, true); $this->db->sql_query($sql); foreach ($this->notification_types as $notification_type) { $sql = 'SELECT notification_type_id FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = 'notification.type.{$notification_type}'"; $result = $this->db->sql_query($sql); $new_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); $this->db->sql_freeresult($result); if ($new_type_id) { // New type name already exists, // so we delete the old type and update the type id of existing entries. $sql = 'SELECT notification_type_id FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = '{$notification_type}'"; $result = $this->db->sql_query($sql); $old_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); $this->db->sql_freeresult($result); $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' SET notification_type_id = ' . (int) $new_type_id . ' WHERE notification_type_id = ' . (int) $old_type_id; $this->db->sql_query($sql); $sql = 'DELETE FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = '{$notification_type}'"; $this->db->sql_query($sql); } else { // Otherwise we just update the name $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " SET notification_type_name = 'notification.type.{$notification_type}' WHERE notification_type_name = '{$notification_type}'"; $this->db->sql_query($sql); } $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET item_type = 'notification.type.{$notification_type}' WHERE item_type = '{$notification_type}'"; $this->db->sql_query($sql); } } public function revert_notifications_name() { foreach ($this->notification_types as $notification_type) { $sql = 'SELECT notification_type_id FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = '{$notification_type}'"; $result = $this->db->sql_query($sql); $new_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); $this->db->sql_freeresult($result); if ($new_type_id) { // New type name already exists, // so we delete the old type and update the type id of existing entries. $sql = 'SELECT notification_type_id FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = 'notification.type.{$notification_type}'"; $result = $this->db->sql_query($sql); $old_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); $this->db->sql_freeresult($result); $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' SET notification_type_id = ' . (int) $new_type_id . ' WHERE notification_type_id = ' . (int) $old_type_id; $this->db->sql_query($sql); $sql = 'DELETE FROM ' . NOTIFICATION_TYPES_TABLE . " WHERE notification_type_name = 'notification.type.{$notification_type}'"; $this->db->sql_query($sql); } else { // Otherwise we just update the name $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " SET notification_type_name = '{$notification_type}' WHERE notification_type_name = 'notification.type.{$notification_type}'"; $this->db->sql_query($sql); } $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET item_type = '{$notification_type}' WHERE item_type = 'notification.type.{$notification_type}'"; $this->db->sql_query($sql); } } } migration/data/v310/passwords_convert_p2.php000077700000002022151514672100015043 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class passwords_convert_p2 extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_pass_convert'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\passwords_convert_p1'); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_pass_convert', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_pass_convert' => array('BOOL', 0, 'after' => 'user_passchg'), ), ), ); } } migration/data/v310/extensions.php000077700000003026151514672100013061 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class extensions extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_table_exists($this->table_prefix . 'ext'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'add_tables' => array( $this->table_prefix . 'ext' => array( 'COLUMNS' => array( 'ext_name' => array('VCHAR', ''), 'ext_active' => array('BOOL', 0), 'ext_state' => array('TEXT', ''), ), 'KEYS' => array( 'ext_name' => array('UNIQUE', 'ext_name'), ), ), ), ); } public function revert_schema() { return array( 'drop_tables' => array( $this->table_prefix . 'ext', ), ); } public function update_data() { return array( // Module will be renamed later array('module.add', array( 'acp', 'ACP_CAT_STYLES', 'ACP_EXTENSION_MANAGEMENT' )), array('module.add', array( 'acp', 'ACP_EXTENSION_MANAGEMENT', array( 'module_basename' => 'acp_extensions', 'modes' => array('main'), ), )), array('permission.add', array('a_extensions', true, 'a_styles')), ); } } migration/data/v310/notification_options_reconvert.php000077700000006415151514672100017217 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class notification_options_reconvert extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v310\notifications_schema_fix'); } public function update_data() { return array( array('custom', array(array($this, 'purge_notifications'))), array('custom', array(array($this, 'convert_notifications'))), ); } public function purge_notifications() { $sql = 'DELETE FROM ' . $this->table_prefix . 'user_notifications'; $this->sql_query($sql); } public function convert_notifications($start) { $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->table_prefix . 'user_notifications'); return $this->perform_conversion($insert_buffer, $start); } /** * Perform the conversion (separate for testability) * * @param \phpbb\db\sql_insert_buffer $insert_buffer * @param int $start Start of staggering step * @return mixed int start of the next step, null if the end was reached */ public function perform_conversion(\phpbb\db\sql_insert_buffer $insert_buffer, $start) { $limit = 250; $converted_users = 0; $sql = 'SELECT user_id, user_notify_type, user_notify_pm FROM ' . $this->table_prefix . 'users ORDER BY user_id'; $result = $this->db->sql_query_limit($sql, $limit, $start); while ($row = $this->db->sql_fetchrow($result)) { $converted_users++; $notification_methods = array(); // In-board notification $notification_methods[] = ''; if ($row['user_notify_type'] == NOTIFY_EMAIL || $row['user_notify_type'] == NOTIFY_BOTH) { $notification_methods[] = 'email'; } if ($row['user_notify_type'] == NOTIFY_IM || $row['user_notify_type'] == NOTIFY_BOTH) { $notification_methods[] = 'jabber'; } // Notifications for posts foreach (array('post', 'topic') as $item_type) { $this->add_method_rows( $insert_buffer, $item_type, 0, $row['user_id'], $notification_methods ); } if ($row['user_notify_pm']) { // Notifications for private messages // User either gets all methods or no method $this->add_method_rows( $insert_buffer, 'pm', 0, $row['user_id'], $notification_methods ); } } $this->db->sql_freeresult($result); $insert_buffer->flush(); if ($converted_users < $limit) { // No more users left, we are done... return; } return $start + $limit; } /** * Insert method rows to DB * * @param \phpbb\db\sql_insert_buffer $insert_buffer * @param string $item_type * @param int $item_id * @param int $user_id * @param string $methods */ protected function add_method_rows(\phpbb\db\sql_insert_buffer $insert_buffer, $item_type, $item_id, $user_id, array $methods) { $row_base = array( 'item_type' => $item_type, 'item_id' => (int) $item_id, 'user_id' => (int) $user_id, 'notify' => 1 ); foreach ($methods as $method) { $row_base['method'] = $method; $insert_buffer->insert($row_base); } } } migration/data/v310/dev.php000077700000030412151514672100011437 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class dev extends \phpbb\db\migration\migration { public function effectively_installed() { return version_compare($this->config['version'], '3.1.0-dev', '>='); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\extensions', '\phpbb\db\migration\data\v310\style_update_p2', '\phpbb\db\migration\data\v310\timezone_p2', '\phpbb\db\migration\data\v310\reported_posts_display', '\phpbb\db\migration\data\v310\migrations_table', ); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'groups' => array( 'group_teampage' => array('UINT', 0, 'after' => 'group_legend'), ), $this->table_prefix . 'profile_fields' => array( 'field_show_on_pm' => array('BOOL', 0), ), $this->table_prefix . 'styles' => array( 'style_path' => array('VCHAR:100', ''), 'bbcode_bitfield' => array('VCHAR:255', 'kNg='), 'style_parent_id' => array('UINT:4', 0), 'style_parent_tree' => array('TEXT', ''), ), $this->table_prefix . 'reports' => array( 'reported_post_text' => array('MTEXT_UNI', ''), 'reported_post_uid' => array('VCHAR:8', ''), 'reported_post_bitfield' => array('VCHAR:255', ''), ), ), 'change_columns' => array( $this->table_prefix . 'groups' => array( 'group_legend' => array('UINT', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'groups' => array( 'group_teampage', ), $this->table_prefix . 'profile_fields' => array( 'field_show_on_pm', ), $this->table_prefix . 'styles' => array( 'style_path', 'bbcode_bitfield', 'style_parent_id', 'style_parent_tree', ), $this->table_prefix . 'reports' => array( 'reported_post_text', 'reported_post_uid', 'reported_post_bitfield', ), ), ); } public function update_data() { return array( array('if', array( (strpos('phpbb_search_', $this->config['search_type']) !== 0), array('config.update', array('search_type', 'phpbb_search_' . $this->config['search_type'])), )), array('config.add', array('fulltext_postgres_ts_name', 'simple')), array('config.add', array('fulltext_postgres_min_word_len', 4)), array('config.add', array('fulltext_postgres_max_word_len', 254)), array('config.add', array('fulltext_sphinx_stopwords', 0)), array('config.add', array('fulltext_sphinx_indexer_mem_limit', 512)), array('config.add', array('load_jquery_cdn', 0)), array('config.add', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js')), array('config.add', array('use_system_cron', 0)), array('config.add', array('legend_sort_groupname', 0)), array('config.add', array('teampage_forums', 1)), array('config.add', array('teampage_memberships', 1)), array('config.add', array('load_cpf_pm', 0)), array('config.add', array('display_last_subject', 1)), array('config.add', array('assets_version', 1)), array('config.add', array('site_home_url', '')), array('config.add', array('site_home_text', '')), array('permission.add', array('u_chgprofileinfo', true, 'u_sig')), array('module.add', array( 'acp', 'ACP_GROUPS', array( 'module_basename' => 'acp_groups', 'modes' => array('position'), ), )), array('module.add', array( 'acp', 'ACP_ATTACHMENTS', array( 'module_basename' => 'acp_attachments', 'modes' => array('manage'), ), )), array('module.add', array( 'acp', 'ACP_STYLE_MANAGEMENT', array( 'module_basename' => 'acp_styles', 'modes' => array('install', 'cache'), ), )), array('module.add', array( 'ucp', 'UCP_PROFILE', array( 'module_basename' => 'ucp_profile', 'modes' => array('autologin_keys'), ), )), // Module will be renamed later array('module.add', array( 'acp', 'ACP_CAT_STYLES', 'ACP_LANGUAGE' )), array('module.remove', array( 'acp', false, 'ACP_TEMPLATES', )), array('module.remove', array( 'acp', false, 'ACP_THEMES', )), array('module.remove', array( 'acp', false, 'ACP_IMAGESETS', )), array('custom', array(array($this, 'rename_module_basenames'))), array('custom', array(array($this, 'rename_styles_module'))), array('custom', array(array($this, 'add_group_teampage'))), array('custom', array(array($this, 'update_group_legend'))), array('custom', array(array($this, 'localise_global_announcements'))), array('custom', array(array($this, 'update_ucp_pm_basename'))), array('custom', array(array($this, 'update_ucp_profile_auth'))), array('custom', array(array($this, 'move_customise_modules'))), array('config.update', array('version', '3.1.0-dev')), ); } public function move_customise_modules() { // Move language management to new location in the Customise tab // First get language module id $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_basename = 'acp_language'"; $result = $this->db->sql_query($sql); $language_module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); // Next get language management module id of the one just created $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " WHERE module_langname = 'ACP_LANGUAGE'"; $result = $this->db->sql_query($sql); $language_management_module_id = $this->db->sql_fetchfield('module_id'); $this->db->sql_freeresult($result); if (!class_exists('acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); } // acp_modules calls adm_back_link, which is undefined at this point if (!function_exists('adm_back_link')) { include($this->phpbb_root_path . 'includes/functions_acp.' . $this->php_ext); } $module_manager = new \acp_modules(); $module_manager->module_class = 'acp'; $module_manager->move_module($language_module_id, $language_management_module_id); } public function update_ucp_pm_basename() { $sql = 'SELECT module_id, module_basename FROM ' . MODULES_TABLE . " WHERE module_basename <> 'ucp_pm' AND module_langname='UCP_PM'"; $result = $this->db->sql_query_limit($sql, 1); if ($row = $this->db->sql_fetchrow($result)) { // This update is still not applied. Applying it $sql = 'UPDATE ' . MODULES_TABLE . " SET module_basename = 'ucp_pm' WHERE module_id = " . (int) $row['module_id']; $this->sql_query($sql); } $this->db->sql_freeresult($result); } public function update_ucp_profile_auth() { // Update the auth setting for the module $sql = 'UPDATE ' . MODULES_TABLE . " SET module_auth = 'acl_u_chgprofileinfo' WHERE module_class = 'ucp' AND module_basename = 'ucp_profile' AND module_mode = 'profile_info'"; $this->sql_query($sql); } public function rename_styles_module() { // Rename styles module to Customise $sql = 'UPDATE ' . MODULES_TABLE . " SET module_langname = 'ACP_CAT_CUSTOMISE' WHERE module_langname = 'ACP_CAT_STYLES'"; $this->sql_query($sql); } public function rename_module_basenames() { // rename all module basenames to full classname $sql = 'SELECT module_id, module_basename, module_class FROM ' . MODULES_TABLE; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $module_id = (int) $row['module_id']; unset($row['module_id']); if (!empty($row['module_basename']) && !empty($row['module_class'])) { // all the class names start with class name or with phpbb_ for auto loading if (strpos($row['module_basename'], $row['module_class'] . '_') !== 0 && strpos($row['module_basename'], 'phpbb_') !== 0) { $row['module_basename'] = $row['module_class'] . '_' . $row['module_basename']; $sql_update = $this->db->sql_build_array('UPDATE', $row); $sql = 'UPDATE ' . MODULES_TABLE . ' SET ' . $sql_update . ' WHERE module_id = ' . $module_id; $this->sql_query($sql); } } } $this->db->sql_freeresult($result); } public function add_group_teampage() { $sql = 'UPDATE ' . GROUPS_TABLE . ' SET group_teampage = 1 WHERE group_type = ' . GROUP_SPECIAL . " AND group_name = 'ADMINISTRATORS'"; $this->sql_query($sql); $sql = 'UPDATE ' . GROUPS_TABLE . ' SET group_teampage = 2 WHERE group_type = ' . GROUP_SPECIAL . " AND group_name = 'GLOBAL_MODERATORS'"; $this->sql_query($sql); } public function update_group_legend() { $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . ' WHERE group_legend = 1 ORDER BY group_name ASC'; $result = $this->db->sql_query($sql); $next_legend = 1; while ($row = $this->db->sql_fetchrow($result)) { $sql = 'UPDATE ' . GROUPS_TABLE . ' SET group_legend = ' . $next_legend . ' WHERE group_id = ' . (int) $row['group_id']; $this->sql_query($sql); $next_legend++; } $this->db->sql_freeresult($result); } public function localise_global_announcements() { // Localise Global Announcements $sql = 'SELECT topic_id, topic_approved, (topic_replies + 1) AS topic_posts, topic_last_post_id, topic_last_post_subject, topic_last_post_time, topic_last_poster_id, topic_last_poster_name, topic_last_poster_colour FROM ' . TOPICS_TABLE . ' WHERE forum_id = 0 AND topic_type = ' . POST_GLOBAL; $result = $this->db->sql_query($sql); $global_announcements = $update_lastpost_data = array(); $update_lastpost_data['forum_last_post_time'] = 0; $update_forum_data = array( 'forum_posts' => 0, 'forum_topics' => 0, 'forum_topics_real' => 0, ); while ($row = $this->db->sql_fetchrow($result)) { $global_announcements[] = (int) $row['topic_id']; $update_forum_data['forum_posts'] += (int) $row['topic_posts']; $update_forum_data['forum_topics_real']++; if ($row['topic_approved']) { $update_forum_data['forum_topics']++; } if ($update_lastpost_data['forum_last_post_time'] < $row['topic_last_post_time']) { $update_lastpost_data = array( 'forum_last_post_id' => (int) $row['topic_last_post_id'], 'forum_last_post_subject' => $row['topic_last_post_subject'], 'forum_last_post_time' => (int) $row['topic_last_post_time'], 'forum_last_poster_id' => (int) $row['topic_last_poster_id'], 'forum_last_poster_name' => $row['topic_last_poster_name'], 'forum_last_poster_colour' => $row['topic_last_poster_colour'], ); } } $this->db->sql_freeresult($result); if (!empty($global_announcements)) { // Update the post/topic-count for the forum and the last-post if needed $sql = 'SELECT forum_id FROM ' . FORUMS_TABLE . ' WHERE forum_type = ' . FORUM_POST; $result = $this->db->sql_query_limit($sql, 1); $ga_forum_id = $this->db->sql_fetchfield('forum_id'); $this->db->sql_freeresult($result); $sql = 'SELECT forum_last_post_time FROM ' . FORUMS_TABLE . ' WHERE forum_id = ' . $ga_forum_id; $result = $this->db->sql_query($sql); $lastpost = (int) $this->db->sql_fetchfield('forum_last_post_time'); $this->db->sql_freeresult($result); $sql_update = 'forum_posts = forum_posts + ' . $update_forum_data['forum_posts'] . ', '; $sql_update .= 'forum_topics_real = forum_topics_real + ' . $update_forum_data['forum_topics_real'] . ', '; $sql_update .= 'forum_topics = forum_topics + ' . $update_forum_data['forum_topics']; if ($lastpost < $update_lastpost_data['forum_last_post_time']) { $sql_update .= ', ' . $this->db->sql_build_array('UPDATE', $update_lastpost_data); } $sql = 'UPDATE ' . FORUMS_TABLE . ' SET ' . $sql_update . ' WHERE forum_id = ' . $ga_forum_id; $this->sql_query($sql); // Update some forum_ids $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); foreach ($table_ary as $table) { $sql = "UPDATE $table SET forum_id = $ga_forum_id WHERE " . $this->db->sql_in_set('topic_id', $global_announcements); $this->sql_query($sql); } unset($table_ary); } } } migration/data/v310/profilefield_yahoo_cleanup.php000077700000001756151514672100016244 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_yahoo_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_yim'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_yahoo', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_yim', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_yim' => array('VCHAR_UNI', ''), ), ), ); } } migration/data/v310/profilefield_twitter.php000077700000003102151514672100015103 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_twitter extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), ); } protected $profilefield_name = 'phpbb_twitter'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_twitter', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_twitter', 'field_length' => '20', 'field_minlen' => '1', 'field_maxlen' => '15', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[\w_]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VIEW_TWITTER_PROFILE', 'field_contact_url' => 'http://twitter.com/%s', ); } migration/data/v310/rename_too_long_indexes.php000077700000001477151514672100015560 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rename_too_long_indexes extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_0'); } public function update_schema() { return array( 'drop_keys' => array( $this->table_prefix . 'search_wordmatch' => array( 'unq_mtch', ), ), 'add_unique_index' => array( $this->table_prefix . 'search_wordmatch' => array( 'un_mtch' => array('word_id', 'post_id', 'title_match'), ), ), ); } } migration/data/v310/reported_posts_display.php000077700000002330151514672100015460 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class reported_posts_display extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'reports', 'reported_post_enable_bbcode'); } static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'reports' => array( 'reported_post_enable_bbcode' => array('BOOL', 1), 'reported_post_enable_smilies' => array('BOOL', 1), 'reported_post_enable_magic_url' => array('BOOL', 1), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'reports' => array( 'reported_post_enable_bbcode', 'reported_post_enable_smilies', 'reported_post_enable_magic_url', ), ), ); } } migration/data/v310/passwords.php000077700000002067151514672100012713 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class passwords extends \phpbb\db\migration\migration { static public function depends_on() { return array('\phpbb\db\migration\data\v30x\release_3_0_11'); } public function update_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_password' => array('VCHAR:255', ''), ), $this->table_prefix . 'forums' => array( 'forum_password' => array('VCHAR:255', ''), ), ), ); } public function revert_schema() { return array( 'change_columns' => array( $this->table_prefix . 'users' => array( 'user_password' => array('VCHAR:40', ''), ), $this->table_prefix . 'forums' => array( 'forum_password' => array('VCHAR:40', ''), ), ), ); } } migration/data/v310/profilefield_on_memberlist.php000077700000002032151514672100016241 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_on_memberlist extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->db_tools->sql_column_exists($this->table_prefix . 'profile_fields', 'field_show_on_ml'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_cleanup', ); } public function update_schema() { return array( 'add_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_on_ml' => array('BOOL', 0), ), ), ); } public function revert_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'profile_fields' => array( 'field_show_on_ml', ), ), ); } } migration/data/v310/profilefield_interests.php000077700000002476151514672100015436 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_interests extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_types', '\phpbb\db\migration\data\v310\profilefield_show_novalue', ); } protected $profilefield_name = 'phpbb_interests'; protected $profilefield_database_type = array('MTEXT', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_interests', 'field_type' => 'profilefields.type.text', 'field_ident' => 'phpbb_interests', 'field_length' => '3|30', 'field_minlen' => '2', 'field_maxlen' => '500', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 0, 'field_show_on_vt' => 0, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, ); protected $user_column_name = 'user_interests'; } migration/data/v310/plupload.php000077700000001426151514672100012504 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class plupload extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['plupload_last_gc']) && isset($this->config['plupload_salt']); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\dev'); } public function update_data() { return array( array('config.add', array('plupload_last_gc', 0)), array('config.add', array('plupload_salt', unique_id())), ); } } migration/data/v310/profilefield_aol.php000077700000002536151514672100014166 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_aol extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_yahoo_cleanup', ); } protected $profilefield_name = 'phpbb_aol'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_aol', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_aol', 'field_length' => '40', 'field_minlen' => '5', 'field_maxlen' => '255', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '.*', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_on_ml' => 0, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => '', 'field_contact_url' => '', ); protected $user_column_name = 'user_aim'; } migration/data/v310/rc2.php000077700000001121151514672100011342 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc1', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC2')), ); } } migration/data/v310/allow_cdn.php000077700000001414151514672100012623 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class allow_cdn extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['allow_cdn']); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\jquery_update', ); } public function update_data() { return array( array('config.add', array('allow_cdn', (int) $this->config['load_jquery_cdn'])), array('config.remove', array('load_jquery_cdn')), ); } } migration/data/v310/profilefield_change_load_settings.php000077700000001472151514672100017555 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_change_load_settings extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_aol_cleanup', ); } public function update_data() { return array( array('config.update', array('load_cpf_memberlist', '1')), array('config.update', array('load_cpf_pm', '1')), array('config.update', array('load_cpf_viewprofile', '1')), array('config.update', array('load_cpf_viewtopic', '1')), ); } } migration/data/v310/beta1.php000077700000001665151514672100011665 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class beta1 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\alpha3', '\phpbb\db\migration\data\v310\passwords_p2', '\phpbb\db\migration\data\v310\postgres_fulltext_drop', '\phpbb\db\migration\data\v310\profilefield_change_load_settings', '\phpbb\db\migration\data\v310\profilefield_location', '\phpbb\db\migration\data\v310\soft_delete_mod_convert2', '\phpbb\db\migration\data\v310\ucp_popuppm_module', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-b1')), ); } } migration/data/v310/rc5.php000077700000001326151514672100011354 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class rc5 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\rc4', '\phpbb\db\migration\data\v310\profilefield_field_validation_length', '\phpbb\db\migration\data\v310\remove_acp_styles_cache', ); } public function update_data() { return array( array('config.update', array('version', '3.1.0-RC5')), ); } } migration/data/v310/profilefield_icq_cleanup.php000077700000001751151514672100015674 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_icq_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_icq'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_icq', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_icq', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_icq' => array('VCHAR:20', ''), ), ), ); } } migration/data/v310/auth_provider_oauth2.php000077700000001664151514672100015025 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class auth_provider_oauth2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\auth_provider_oauth', ); } public function update_data() { return array( array('custom', array( array($this, 'update_auth_link_module_auth'), )), ); } public function update_auth_link_module_auth() { $sql = 'UPDATE ' . MODULES_TABLE . " SET module_auth = 'authmethod_oauth' WHERE module_class = 'ucp' AND module_basename = 'ucp_auth_link' AND module_mode = 'auth_link' AND module_auth = ''"; $this->db->sql_query($sql); } } migration/data/v310/mod_rewrite.php000077700000001131151514672100013175 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class mod_rewrite extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_data() { return array( array('config.add', array('enable_mod_rewrite', '0')), ); } } migration/data/v310/profilefield_youtube.php000077700000003124151514672100015101 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_youtube extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), ); } protected $profilefield_name = 'phpbb_youtube'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_youtube', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_youtube', 'field_length' => '20', 'field_minlen' => '3', 'field_maxlen' => '60', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[a-zA-Z][\w\.,\-_]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VIEW_YOUTUBE_CHANNEL', 'field_contact_url' => 'http://youtube.com/user/%s', ); } migration/data/v310/profilefield_location_cleanup.php000077700000001773151514672100016734 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_location_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_from'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_location', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_from', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_from' => array('VCHAR_UNI:100', ''), ), ), ); } } migration/data/v310/profilefield_skype.php000077700000003101151514672100014533 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_skype extends \phpbb\db\migration\profilefield_base_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_contact_field', '\phpbb\db\migration\data\v310\profilefield_show_novalue', '\phpbb\db\migration\data\v310\profilefield_types', ); } public function update_data() { return array( array('custom', array(array($this, 'create_custom_field'))), ); } protected $profilefield_name = 'phpbb_skype'; protected $profilefield_database_type = array('VCHAR', ''); protected $profilefield_data = array( 'field_name' => 'phpbb_skype', 'field_type' => 'profilefields.type.string', 'field_ident' => 'phpbb_skype', 'field_length' => '20', 'field_minlen' => '6', 'field_maxlen' => '32', 'field_novalue' => '', 'field_default_value' => '', 'field_validation' => '[a-zA-Z][\w\.,\-_]+', 'field_required' => 0, 'field_show_novalue' => 0, 'field_show_on_reg' => 0, 'field_show_on_pm' => 1, 'field_show_on_vt' => 1, 'field_show_profile' => 1, 'field_hide' => 0, 'field_no_view' => 0, 'field_active' => 1, 'field_is_contact' => 1, 'field_contact_desc' => 'VIEW_SKYPE_PROFILE', 'field_contact_url' => 'skype:%s?userinfo', ); } migration/data/v310/boardindex.php000077700000001117151514672100013000 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class boardindex extends \phpbb\db\migration\migration { public function effectively_installed() { return isset($this->config['board_index_text']); } public function update_data() { return array( array('config.add', array('board_index_text', '')), ); } } migration/data/v310/jquery_update.php000077700000001461151514672100013544 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class jquery_update extends \phpbb\db\migration\migration { public function effectively_installed() { return $this->config['load_jquery_url'] !== '//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js'; } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\dev', ); } public function update_data() { return array( array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js')), ); } } migration/data/v310/soft_delete_mod_convert.php000077700000005331151514672100015557 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; use phpbb\db\migration\container_aware_migration; /** * Migration to convert the Soft Delete MOD for 3.0 * * https://www.phpbb.com/customise/db/mod/soft_delete/ */ class soft_delete_mod_convert extends container_aware_migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\alpha3', ); } public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_deleted'); } public function update_data() { return array( array('permission.remove', array('m_harddelete', true)), array('permission.remove', array('m_harddelete', false)), array('custom', array(array($this, 'convert_posts'))), array('custom', array(array($this, 'convert_topics'))), ); } public function convert_posts($start) { $content_visibility = $this->get_content_visibility(); $limit = 250; $i = 0; $sql = 'SELECT p.*, t.topic_first_post_id, t.topic_last_post_id FROM ' . $this->table_prefix . 'posts p, ' . $this->table_prefix . 'topics t WHERE p.post_deleted > 0 AND t.topic_id = p.topic_id'; $result = $this->db->sql_query_limit($sql, $limit, $start); while ($row = $this->db->sql_fetchrow($result)) { $content_visibility->set_post_visibility( ITEM_DELETED, $row['post_id'], $row['topic_id'], $row['forum_id'], $row['post_deleted'], $row['post_deleted_time'], '', ($row['post_id'] == $row['topic_first_post_id']) ? true : false, ($row['post_id'] == $row['topic_last_post_id']) ? true : false ); $i++; } $this->db->sql_freeresult($result); if ($i == $limit) { return $start + $i; } } public function convert_topics($start) { $content_visibility = $this->get_content_visibility(); $limit = 100; $i = 0; $sql = 'SELECT * FROM ' . $this->table_prefix . 'topics WHERE topic_deleted > 0'; $result = $this->db->sql_query_limit($sql, $limit, $start); while ($row = $this->db->sql_fetchrow($result)) { $content_visibility->set_topic_visibility( ITEM_DELETED, $row['topic_id'], $row['forum_id'], $row['topic_deleted'], $row['topic_deleted_time'], '' ); $i++; } $this->db->sql_freeresult($result); if ($i == $limit) { return $start + $i; } } /** * @return \phpbb\content_visibility */ protected function get_content_visibility() { return $this->container->get('content.visibility'); } } migration/data/v310/style_update_p2.php000077700000010571151514672100013770 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class style_update_p2 extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_table_exists($this->table_prefix . 'styles_imageset'); } static public function depends_on() { return array('\phpbb\db\migration\data\v310\style_update_p1'); } public function update_schema() { return array( 'drop_keys' => array( $this->table_prefix . 'styles' => array( 'imageset_id', 'template_id', 'theme_id', ), ), 'drop_columns' => array( $this->table_prefix . 'styles' => array( 'imageset_id', 'template_id', 'theme_id', ), ), 'drop_tables' => array( $this->table_prefix . 'styles_imageset', $this->table_prefix . 'styles_imageset_data', $this->table_prefix . 'styles_template', $this->table_prefix . 'styles_template_data', $this->table_prefix . 'styles_theme', ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'styles' => array( 'imageset_id' => array('UINT', 0), 'template_id' => array('UINT', 0), 'theme_id' => array('UINT', 0), ), ), 'add_index' => array( $this->table_prefix . 'styles' => array( 'imageset_id' => array('imageset_id'), 'template_id' => array('template_id'), 'theme_id' => array('theme_id'), ), ), 'add_tables' => array( $this->table_prefix . 'styles_imageset' => array( 'COLUMNS' => array( 'imageset_id' => array('UINT', null, 'auto_increment'), 'imageset_name' => array('VCHAR_UNI:255', ''), 'imageset_copyright' => array('VCHAR_UNI', ''), 'imageset_path' => array('VCHAR:100', ''), ), 'PRIMARY_KEY' => 'imageset_id', 'KEYS' => array( 'imgset_nm' => array('UNIQUE', 'imageset_name'), ), ), $this->table_prefix . 'styles_imageset_data' => array( 'COLUMNS' => array( 'image_id' => array('UINT', null, 'auto_increment'), 'image_name' => array('VCHAR:200', ''), 'image_filename' => array('VCHAR:200', ''), 'image_lang' => array('VCHAR:30', ''), 'image_height' => array('USINT', 0), 'image_width' => array('USINT', 0), 'imageset_id' => array('UINT', 0), ), 'PRIMARY_KEY' => 'image_id', 'KEYS' => array( 'i_d' => array('INDEX', 'imageset_id'), ), ), $this->table_prefix . 'styles_template' => array( 'COLUMNS' => array( 'template_id' => array('UINT', null, 'auto_increment'), 'template_name' => array('VCHAR_UNI:255', ''), 'template_copyright' => array('VCHAR_UNI', ''), 'template_path' => array('VCHAR:100', ''), 'bbcode_bitfield' => array('VCHAR:255', 'kNg='), 'template_storedb' => array('BOOL', 0), 'template_inherits_id' => array('UINT:4', 0), 'template_inherit_path' => array('VCHAR', ''), ), 'PRIMARY_KEY' => 'template_id', 'KEYS' => array( 'tmplte_nm' => array('UNIQUE', 'template_name'), ), ), $this->table_prefix . 'styles_template_data' => array( 'COLUMNS' => array( 'template_id' => array('UINT', 0), 'template_filename' => array('VCHAR:100', ''), 'template_included' => array('TEXT', ''), 'template_mtime' => array('TIMESTAMP', 0), 'template_data' => array('MTEXT_UNI', ''), ), 'KEYS' => array( 'tid' => array('INDEX', 'template_id'), 'tfn' => array('INDEX', 'template_filename'), ), ), $this->table_prefix . 'styles_theme' => array( 'COLUMNS' => array( 'theme_id' => array('UINT', null, 'auto_increment'), 'theme_name' => array('VCHAR_UNI:255', ''), 'theme_copyright' => array('VCHAR_UNI', ''), 'theme_path' => array('VCHAR:100', ''), 'theme_storedb' => array('BOOL', 0), 'theme_mtime' => array('TIMESTAMP', 0), 'theme_data' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'theme_id', 'KEYS' => array( 'theme_name' => array('UNIQUE', 'theme_name'), ), ), ), ); } } migration/data/v310/profilefield_wlm_cleanup.php000077700000001755151514672100015723 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; class profilefield_wlm_cleanup extends \phpbb\db\migration\migration { public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'users', 'user_msnm'); } static public function depends_on() { return array( '\phpbb\db\migration\data\v310\profilefield_wlm', ); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'users' => array( 'user_msnm', ), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'users' => array( 'user_msnm' => array('VCHAR_UNI', ''), ), ), ); } } migration/data/v310/soft_delete_mod_convert2.php000077700000003403151514672100015637 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration\data\v310; /** * Migration to convert the Soft Delete MOD for 3.0 * * https://www.phpbb.com/customise/db/mod/soft_delete/ */ class soft_delete_mod_convert2 extends \phpbb\db\migration\migration { static public function depends_on() { return array( '\phpbb\db\migration\data\v310\soft_delete_mod_convert', ); } public function effectively_installed() { return !$this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_deleted'); } public function update_schema() { return array( 'drop_columns' => array( $this->table_prefix . 'forums' => array('forum_deleted_topic_count', 'forum_deleted_reply_count'), $this->table_prefix . 'posts' => array('post_deleted', 'post_deleted_time'), $this->table_prefix . 'topics' => array('topic_deleted', 'topic_deleted_time', 'topic_deleted_reply_count'), ), ); } public function revert_schema() { return array( 'add_columns' => array( $this->table_prefix . 'forums' => array( 'forum_deleted_topic_count' => array('UINT', 0), 'forum_deleted_reply_count' => array('UINT', 0), ), $this->table_prefix . 'posts' => array( 'post_deleted' => array('UINT', 0), 'post_deleted_time' => array('TIMESTAMP', 0), ), $this->table_prefix . 'topics' => array( 'topic_deleted' => array('UINT', 0), 'topic_deleted_time' => array('TIMESTAMP', 0), 'topic_deleted_reply_count' => array('UINT', 0), ), ), ); } } migration/migration.php000077700000010603151514672100011250 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db\migration; /** * Abstract base class for database migrations * * Each migration consists of a set of schema and data changes to be implemented * in a subclass. This class provides various utility methods to simplify editing * a phpBB. */ abstract class migration { /** @var \phpbb\config\config */ protected $config; /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var \phpbb\db\tools */ protected $db_tools; /** @var string */ protected $table_prefix; /** @var string */ protected $phpbb_root_path; /** @var string */ protected $php_ext; /** @var array Errors, if any occurred */ protected $errors; /** @var array List of queries executed through $this->sql_query() */ protected $queries = array(); /** * Constructor * * @param \phpbb\config\config $config * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\db\tools $db_tools * @param string $phpbb_root_path * @param string $php_ext * @param string $table_prefix */ public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix) { $this->config = $config; $this->db = $db; $this->db_tools = $db_tools; $this->table_prefix = $table_prefix; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->errors = array(); } /** * Defines other migrations to be applied first * * @return array An array of migration class names */ static public function depends_on() { return array(); } /** * Allows you to check if the migration is effectively installed (entirely optional) * * This is checked when a migration is installed. If true is returned, the migration will be set as * installed without performing the database changes. * This function is intended to help moving to migrations from a previous database updater, where some * migrations may have been installed already even though they are not yet listed in the migrations table. * * @return bool True if this migration is installed, False if this migration is not installed (checked on install) */ public function effectively_installed() { return false; } /** * Updates the database schema by providing a set of change instructions * * @return array Array of schema changes (compatible with db_tools->perform_schema_changes()) */ public function update_schema() { return array(); } /** * Reverts the database schema by providing a set of change instructions * * @return array Array of schema changes (compatible with db_tools->perform_schema_changes()) */ public function revert_schema() { return array(); } /** * Updates data by returning a list of instructions to be executed * * @return array Array of data update instructions */ public function update_data() { return array(); } /** * Reverts data by returning a list of instructions to be executed * * @return array Array of data instructions that will be performed on revert * NOTE: calls to tools (such as config.add) are automatically reverted when * possible, so you should not attempt to revert those, this is mostly for * otherwise unrevertable calls (custom functions for example) */ public function revert_data() { return array(); } /** * Wrapper for running queries to generate user feedback on updates * * @param string $sql SQL query to run on the database * @return mixed Query result from db->sql_query() */ protected function sql_query($sql) { $this->queries[] = $sql; $this->db->sql_return_on_error(true); if ($sql === 'begin') { $result = $this->db->sql_transaction('begin'); } else if ($sql === 'commit') { $result = $this->db->sql_transaction('commit'); } else { $result = $this->db->sql_query($sql); if ($this->db->get_sql_error_triggered()) { $this->errors[] = array( 'sql' => $this->db->get_sql_error_sql(), 'code' => $this->db->get_sql_error_returned(), ); } } $this->db->sql_return_on_error(false); return $result; } /** * Get the list of queries run * * @return array */ public function get_queries() { return $this->queries; } } html_migrator_output_handler.php000077700000001554151514672100013260 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; use phpbb\user; class html_migrator_output_handler implements migrator_output_handler_interface { /** * User object. * * @var user */ private $user; /** * Constructor * * @param user $user User object */ public function __construct(user $user) { $this->user = $user; } /** * {@inheritdoc} */ public function write($message, $verbosity) { if ($verbosity <= migrator_output_handler_interface::VERBOSITY_VERBOSE) { $final_message = call_user_func_array(array($this->user, 'lang'), $message); echo $final_message . "<br />\n"; } } } sql_insert_buffer.php000077700000007030151514672100011002 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; /** * Collects rows for insert into a database until the buffer size is reached. * Then flushes the buffer to the database and starts over again. * * Benefits over collecting a (possibly huge) insert array and then using * $db->sql_multi_insert() include: * * - Going over max packet size of the database connection is usually prevented * because the data is submitted in batches. * * - Reaching database connection timeout is usually prevented because * submission of batches talks to the database every now and then. * * - Usage of less PHP memory because data no longer needed is discarded on * buffer flush. * * Attention: * Please note that users of this class have to call flush() to flush the * remaining rows to the database after their batch insert operation is * finished. * * Usage: * <code> * $buffer = new \phpbb\db\sql_insert_buffer($db, 'test_table', 1234); * * while (do_stuff()) * { * $buffer->insert(array( * 'column1' => 'value1', * 'column2' => 'value2', * )); * } * * $buffer->flush(); * </code> */ class sql_insert_buffer { /** @var \phpbb\db\driver\driver_interface */ protected $db; /** @var string */ protected $table_name; /** @var int */ protected $max_buffered_rows; /** @var array */ protected $buffer = array(); /** * @param \phpbb\db\driver\driver_interface $db * @param string $table_name * @param int $max_buffered_rows */ public function __construct(\phpbb\db\driver\driver_interface $db, $table_name, $max_buffered_rows = 500) { $this->db = $db; $this->table_name = $table_name; $this->max_buffered_rows = $max_buffered_rows; } /** * Inserts a single row into the buffer if multi insert is supported by the * database (otherwise an insert query is sent immediately). Then flushes * the buffer if the number of rows in the buffer is now greater than or * equal to $max_buffered_rows. * * @param array $row * * @return bool True when some data was flushed to the database. * False otherwise. */ public function insert(array $row) { $this->buffer[] = $row; // Flush buffer if it is full or when DB does not support multi inserts. // In the later case, the buffer will always only contain one row. if (!$this->db->get_multi_insert() || sizeof($this->buffer) >= $this->max_buffered_rows) { return $this->flush(); } return false; } /** * Inserts a row set, i.e. an array of rows, by calling insert(). * * Please note that it is in most cases better to use insert() instead of * first building a huge rowset. Or at least sizeof($rows) should be kept * small. * * @param array $rows * * @return bool True when some data was flushed to the database. * False otherwise. */ public function insert_all(array $rows) { // Using bitwise |= because PHP does not have logical ||= $result = 0; foreach ($rows as $row) { $result |= (int) $this->insert($row); } return (bool) $result; } /** * Flushes the buffer content to the DB and clears the buffer. * * @return bool True when some data was flushed to the database. * False otherwise. */ public function flush() { if (!empty($this->buffer)) { $this->db->sql_multi_insert($this->table_name, $this->buffer); $this->buffer = array(); return true; } return false; } } tools.php000077700000230664151514672100006441 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; /** * Database Tools for handling cross-db actions such as altering columns, etc. * Currently not supported is returning SQL for creating tables. */ class tools { /** * Current sql layer */ var $sql_layer = ''; /** * @var object DB object */ var $db = null; /** * The Column types for every database we support * @var array */ var $dbms_type_map = array(); /** * Is the used MS SQL Server a SQL Server 2000? * @var bool */ protected $is_sql_server_2000; /** * Get the column types for every database we support * * @return array */ public static function get_dbms_type_map() { return array( 'mysql_41' => array( 'INT:' => 'int(%d)', 'BINT' => 'bigint(20)', 'UINT' => 'mediumint(8) UNSIGNED', 'UINT:' => 'int(%d) UNSIGNED', 'TINT:' => 'tinyint(%d)', 'USINT' => 'smallint(4) UNSIGNED', 'BOOL' => 'tinyint(1) UNSIGNED', 'VCHAR' => 'varchar(255)', 'VCHAR:' => 'varchar(%d)', 'CHAR:' => 'char(%d)', 'XSTEXT' => 'text', 'XSTEXT_UNI'=> 'varchar(100)', 'STEXT' => 'text', 'STEXT_UNI' => 'varchar(255)', 'TEXT' => 'text', 'TEXT_UNI' => 'text', 'MTEXT' => 'mediumtext', 'MTEXT_UNI' => 'mediumtext', 'TIMESTAMP' => 'int(11) UNSIGNED', 'DECIMAL' => 'decimal(5,2)', 'DECIMAL:' => 'decimal(%d,2)', 'PDECIMAL' => 'decimal(6,3)', 'PDECIMAL:' => 'decimal(%d,3)', 'VCHAR_UNI' => 'varchar(255)', 'VCHAR_UNI:'=> 'varchar(%d)', 'VCHAR_CI' => 'varchar(255)', 'VARBINARY' => 'varbinary(255)', ), 'mysql_40' => array( 'INT:' => 'int(%d)', 'BINT' => 'bigint(20)', 'UINT' => 'mediumint(8) UNSIGNED', 'UINT:' => 'int(%d) UNSIGNED', 'TINT:' => 'tinyint(%d)', 'USINT' => 'smallint(4) UNSIGNED', 'BOOL' => 'tinyint(1) UNSIGNED', 'VCHAR' => 'varbinary(255)', 'VCHAR:' => 'varbinary(%d)', 'CHAR:' => 'binary(%d)', 'XSTEXT' => 'blob', 'XSTEXT_UNI'=> 'blob', 'STEXT' => 'blob', 'STEXT_UNI' => 'blob', 'TEXT' => 'blob', 'TEXT_UNI' => 'blob', 'MTEXT' => 'mediumblob', 'MTEXT_UNI' => 'mediumblob', 'TIMESTAMP' => 'int(11) UNSIGNED', 'DECIMAL' => 'decimal(5,2)', 'DECIMAL:' => 'decimal(%d,2)', 'PDECIMAL' => 'decimal(6,3)', 'PDECIMAL:' => 'decimal(%d,3)', 'VCHAR_UNI' => 'blob', 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')), 'VCHAR_CI' => 'blob', 'VARBINARY' => 'varbinary(255)', ), 'mssql' => array( 'INT:' => '[int]', 'BINT' => '[float]', 'UINT' => '[int]', 'UINT:' => '[int]', 'TINT:' => '[int]', 'USINT' => '[int]', 'BOOL' => '[int]', 'VCHAR' => '[varchar] (255)', 'VCHAR:' => '[varchar] (%d)', 'CHAR:' => '[char] (%d)', 'XSTEXT' => '[varchar] (1000)', 'STEXT' => '[varchar] (3000)', 'TEXT' => '[varchar] (8000)', 'MTEXT' => '[text]', 'XSTEXT_UNI'=> '[varchar] (100)', 'STEXT_UNI' => '[varchar] (255)', 'TEXT_UNI' => '[varchar] (4000)', 'MTEXT_UNI' => '[text]', 'TIMESTAMP' => '[int]', 'DECIMAL' => '[float]', 'DECIMAL:' => '[float]', 'PDECIMAL' => '[float]', 'PDECIMAL:' => '[float]', 'VCHAR_UNI' => '[varchar] (255)', 'VCHAR_UNI:'=> '[varchar] (%d)', 'VCHAR_CI' => '[varchar] (255)', 'VARBINARY' => '[varchar] (255)', ), 'mssqlnative' => array( 'INT:' => '[int]', 'BINT' => '[float]', 'UINT' => '[int]', 'UINT:' => '[int]', 'TINT:' => '[int]', 'USINT' => '[int]', 'BOOL' => '[int]', 'VCHAR' => '[varchar] (255)', 'VCHAR:' => '[varchar] (%d)', 'CHAR:' => '[char] (%d)', 'XSTEXT' => '[varchar] (1000)', 'STEXT' => '[varchar] (3000)', 'TEXT' => '[varchar] (8000)', 'MTEXT' => '[text]', 'XSTEXT_UNI'=> '[varchar] (100)', 'STEXT_UNI' => '[varchar] (255)', 'TEXT_UNI' => '[varchar] (4000)', 'MTEXT_UNI' => '[text]', 'TIMESTAMP' => '[int]', 'DECIMAL' => '[float]', 'DECIMAL:' => '[float]', 'PDECIMAL' => '[float]', 'PDECIMAL:' => '[float]', 'VCHAR_UNI' => '[varchar] (255)', 'VCHAR_UNI:'=> '[varchar] (%d)', 'VCHAR_CI' => '[varchar] (255)', 'VARBINARY' => '[varchar] (255)', ), 'oracle' => array( 'INT:' => 'number(%d)', 'BINT' => 'number(20)', 'UINT' => 'number(8)', 'UINT:' => 'number(%d)', 'TINT:' => 'number(%d)', 'USINT' => 'number(4)', 'BOOL' => 'number(1)', 'VCHAR' => 'varchar2(255)', 'VCHAR:' => 'varchar2(%d)', 'CHAR:' => 'char(%d)', 'XSTEXT' => 'varchar2(1000)', 'STEXT' => 'varchar2(3000)', 'TEXT' => 'clob', 'MTEXT' => 'clob', 'XSTEXT_UNI'=> 'varchar2(300)', 'STEXT_UNI' => 'varchar2(765)', 'TEXT_UNI' => 'clob', 'MTEXT_UNI' => 'clob', 'TIMESTAMP' => 'number(11)', 'DECIMAL' => 'number(5, 2)', 'DECIMAL:' => 'number(%d, 2)', 'PDECIMAL' => 'number(6, 3)', 'PDECIMAL:' => 'number(%d, 3)', 'VCHAR_UNI' => 'varchar2(765)', 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')), 'VCHAR_CI' => 'varchar2(255)', 'VARBINARY' => 'raw(255)', ), 'sqlite' => array( 'INT:' => 'int(%d)', 'BINT' => 'bigint(20)', 'UINT' => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED', 'UINT:' => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED', 'TINT:' => 'tinyint(%d)', 'USINT' => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED', 'BOOL' => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED', 'VCHAR' => 'varchar(255)', 'VCHAR:' => 'varchar(%d)', 'CHAR:' => 'char(%d)', 'XSTEXT' => 'text(65535)', 'STEXT' => 'text(65535)', 'TEXT' => 'text(65535)', 'MTEXT' => 'mediumtext(16777215)', 'XSTEXT_UNI'=> 'text(65535)', 'STEXT_UNI' => 'text(65535)', 'TEXT_UNI' => 'text(65535)', 'MTEXT_UNI' => 'mediumtext(16777215)', 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED', 'DECIMAL' => 'decimal(5,2)', 'DECIMAL:' => 'decimal(%d,2)', 'PDECIMAL' => 'decimal(6,3)', 'PDECIMAL:' => 'decimal(%d,3)', 'VCHAR_UNI' => 'varchar(255)', 'VCHAR_UNI:'=> 'varchar(%d)', 'VCHAR_CI' => 'varchar(255)', 'VARBINARY' => 'blob', ), 'sqlite3' => array( 'INT:' => 'INT(%d)', 'BINT' => 'BIGINT(20)', 'UINT' => 'INTEGER UNSIGNED', 'UINT:' => 'INTEGER UNSIGNED', 'TINT:' => 'TINYINT(%d)', 'USINT' => 'INTEGER UNSIGNED', 'BOOL' => 'INTEGER UNSIGNED', 'VCHAR' => 'VARCHAR(255)', 'VCHAR:' => 'VARCHAR(%d)', 'CHAR:' => 'CHAR(%d)', 'XSTEXT' => 'TEXT(65535)', 'STEXT' => 'TEXT(65535)', 'TEXT' => 'TEXT(65535)', 'MTEXT' => 'MEDIUMTEXT(16777215)', 'XSTEXT_UNI'=> 'TEXT(65535)', 'STEXT_UNI' => 'TEXT(65535)', 'TEXT_UNI' => 'TEXT(65535)', 'MTEXT_UNI' => 'MEDIUMTEXT(16777215)', 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED', 'DECIMAL' => 'DECIMAL(5,2)', 'DECIMAL:' => 'DECIMAL(%d,2)', 'PDECIMAL' => 'DECIMAL(6,3)', 'PDECIMAL:' => 'DECIMAL(%d,3)', 'VCHAR_UNI' => 'VARCHAR(255)', 'VCHAR_UNI:'=> 'VARCHAR(%d)', 'VCHAR_CI' => 'VARCHAR(255)', 'VARBINARY' => 'BLOB', ), 'postgres' => array( 'INT:' => 'INT4', 'BINT' => 'INT8', 'UINT' => 'INT4', // unsigned 'UINT:' => 'INT4', // unsigned 'USINT' => 'INT2', // unsigned 'BOOL' => 'INT2', // unsigned 'TINT:' => 'INT2', 'VCHAR' => 'varchar(255)', 'VCHAR:' => 'varchar(%d)', 'CHAR:' => 'char(%d)', 'XSTEXT' => 'varchar(1000)', 'STEXT' => 'varchar(3000)', 'TEXT' => 'varchar(8000)', 'MTEXT' => 'TEXT', 'XSTEXT_UNI'=> 'varchar(100)', 'STEXT_UNI' => 'varchar(255)', 'TEXT_UNI' => 'varchar(4000)', 'MTEXT_UNI' => 'TEXT', 'TIMESTAMP' => 'INT4', // unsigned 'DECIMAL' => 'decimal(5,2)', 'DECIMAL:' => 'decimal(%d,2)', 'PDECIMAL' => 'decimal(6,3)', 'PDECIMAL:' => 'decimal(%d,3)', 'VCHAR_UNI' => 'varchar(255)', 'VCHAR_UNI:'=> 'varchar(%d)', 'VCHAR_CI' => 'varchar_ci', 'VARBINARY' => 'bytea', ), ); } /** * A list of types being unsigned for better reference in some db's * @var array */ var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP'); /** * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. * @var array */ var $supported_dbms = array('mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite', 'sqlite3'); /** * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array). * This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command. */ var $return_statements = false; /** * Constructor. Set DB Object and set {@link $return_statements return_statements}. * * @param \phpbb\db\driver\driver_interface $db Database connection * @param bool $return_statements True if only statements should be returned and no SQL being executed */ public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false) { $this->db = $db; $this->return_statements = $return_statements; $this->dbms_type_map = self::get_dbms_type_map(); // Determine mapping database type switch ($this->db->get_sql_layer()) { case 'mysql': $this->sql_layer = 'mysql_40'; break; case 'mysql4': if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) { $this->sql_layer = 'mysql_41'; } else { $this->sql_layer = 'mysql_40'; } break; case 'mysqli': $this->sql_layer = 'mysql_41'; break; case 'mssql': case 'mssql_odbc': $this->sql_layer = 'mssql'; break; case 'mssqlnative': $this->sql_layer = 'mssqlnative'; break; default: $this->sql_layer = $this->db->get_sql_layer(); break; } } /** * Setter for {@link $return_statements return_statements}. * * @param bool $return_statements True if SQL should not be executed but returned as strings * @return null */ public function set_return_statements($return_statements) { $this->return_statements = $return_statements; } /** * Gets a list of tables in the database. * * @return array Array of table names (all lower case) */ function sql_list_tables() { switch ($this->db->get_sql_layer()) { case 'mysql': case 'mysql4': case 'mysqli': $sql = 'SHOW TABLES'; break; case 'sqlite': $sql = 'SELECT name FROM sqlite_master WHERE type = "table"'; break; case 'sqlite3': $sql = 'SELECT name FROM sqlite_master WHERE type = "table" AND name <> "sqlite_sequence"'; break; case 'mssql': case 'mssql_odbc': case 'mssqlnative': $sql = "SELECT name FROM sysobjects WHERE type='U'"; break; case 'postgres': $sql = 'SELECT relname FROM pg_stat_user_tables'; break; case 'oracle': $sql = 'SELECT table_name FROM USER_TABLES'; break; } $result = $this->db->sql_query($sql); $tables = array(); while ($row = $this->db->sql_fetchrow($result)) { $name = current($row); $tables[$name] = $name; } $this->db->sql_freeresult($result); return $tables; } /** * Check if table exists * * * @param string $table_name The table name to check for * @return bool true if table exists, else false */ function sql_table_exists($table_name) { $this->db->sql_return_on_error(true); $result = $this->db->sql_query_limit('SELECT * FROM ' . $table_name, 1); $this->db->sql_return_on_error(false); if ($result) { $this->db->sql_freeresult($result); return true; } return false; } /** * Create SQL Table * * @param string $table_name The table name to create * @param array $table_data Array containing table data. * @return array Statements if $return_statements is true. */ function sql_create_table($table_name, $table_data) { // holds the DDL for a column $columns = $statements = array(); if ($this->sql_table_exists($table_name)) { return $this->_sql_run_sql($statements); } // Begin transaction $statements[] = 'begin'; // Determine if we have created a PRIMARY KEY in the earliest $primary_key_gen = false; // Determine if the table requires a sequence $create_sequence = false; // Begin table sql statement switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n"; break; default: $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n"; break; } if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { if (!isset($table_data['PRIMARY_KEY'])) { $table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment'); $table_data['PRIMARY_KEY'] = 'mssqlindex'; } } // Iterate through the columns to create a table foreach ($table_data['COLUMNS'] as $column_name => $column_data) { // here lies an array, filled with information compiled on the column's data $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen" { trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); } // here we add the definition of the new column to the list of columns switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default']; break; default: $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql']; break; } // see if we have found a primary key set due to a column definition if we have found it, we can stop looking if (!$primary_key_gen) { $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; } // create sequence DDL based off of the existance of auto incrementing columns if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) { $create_sequence = $column_name; } } // this makes up all the columns in the create table statement $table_sql .= implode(",\n", $columns); // Close the table for two DBMS and add to the statements switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': $table_sql .= "\n);"; $statements[] = $table_sql; break; } // we have yet to create a primary key for this table, // this means that we can add the one we really wanted instead if (!$primary_key_gen) { // Write primary key if (isset($table_data['PRIMARY_KEY'])) { if (!is_array($table_data['PRIMARY_KEY'])) { $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']); } switch ($this->sql_layer) { case 'mysql_40': case 'mysql_41': case 'postgres': case 'sqlite': case 'sqlite3': $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; break; case 'mssql': case 'mssqlnative': // We need the data here $old_return_statements = $this->return_statements; $this->return_statements = true; $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']); foreach ($primary_key_stmts as $pk_stmt) { $statements[] = $pk_stmt; } $this->return_statements = $old_return_statements; break; case 'oracle': $table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; break; } } } // close the table switch ($this->sql_layer) { case 'mysql_41': // make sure the table is in UTF-8 mode $table_sql .= "\n) CHARACTER SET `utf8` COLLATE `utf8_bin`;"; $statements[] = $table_sql; break; case 'mysql_40': case 'sqlite': case 'sqlite3': $table_sql .= "\n);"; $statements[] = $table_sql; break; case 'postgres': // do we need to add a sequence for auto incrementing columns? if ($create_sequence) { $statements[] = "CREATE SEQUENCE {$table_name}_seq;"; } $table_sql .= "\n);"; $statements[] = $table_sql; break; case 'oracle': $table_sql .= "\n)"; $statements[] = $table_sql; // do we need to add a sequence and a tigger for auto incrementing columns? if ($create_sequence) { // create the actual sequence $statements[] = "CREATE SEQUENCE {$table_name}_seq"; // the trigger is the mechanism by which we increment the counter $trigger = "CREATE OR REPLACE TRIGGER t_{$table_name}\n"; $trigger .= "BEFORE INSERT ON {$table_name}\n"; $trigger .= "FOR EACH ROW WHEN (\n"; $trigger .= "\tnew.{$create_sequence} IS NULL OR new.{$create_sequence} = 0\n"; $trigger .= ")\n"; $trigger .= "BEGIN\n"; $trigger .= "\tSELECT {$table_name}_seq.nextval\n"; $trigger .= "\tINTO :new.{$create_sequence}\n"; $trigger .= "\tFROM dual;\n"; $trigger .= "END;"; $statements[] = $trigger; } break; } // Write Keys if (isset($table_data['KEYS'])) { foreach ($table_data['KEYS'] as $key_name => $key_data) { if (!is_array($key_data[1])) { $key_data[1] = array($key_data[1]); } $old_return_statements = $this->return_statements; $this->return_statements = true; $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]); foreach ($key_stmts as $key_stmt) { $statements[] = $key_stmt; } $this->return_statements = $old_return_statements; } } // Commit Transaction $statements[] = 'commit'; return $this->_sql_run_sql($statements); } /** * Handle passed database update array. * Expected structure... * Key being one of the following * drop_tables: Drop tables * add_tables: Add tables * change_columns: Column changes (only type, not name) * add_columns: Add columns to a table * drop_keys: Dropping keys * drop_columns: Removing/Dropping columns * add_primary_keys: adding primary keys * add_unique_index: adding an unique index * add_index: adding an index (can be column:index_size if you need to provide size) * * The values are in this format: * {TABLE NAME} => array( * {COLUMN NAME} => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}), * {KEY/INDEX NAME} => array({COLUMN NAMES}), * ) * * For more information have a look at /develop/create_schema_files.php (only available through SVN) */ function perform_schema_changes($schema_changes) { if (empty($schema_changes)) { return; } $statements = array(); $sqlite = false; // For SQLite we need to perform the schema changes in a much more different way if (($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3') && $this->return_statements) { $sqlite_data = array(); $sqlite = true; } // Drop tables? if (!empty($schema_changes['drop_tables'])) { foreach ($schema_changes['drop_tables'] as $table) { // only drop table if it exists if ($this->sql_table_exists($table)) { $result = $this->sql_table_drop($table); if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } // Add tables? if (!empty($schema_changes['add_tables'])) { foreach ($schema_changes['add_tables'] as $table => $table_data) { $result = $this->sql_create_table($table, $table_data); if ($this->return_statements) { $statements = array_merge($statements, $result); } } } // Change columns? if (!empty($schema_changes['change_columns'])) { foreach ($schema_changes['change_columns'] as $table => $columns) { foreach ($columns as $column_name => $column_data) { // If the column exists we change it, else we add it ;) if ($column_exists = $this->sql_column_exists($table, $column_name)) { $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { $result = $this->sql_column_add($table, $column_name, $column_data, true); } if ($sqlite) { if ($column_exists) { $sqlite_data[$table]['change_columns'][] = $result; } else { $sqlite_data[$table]['add_columns'][] = $result; } } else if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } // Add columns? if (!empty($schema_changes['add_columns'])) { foreach ($schema_changes['add_columns'] as $table => $columns) { foreach ($columns as $column_name => $column_data) { // Only add the column if it does not exist yet if ($column_exists = $this->sql_column_exists($table, $column_name)) { continue; // This is commented out here because it can take tremendous time on updates // $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { $result = $this->sql_column_add($table, $column_name, $column_data, true); } if ($sqlite) { if ($column_exists) { continue; // $sqlite_data[$table]['change_columns'][] = $result; } else { $sqlite_data[$table]['add_columns'][] = $result; } } else if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } // Remove keys? if (!empty($schema_changes['drop_keys'])) { foreach ($schema_changes['drop_keys'] as $table => $indexes) { foreach ($indexes as $index_name) { if (!$this->sql_index_exists($table, $index_name)) { continue; } $result = $this->sql_index_drop($table, $index_name); if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } // Drop columns? if (!empty($schema_changes['drop_columns'])) { foreach ($schema_changes['drop_columns'] as $table => $columns) { foreach ($columns as $column) { // Only remove the column if it exists... if ($this->sql_column_exists($table, $column)) { $result = $this->sql_column_remove($table, $column, true); if ($sqlite) { $sqlite_data[$table]['drop_columns'][] = $result; } else if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } } // Add primary keys? if (!empty($schema_changes['add_primary_keys'])) { foreach ($schema_changes['add_primary_keys'] as $table => $columns) { $result = $this->sql_create_primary_key($table, $columns, true); if ($sqlite) { $sqlite_data[$table]['primary_key'] = $result; } else if ($this->return_statements) { $statements = array_merge($statements, $result); } } } // Add unique indexes? if (!empty($schema_changes['add_unique_index'])) { foreach ($schema_changes['add_unique_index'] as $table => $index_array) { foreach ($index_array as $index_name => $column) { if ($this->sql_unique_index_exists($table, $index_name)) { continue; } $result = $this->sql_create_unique_index($table, $index_name, $column); if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } // Add indexes? if (!empty($schema_changes['add_index'])) { foreach ($schema_changes['add_index'] as $table => $index_array) { foreach ($index_array as $index_name => $column) { if ($this->sql_index_exists($table, $index_name)) { continue; } $result = $this->sql_create_index($table, $index_name, $column); if ($this->return_statements) { $statements = array_merge($statements, $result); } } } } if ($sqlite) { foreach ($sqlite_data as $table_name => $sql_schema_changes) { // Create temporary table with original data $statements[] = 'begin'; $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '{$table_name}' ORDER BY type DESC, name;"; $result = $this->db->sql_query($sql); if (!$result) { continue; } $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); // Create a backup table and populate it, destroy the existing one $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; // Get the columns... preg_match('#\((.*)\)#s', $row['sql'], $matches); $plain_table_cols = trim($matches[1]); $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols); $column_list = array(); foreach ($new_table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY') { continue; } $column_list[] = $entities[0]; } // note down the primary key notation because sqlite only supports adding it to the end for the new table $primary_key = false; $_new_cols = array(); foreach ($new_table_cols as $key => $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY') { $primary_key = $declaration; continue; } $_new_cols[] = $declaration; } $new_table_cols = $_new_cols; // First of all... change columns if (!empty($sql_schema_changes['change_columns'])) { foreach ($sql_schema_changes['change_columns'] as $column_sql) { foreach ($new_table_cols as $key => $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if (strpos($column_sql, $entities[0] . ' ') === 0) { $new_table_cols[$key] = $column_sql; } } } } if (!empty($sql_schema_changes['add_columns'])) { foreach ($sql_schema_changes['add_columns'] as $column_sql) { $new_table_cols[] = $column_sql; } } // Now drop them... if (!empty($sql_schema_changes['drop_columns'])) { foreach ($sql_schema_changes['drop_columns'] as $column_name) { // Remove from column list... $new_column_list = array(); foreach ($column_list as $key => $value) { if ($value === $column_name) { continue; } $new_column_list[] = $value; } $column_list = $new_column_list; // Remove from table... $_new_cols = array(); foreach ($new_table_cols as $key => $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if (strpos($column_name . ' ', $entities[0] . ' ') === 0) { continue; } $_new_cols[] = $declaration; } $new_table_cols = $_new_cols; } } // Primary key... if (!empty($sql_schema_changes['primary_key'])) { $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')'; } // Add a new one or the old primary key else if ($primary_key !== false) { $new_table_cols[] = $primary_key; } $columns = implode(',', $column_list); // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');'; $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; $statements[] = 'commit'; } } if ($this->return_statements) { return $statements; } } /** * Gets a list of columns of a table. * * @param string $table Table name * * @return array Array of column names (all lower case) */ function sql_list_columns($table) { $columns = array(); switch ($this->sql_layer) { case 'mysql_40': case 'mysql_41': $sql = "SHOW COLUMNS FROM $table"; break; // PostgreSQL has a way of doing this in a much simpler way but would // not allow us to support all versions of PostgreSQL case 'postgres': $sql = "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = '{$table}' AND a.attnum > 0 AND a.attrelid = c.oid"; break; // same deal with PostgreSQL, we must perform more complex operations than // we technically could case 'mssql': case 'mssqlnative': $sql = "SELECT c.name FROM syscolumns c LEFT JOIN sysobjects o ON c.id = o.id WHERE o.name = '{$table}'"; break; case 'oracle': $sql = "SELECT column_name FROM user_tab_columns WHERE LOWER(table_name) = '" . strtolower($table) . "'"; break; case 'sqlite': case 'sqlite3': $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '{$table}'"; $result = $this->db->sql_query($sql); if (!$result) { return false; } $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); preg_match('#\((.*)\)#s', $row['sql'], $matches); $cols = trim($matches[1]); $col_array = preg_split('/,(?![\s\w]+\))/m', $cols); foreach ($col_array as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY') { continue; } $column = strtolower($entities[0]); $columns[$column] = $column; } return $columns; break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $column = strtolower(current($row)); $columns[$column] = $column; } $this->db->sql_freeresult($result); return $columns; } /** * Check whether a specified column exist in a table * * @param string $table Table to check * @param string $column_name Column to check * * @return bool True if column exists, false otherwise */ function sql_column_exists($table, $column_name) { $columns = $this->sql_list_columns($table); return isset($columns[$column_name]); } /** * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. * * @param string $table_name Table to check the index at * @param string $index_name The index name to check * * @return bool True if index exists, else false */ function sql_index_exists($table_name, $index_name) { if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if ($row['TYPE'] == 3) { if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) { $this->db->sql_freeresult($result); return true; } } } $this->db->sql_freeresult($result); return false; } switch ($this->sql_layer) { case 'postgres': $sql = "SELECT ic.relname as index_name FROM pg_class bc, pg_class ic, pg_index i WHERE (bc.oid = i.indrelid) AND (ic.oid = i.indexrelid) AND (bc.relname = '" . $table_name . "') AND (i.indisunique != 't') AND (i.indisprimary != 't')"; $col = 'index_name'; break; case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; $col = 'Key_name'; break; case 'oracle': $sql = "SELECT index_name FROM user_indexes WHERE table_name = '" . strtoupper($table_name) . "' AND generated = 'N' AND uniqueness = 'NONUNIQUE'"; $col = 'index_name'; break; case 'sqlite': case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) { continue; } // These DBMS prefix index name with the table name switch ($this->sql_layer) { case 'oracle': case 'postgres': case 'sqlite': case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } if (strtolower($row[$col]) == strtolower($index_name)) { $this->db->sql_freeresult($result); return true; } } $this->db->sql_freeresult($result); return false; } /** * Check if a specified index exists in table. Does not return PRIMARY KEY indexes. * * @param string $table_name Table to check the index at * @param string $index_name The index name to check * * @return bool True if index exists, else false */ function sql_unique_index_exists($table_name, $index_name) { if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { // Usually NON_UNIQUE is the column we want to check, but we allow for both if ($row['TYPE'] == 3) { if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) { $this->db->sql_freeresult($result); return true; } } } $this->db->sql_freeresult($result); return false; } switch ($this->sql_layer) { case 'postgres': $sql = "SELECT ic.relname as index_name, i.indisunique FROM pg_class bc, pg_class ic, pg_index i WHERE (bc.oid = i.indrelid) AND (ic.oid = i.indexrelid) AND (bc.relname = '" . $table_name . "') AND (i.indisprimary != 't')"; $col = 'index_name'; break; case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; $col = 'Key_name'; break; case 'oracle': $sql = "SELECT index_name, table_owner FROM user_indexes WHERE table_name = '" . strtoupper($table_name) . "' AND generated = 'N' AND uniqueness = 'UNIQUE'"; $col = 'index_name'; break; case 'sqlite': case 'sqlite3': $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) { continue; } if (($this->sql_layer == 'sqlite' || $this->sql_layer == 'sqlite3') && !$row['unique']) { continue; } if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') { continue; } // These DBMS prefix index name with the table name switch ($this->sql_layer) { case 'oracle': // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name if (strpos($row[$col], 'U_') === 0) { $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); } else if (strpos($row[$col], strtoupper($table_name)) === 0) { $row[$col] = substr($row[$col], strlen($table_name) + 1); } break; case 'postgres': case 'sqlite': case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } if (strtolower($row[$col]) == strtolower($index_name)) { $this->db->sql_freeresult($result); return true; } } $this->db->sql_freeresult($result); return false; } /** * Private method for performing sql statements (either execute them or return them) * @access private */ function _sql_run_sql($statements) { if ($this->return_statements) { return $statements; } // We could add error handling here... foreach ($statements as $sql) { if ($sql === 'begin') { $this->db->sql_transaction('begin'); } else if ($sql === 'commit') { $this->db->sql_transaction('commit'); } else { $this->db->sql_query($sql); } } return true; } /** * Function to prepare some column information for better usage * @access private */ function sql_prepare_column_data($table_name, $column_name, $column_data) { if (strlen($column_name) > 30) { trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); } // Get type list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]); // Adjust default value if db-dependent specified if (is_array($column_data[1])) { $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default']; } $sql = ''; $return_array = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': $sql .= " {$column_type} "; $sql_default = " {$column_type} "; // For adding columns we need the default definition if (!is_null($column_data[1])) { // For hexadecimal values do not use single quotes if (strpos($column_data[1], '0x') === 0) { $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; $sql_default .= $return_array['default']; } else { $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; $sql_default .= $return_array['default']; } } if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { // $sql .= 'IDENTITY (1, 1) '; $sql_default .= 'IDENTITY (1, 1) '; } $return_array['textimage'] = $column_type === '[text]'; if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment')) { $sql .= 'NOT NULL'; $sql_default .= 'NOT NULL'; } else { $sql .= 'NULL'; $sql_default .= 'NULL'; } $return_array['column_type_sql_default'] = $sql_default; break; case 'mysql_40': case 'mysql_41': $sql .= " {$column_type} "; // For hexadecimal values do not use single quotes if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob') { $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' "; } if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment')) { $sql .= 'NOT NULL'; } else { $sql .= 'NULL'; } if (isset($column_data[2])) { if ($column_data[2] == 'auto_increment') { $sql .= ' auto_increment'; } else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort') { $sql .= ' COLLATE utf8_unicode_ci'; } } break; case 'oracle': $sql .= " {$column_type} "; $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : ''; // In Oracle empty strings ('') are treated as NULL. // Therefore in oracle we allow NULL's for all DEFAULT '' entries // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields) if (!preg_match('/number/i', $column_type)) { $sql .= ($column_data[1] === '' || $column_data[1] === null) ? '' : 'NOT NULL'; } $return_array['auto_increment'] = false; if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { $return_array['auto_increment'] = true; } break; case 'postgres': $return_array['column_type'] = $column_type; $sql .= " {$column_type} "; $return_array['auto_increment'] = false; if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { $default_val = "nextval('{$table_name}_seq')"; $return_array['auto_increment'] = true; } else if (!is_null($column_data[1])) { $default_val = "'" . $column_data[1] . "'"; $return_array['null'] = 'NOT NULL'; $sql .= 'NOT NULL '; } else { // Integers need to have 0 instead of empty string as default if (strpos($column_type, 'INT') === 0) { $default_val = '0'; } else { $default_val = "'" . $column_data[1] . "'"; } $return_array['null'] = 'NULL'; $sql .= 'NULL '; } $return_array['default'] = $default_val; $sql .= "DEFAULT {$default_val}"; // Unsigned? Then add a CHECK contraint if (in_array($orig_column_type, $this->unsigned_types)) { $return_array['constraint'] = "CHECK ({$column_name} >= 0)"; $sql .= " CHECK ({$column_name} >= 0)"; } break; case 'sqlite': case 'sqlite3': $return_array['primary_key_set'] = false; if (isset($column_data[2]) && $column_data[2] == 'auto_increment') { $sql .= ' INTEGER PRIMARY KEY'; $return_array['primary_key_set'] = true; if ($this->sql_layer === 'sqlite3') { $sql .= ' AUTOINCREMENT'; } } else { $sql .= ' ' . $column_type; } if (!is_null($column_data[1])) { $sql .= ' NOT NULL '; $sql .= "DEFAULT '{$column_data[1]}'"; } break; } $return_array['column_type_sql'] = $sql; return $return_array; } /** * Get the column's database type from the type map * * @param string $column_map_type * @return array column type for this database * and map type without length */ function get_column_type($column_map_type) { if (strpos($column_map_type, ':') !== false) { list($orig_column_type, $column_length) = explode(':', $column_map_type); if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'])) { $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length); } else { if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'])) { switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0]) { case 'div': $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1]; $column_length = ceil($column_length); $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length); break; } } if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'])) { switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0]) { case 'mult': $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1]; if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2]) { $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3]; } else { $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length); } break; } } } $orig_column_type .= ':'; } else { $orig_column_type = $column_map_type; $column_type = $this->dbms_type_map[$this->sql_layer][$column_map_type]; } return array($column_type, $orig_column_type); } /** * Add new column */ function sql_column_add($table_name, $column_name, $column_data, $inline = false) { $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; break; case 'mysql_40': case 'mysql_41': $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after; break; case 'oracle': // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; case 'postgres': // Does not support AFTER, only through temporary table if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) { $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; } else { // old versions cannot add columns with default and null information $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint']; if (isset($column_data['null'])) { if ($column_data['null'] == 'NOT NULL') { $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL'; } } if (isset($column_data['default'])) { $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; } } break; case 'sqlite': if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); if (empty($recreate_queries)) { break; } $statements[] = 'begin'; $sql_create_table = array_shift($recreate_queries); // Create a backup table and populate it, destroy the existing one $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); $column_list = array(); foreach ($old_table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY') { continue; } $column_list[] = $entities[0]; } $columns = implode(',', $column_list); $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; $statements = array_merge($statements, $recreate_queries); $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; $statements[] = 'commit'; break; case 'sqlite3': if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; } return $this->_sql_run_sql($statements); } /** * Drop column */ function sql_column_remove($table_name, $column_name, $inline = false) { $statements = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': // We need the data here $old_return_statements = $this->return_statements; $this->return_statements = true; $indexes = $this->get_existing_indexes($table_name, $column_name); $indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true)); // Drop any indexes $recreate_indexes = array(); if (!empty($indexes)) { foreach ($indexes as $index_name => $index_data) { $result = $this->sql_index_drop($table_name, $index_name); $statements = array_merge($statements, $result); if (sizeof($index_data) > 1) { // Remove this column from the index and recreate it $recreate_indexes[$index_name] = array_diff($index_data, array($column_name)); } } } // Drop default value constraint $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); $statements = array_merge($statements, $result); // Remove the column $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; if (!empty($recreate_indexes)) { // Recreate indexes after we removed the column foreach ($recreate_indexes as $index_name => $index_data) { $result = $this->sql_create_index($table_name, $index_name, $index_data); $statements = array_merge($statements, $result); } } $this->return_statements = $old_return_statements; break; case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`'; break; case 'oracle': $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name; break; case 'postgres': $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"'; break; case 'sqlite': case 'sqlite3': if ($inline && $this->return_statements) { return $column_name; } $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name, $column_name); if (empty($recreate_queries)) { break; } $statements[] = 'begin'; $sql_create_table = array_shift($recreate_queries); // Create a backup table and populate it, destroy the existing one $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); $column_list = array(); foreach ($old_table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) { continue; } $column_list[] = $entities[0]; } $columns = implode(',', $column_list); $new_table_cols = trim(preg_replace('/' . $column_name . '\b[^,]+(?:,|$)/m', '', $new_table_cols)); if (substr($new_table_cols, -1) === ',') { // Remove the comma from the last entry again $new_table_cols = substr($new_table_cols, 0, -1); } // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; $statements = array_merge($statements, $recreate_queries); $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; $statements[] = 'commit'; break; } return $this->_sql_run_sql($statements); } /** * Drop Index */ function sql_index_drop($table_name, $index_name) { $statements = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; break; case 'mysql_40': case 'mysql_41': $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name; break; case 'oracle': case 'postgres': case 'sqlite': case 'sqlite3': $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; break; } return $this->_sql_run_sql($statements); } /** * Drop Table */ function sql_table_drop($table_name) { $statements = array(); if (!$this->sql_table_exists($table_name)) { return $this->_sql_run_sql($statements); } // the most basic operation, get rid of the table $statements[] = 'DROP TABLE ' . $table_name; switch ($this->sql_layer) { case 'oracle': $sql = 'SELECT A.REFERENCED_NAME FROM USER_DEPENDENCIES A, USER_TRIGGERS B WHERE A.REFERENCED_TYPE = \'SEQUENCE\' AND A.NAME = B.TRIGGER_NAME AND B.TABLE_NAME = \'' . strtoupper($table_name) . "'"; $result = $this->db->sql_query($sql); // any sequences ref'd to this table's triggers? while ($row = $this->db->sql_fetchrow($result)) { $statements[] = "DROP SEQUENCE {$row['referenced_name']}"; } $this->db->sql_freeresult($result); break; case 'postgres': // PGSQL does not "tightly" bind sequences and tables, we must guess... $sql = "SELECT relname FROM pg_class WHERE relkind = 'S' AND relname = '{$table_name}_seq'"; $result = $this->db->sql_query($sql); // We don't even care about storing the results. We already know the answer if we get rows back. if ($this->db->sql_fetchrow($result)) { $statements[] = "DROP SEQUENCE {$table_name}_seq;\n"; } $this->db->sql_freeresult($result); break; } return $this->_sql_run_sql($statements); } /** * Add primary key */ function sql_create_primary_key($table_name, $column, $inline = false) { $statements = array(); switch ($this->sql_layer) { case 'postgres': case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')'; break; case 'mssql': case 'mssqlnative': $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD "; $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED ("; $sql .= '[' . implode("],\n\t\t[", $column) . ']'; $sql .= ')'; $statements[] = $sql; break; case 'oracle': $statements[] = 'ALTER TABLE ' . $table_name . ' add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')'; break; case 'sqlite': case 'sqlite3': if ($inline && $this->return_statements) { return $column; } $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); if (empty($recreate_queries)) { break; } $statements[] = 'begin'; $sql_create_table = array_shift($recreate_queries); // Create a backup table and populate it, destroy the existing one $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); $column_list = array(); foreach ($old_table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); if ($entities[0] == 'PRIMARY') { continue; } $column_list[] = $entities[0]; } $columns = implode(',', $column_list); // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));'; $statements = array_merge($statements, $recreate_queries); $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; $statements[] = 'commit'; break; } return $this->_sql_run_sql($statements); } /** * Add unique index */ function sql_create_unique_index($table_name, $index_name, $column) { $statements = array(); $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) if (strlen($table_name . '_' . $index_name) - strlen($table_prefix) > 24) { $max_length = strlen($table_prefix) + 24; trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); } switch ($this->sql_layer) { case 'postgres': case 'oracle': case 'sqlite': case 'sqlite3': $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; break; case 'mssql': case 'mssqlnative': $statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; break; } return $this->_sql_run_sql($statements); } /** * Add index */ function sql_create_index($table_name, $index_name, $column) { $statements = array(); $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) { $max_length = strlen($table_prefix) + 24; trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); } // remove index length unless MySQL4 if ('mysql_40' != $this->sql_layer) { $column = preg_replace('#:.*$#', '', $column); } switch ($this->sql_layer) { case 'postgres': case 'oracle': case 'sqlite': case 'sqlite3': $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; case 'mysql_40': // add index size to definition as required by MySQL4 foreach ($column as $i => $col) { if (false !== strpos($col, ':')) { list($col, $index_size) = explode(':', $col); $column[$i] = "$col($index_size)"; } } // no break case 'mysql_41': $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')'; break; case 'mssql': case 'mssqlnative': $statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; break; } return $this->_sql_run_sql($statements); } /** * List all of the indices that belong to a table, * does not count: * * UNIQUE indices * * PRIMARY keys */ function sql_list_index($table_name) { $index_array = array(); if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if ($row['TYPE'] == 3) { $index_array[] = $row['INDEX_NAME']; } } $this->db->sql_freeresult($result); } else { switch ($this->sql_layer) { case 'postgres': $sql = "SELECT ic.relname as index_name FROM pg_class bc, pg_class ic, pg_index i WHERE (bc.oid = i.indrelid) AND (ic.oid = i.indexrelid) AND (bc.relname = '" . $table_name . "') AND (i.indisunique != 't') AND (i.indisprimary != 't')"; $col = 'index_name'; break; case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; $col = 'Key_name'; break; case 'oracle': $sql = "SELECT index_name FROM user_indexes WHERE table_name = '" . strtoupper($table_name) . "' AND generated = 'N' AND uniqueness = 'NONUNIQUE'"; $col = 'index_name'; break; case 'sqlite': case 'sqlite3': $sql = "PRAGMA index_info('" . $table_name . "');"; $col = 'name'; break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) { continue; } switch ($this->sql_layer) { case 'oracle': case 'postgres': case 'sqlite': case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); break; } $index_array[] = $row[$col]; } $this->db->sql_freeresult($result); } return array_map('strtolower', $index_array); } /** * Removes table_name from the index_name if it is at the beginning * * @param $table_name * @param $index_name * @return string */ protected function strip_table_name_from_index_name($table_name, $index_name) { return (strpos(strtoupper($index_name), strtoupper($table_name)) === 0) ? substr($index_name, strlen($table_name) + 1) : $index_name; } /** * Change column type (not name!) */ function sql_column_change($table_name, $column_name, $column_data, $inline = false) { $original_column_data = $column_data; $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': // We need the data here $old_return_statements = $this->return_statements; $this->return_statements = true; $indexes = $this->get_existing_indexes($table_name, $column_name); $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); // Drop any indexes if (!empty($indexes) || !empty($unique_indexes)) { $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); foreach ($drop_indexes as $index_name) { $result = $this->sql_index_drop($table_name, $index_name); $statements = array_merge($statements, $result); } } // Drop default value constraint $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); $statements = array_merge($statements, $result); // Change the column $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; if (!empty($column_data['default'])) { // Add new default value constraint $statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $this->db->sql_escape($column_data['default']) . ' FOR [' . $column_name . ']'; } if (!empty($indexes)) { // Recreate indexes after we changed the column foreach ($indexes as $index_name => $index_data) { $result = $this->sql_create_index($table_name, $index_name, $index_data); $statements = array_merge($statements, $result); } } if (!empty($unique_indexes)) { // Recreate unique indexes after we changed the column foreach ($unique_indexes as $index_name => $index_data) { $result = $this->sql_create_unique_index($table_name, $index_name, $index_data); $statements = array_merge($statements, $result); } } $this->return_statements = $old_return_statements; break; case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql']; break; case 'oracle': // We need the data here $old_return_statements = $this->return_statements; $this->return_statements = true; // Get list of existing indexes $indexes = $this->get_existing_indexes($table_name, $column_name); $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); // Drop any indexes if (!empty($indexes) || !empty($unique_indexes)) { $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); foreach ($drop_indexes as $index_name) { $result = $this->sql_index_drop($table_name, $this->strip_table_name_from_index_name($table_name, $index_name)); $statements = array_merge($statements, $result); } } $temp_column_name = 'temp_' . substr(md5($column_name), 0, 25); // Add a temporary table with the new type $result = $this->sql_column_add($table_name, $temp_column_name, $original_column_data); $statements = array_merge($statements, $result); // Copy the data to the new column $statements[] = 'UPDATE ' . $table_name . ' SET ' . $temp_column_name . ' = ' . $column_name; // Drop the original column $result = $this->sql_column_remove($table_name, $column_name); $statements = array_merge($statements, $result); // Recreate the original column with the new type $result = $this->sql_column_add($table_name, $column_name, $original_column_data); $statements = array_merge($statements, $result); if (!empty($indexes)) { // Recreate indexes after we changed the column foreach ($indexes as $index_name => $index_data) { $result = $this->sql_create_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data); $statements = array_merge($statements, $result); } } if (!empty($unique_indexes)) { // Recreate unique indexes after we changed the column foreach ($unique_indexes as $index_name => $index_data) { $result = $this->sql_create_unique_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data); $statements = array_merge($statements, $result); } } // Copy the data to the original column $statements[] = 'UPDATE ' . $table_name . ' SET ' . $column_name . ' = ' . $temp_column_name; // Drop the temporary column again $result = $this->sql_column_remove($table_name, $temp_column_name); $statements = array_merge($statements, $result); $this->return_statements = $old_return_statements; break; case 'postgres': $sql = 'ALTER TABLE ' . $table_name . ' '; $sql_array = array(); $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type']; if (isset($column_data['null'])) { if ($column_data['null'] == 'NOT NULL') { $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL'; } else if ($column_data['null'] == 'NULL') { $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL'; } } if (isset($column_data['default'])) { $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; } // we don't want to double up on constraints if we change different number data types if (isset($column_data['constraint'])) { $constraint_sql = "SELECT consrc as constraint_data FROM pg_constraint, pg_class bc WHERE conrelid = bc.oid AND bc.relname = '{$table_name}' AND NOT EXISTS ( SELECT * FROM pg_constraint as c, pg_inherits as i WHERE i.inhrelid = pg_constraint.conrelid AND c.conname = pg_constraint.conname AND c.consrc = pg_constraint.consrc AND c.conrelid = i.inhparent )"; $constraint_exists = false; $result = $this->db->sql_query($constraint_sql); while ($row = $this->db->sql_fetchrow($result)) { if (trim($row['constraint_data']) == trim($column_data['constraint'])) { $constraint_exists = true; break; } } $this->db->sql_freeresult($result); if (!$constraint_exists) { $sql_array[] = 'ADD ' . $column_data['constraint']; } } $sql .= implode(', ', $sql_array); $statements[] = $sql; break; case 'sqlite': case 'sqlite3': if ($inline && $this->return_statements) { return $column_name . ' ' . $column_data['column_type_sql']; } $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name); if (empty($recreate_queries)) { break; } $statements[] = 'begin'; $sql_create_table = array_shift($recreate_queries); // Create a temp table and populate it, destroy the existing one $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table); $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; $statements[] = 'DROP TABLE ' . $table_name; preg_match('#\((.*)\)#s', $sql_create_table, $matches); $new_table_cols = trim($matches[1]); $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); $column_list = array(); foreach ($old_table_cols as $key => $declaration) { $declaration = trim($declaration); // Check for the beginning of the constraint section and stop if (preg_match('/[^\(]*\s*PRIMARY KEY\s+\(/', $declaration) || preg_match('/[^\(]*\s*UNIQUE\s+\(/', $declaration) || preg_match('/[^\(]*\s*FOREIGN KEY\s+\(/', $declaration) || preg_match('/[^\(]*\s*CHECK\s+\(/', $declaration)) { break; } $entities = preg_split('#\s+#', $declaration); $column_list[] = $entities[0]; if ($entities[0] == $column_name) { $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql']; } } $columns = implode(',', $column_list); // Create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');'; $statements = array_merge($statements, $recreate_queries); $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; $statements[] = 'DROP TABLE ' . $table_name . '_temp'; $statements[] = 'commit'; break; } return $this->_sql_run_sql($statements); } /** * Get queries to drop the default constraints of a column * * We need to drop the default constraints of a column, * before being able to change their type or deleting them. * * @param string $table_name * @param string $column_name * @return array Array with SQL statements */ protected function mssql_get_drop_default_constraints_queries($table_name, $column_name) { $statements = array(); if ($this->mssql_is_sql_server_2000()) { // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx // Deprecated in SQL Server 2005 $sql = "SELECT so.name AS def_name FROM sysobjects so JOIN sysconstraints sc ON so.id = sc.constid WHERE object_name(so.parent_obj) = '{$table_name}' AND so.xtype = 'D' AND sc.colid = (SELECT colid FROM syscolumns WHERE id = object_id('{$table_name}') AND name = '{$column_name}')"; } else { $sql = "SELECT dobj.name AS def_name FROM sys.columns col LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D') WHERE col.object_id = object_id('{$table_name}') AND col.name = '{$column_name}' AND dobj.name IS NOT NULL"; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']'; } $this->db->sql_freeresult($result); return $statements; } /** * Get a list with existing indexes for the column * * @param string $table_name * @param string $column_name * @param bool $unique Should we get unique indexes or normal ones * @return array Array with Index name => columns */ public function get_existing_indexes($table_name, $column_name, $unique = false) { switch ($this->sql_layer) { case 'mysql_40': case 'mysql_41': case 'postgres': case 'sqlite': case 'sqlite3': // Not supported throw new \Exception('DBMS is not supported'); break; } $sql = ''; $existing_indexes = array(); switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': if ($this->mssql_is_sql_server_2000()) { // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx // Deprecated in SQL Server 2005 $sql = "SELECT DISTINCT ix.name AS phpbb_index_name FROM sysindexes ix INNER JOIN sysindexkeys ixc ON ixc.id = ix.id AND ixc.indid = ix.indid INNER JOIN syscolumns cols ON cols.colid = ixc.colid AND cols.id = ix.id WHERE ix.id = object_id('{$table_name}') AND cols.name = '{$column_name}' AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0'); } else { $sql = "SELECT DISTINCT ix.name AS phpbb_index_name FROM sys.indexes ix INNER JOIN sys.index_columns ixc ON ixc.object_id = ix.object_id AND ixc.index_id = ix.index_id INNER JOIN sys.columns cols ON cols.column_id = ixc.column_id AND cols.object_id = ix.object_id WHERE ix.object_id = object_id('{$table_name}') AND cols.name = '{$column_name}' AND ix.is_unique = " . ($unique ? '1' : '0'); } break; case 'oracle': $sql = "SELECT ix.index_name AS phpbb_index_name, ix.uniqueness AS is_unique FROM all_ind_columns ixc, all_indexes ix WHERE ix.index_name = ixc.index_name AND ixc.table_name = '" . strtoupper($table_name) . "' AND ixc.column_name = '" . strtoupper($column_name) . "'"; break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE')) { $existing_indexes[$row['phpbb_index_name']] = array(); } } $this->db->sql_freeresult($result); if (empty($existing_indexes)) { return array(); } switch ($this->sql_layer) { case 'mssql': case 'mssqlnative': if ($this->mssql_is_sql_server_2000()) { $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name FROM sysindexes ix INNER JOIN sysindexkeys ixc ON ixc.id = ix.id AND ixc.indid = ix.indid INNER JOIN syscolumns cols ON cols.colid = ixc.colid AND cols.id = ix.id WHERE ix.id = object_id('{$table_name}') AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); } else { $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name FROM sys.indexes ix INNER JOIN sys.index_columns ixc ON ixc.object_id = ix.object_id AND ixc.index_id = ix.index_id INNER JOIN sys.columns cols ON cols.column_id = ixc.column_id AND cols.object_id = ix.object_id WHERE ix.object_id = object_id('{$table_name}') AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); } break; case 'oracle': $sql = "SELECT index_name AS phpbb_index_name, column_name AS phpbb_column_name FROM all_ind_columns WHERE table_name = '" . strtoupper($table_name) . "' AND " . $this->db->sql_in_set('index_name', array_keys($existing_indexes)); break; } $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name']; } $this->db->sql_freeresult($result); return $existing_indexes; } /** * Is the used MS SQL Server a SQL Server 2000? * * @return bool */ protected function mssql_is_sql_server_2000() { if ($this->is_sql_server_2000 === null) { $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version"; $result = $this->db->sql_query($sql); $properties = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); $this->is_sql_server_2000 = $properties['mssql_version'][0] == '8'; } return $this->is_sql_server_2000; } /** * Returns the Queries which are required to recreate a table including indexes * * @param string $table_name * @param string $remove_column When we drop a column, we remove the column * from all indexes. If the index has no other * column, we drop it completly. * @return array */ protected function sqlite_get_recreate_table_queries($table_name, $remove_column = '') { $queries = array(); $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '{$table_name}'"; $result = $this->db->sql_query($sql); $sql_create_table = $this->db->sql_fetchfield('sql'); $this->db->sql_freeresult($result); if (!$sql_create_table) { return array(); } $queries[] = $sql_create_table; $sql = "SELECT sql FROM sqlite_master WHERE type = 'index' AND tbl_name = '{$table_name}'"; $result = $this->db->sql_query($sql); while ($sql_create_index = $this->db->sql_fetchfield('sql')) { if ($remove_column) { $match = array(); preg_match('#(?:[\w ]+)\((.*)\)#', $sql_create_index, $match); if (!isset($match[1])) { continue; } // Find and remove $remove_column from the index $columns = explode(', ', $match[1]); $found_column = array_search($remove_column, $columns); if ($found_column !== false) { unset($columns[$found_column]); // If the column list is not empty add the index to the list if (!empty($columns)) { $queries[] = str_replace($match[1], implode(', ', $columns), $sql_create_index); } } else { $queries[] = $sql_create_index; } } else { $queries[] = $sql_create_index; } } $this->db->sql_freeresult($result); return $queries; } } migrator_output_handler_interface.php000077700000001450151514672100014247 0ustar00<?php /** * * This file is part of the phpBB Forum Software package. * * @copyright (c) phpBB Limited <https://www.phpbb.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ namespace phpbb\db; interface migrator_output_handler_interface { const VERBOSITY_QUIET = 0; const VERBOSITY_NORMAL = 1; const VERBOSITY_VERBOSE = 2; const VERBOSITY_VERY_VERBOSE = 3; const VERBOSITY_DEBUG = 4; /** * Write output using the configured closure. * * @param string|array $message The message to write or an array containing the language key and all of its parameters. * @param int $verbosity The verbosity of the message. */ public function write($message, $verbosity); }
/home/www/hallgroupsolutions.com/./c9428/db.tar