2 rcs_id('$Id: upgrade.php,v 1.47 2005-02-27 19:13:27 rurban Exp $');
4 Copyright 2004,2005 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
8 PhpWiki is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 PhpWiki is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Upgrade the WikiDB and config settings after installing a new
26 * Status: experimental, no queries for verification yet,
27 * no merge conflict resolution (patch?), just overwrite.
29 * Installation on an existing PhpWiki database needs some
30 * additional worksteps. Each step will require multiple pages.
33 * 1. Check for new or changed database schema and update it
34 * according to some predefined upgrade tables. (medium, complete)
35 * 2. Check for new or changed (localized) pgsrc/ pages and ask
36 * for upgrading these. Check timestamps, upgrade silently or
37 * show diffs if existing. Overwrite or merge (easy, complete)
38 * 3. Check for new or changed or deprecated index.php/config.ini settings
39 * and help in upgrading these. (hard)
40 * 3a Convert old-style index.php into config/config.ini. (easy)
41 * 4. Check for changed plugin invocation arguments. (hard)
42 * 5. Check for changed theme variables. (hard)
43 * 6. Convert the single-request upgrade to a class-based multi-page
46 * Done: overwrite=1 link on edit conflicts at first occurence "Overwrite all".
48 * @author: Reini Urban
50 require_once("lib/loadsave.php");
53 * TODO: check for the pgsrc_version number, not the revision mtime only
55 function doPgsrcUpdate(&$request,$pagename,$path,$filename) {
56 $dbi = $request->getDbh();
57 $page = $dbi->getPage($pagename);
58 if ($page->exists()) {
59 // check mtime: update automatically if pgsrc is newer
60 $rev = $page->getCurrentRevision();
61 $page_mtime = $rev->get('mtime');
62 $data = implode("", file($path."/".$filename));
63 if (($parts = ParseMimeifiedPages($data))) {
64 usort($parts, 'SortByPageVersion');
66 $pageinfo = $parts[0];
67 $stat = stat($path."/".$filename);
68 $new_mtime = @$pageinfo['versiondata']['mtime'];
70 $new_mtime = @$pageinfo['versiondata']['lastmodified'];
72 $new_mtime = @$pageinfo['pagedata']['date'];
74 $new_mtime = $stat[9];
75 if ($new_mtime > $page_mtime) {
76 echo "$path/$pagename: ",_("newer than the existing page."),
77 _(" replace "),"($new_mtime > $page_mtime)","<br />\n";
78 LoadAny($request,$path."/".$filename);
81 echo "$path/$pagename: ",_("older than the existing page."),
82 _(" skipped"),".<br />\n";
85 echo "$path/$pagename: ",("unknown format."),
86 _(" skipped"),".<br />\n";
89 echo sprintf(_("%s does not exist"),$pagename),"<br />\n";
90 LoadAny($request,$path."/".$filename);
95 /** Need the english filename (required precondition: urlencode == urldecode).
96 * Returns the plugin name.
98 function isActionPage($filename) {
99 static $special = array("DebugInfo" => "_BackendInfo",
100 "PhpWikiRecentChanges" => "RssFeed",
101 "ProjectSummary" => "RssFeed",
102 "RecentReleases" => "RssFeed",
103 "InterWikiMap" => "InterWikiMap",
105 $base = preg_replace("/\..{1,4}$/","",basename($filename));
106 if (isset($special[$base])) return $special[$base];
107 if (FindFile("lib/plugin/".$base.".php",true)) return $base;
111 function CheckActionPageUpdate(&$request) {
112 echo "<h3>",_("check for necessary ActionPage updates"),"</h3>\n";
113 $dbi = $request->getDbh();
114 $path = FindFile('pgsrc');
115 $pgsrc = new fileSet($path);
116 // most actionpages have the same name as the plugin
117 $loc_path = FindLocalizedFile('pgsrc');
118 foreach ($pgsrc->getFiles() as $filename) {
119 if (substr($filename,-1,1) == '~') continue;
120 $pagename = urldecode($filename);
121 if (isActionPage($filename)) {
122 $translation = gettext($pagename);
123 if ($translation == $pagename)
124 doPgsrcUpdate($request, $pagename, $path, $filename);
125 elseif (FindLocalizedFile('pgsrc/'.urlencode($translation),1))
126 doPgsrcUpdate($request, $translation, $loc_path,
127 urlencode($translation));
129 doPgsrcUpdate($request, $pagename, $path, $filename);
134 // see loadsave.php for saving new pages.
135 function CheckPgsrcUpdate(&$request) {
136 echo "<h3>",_("check for necessary pgsrc updates"),"</h3>\n";
137 $dbi = $request->getDbh();
138 $path = FindLocalizedFile(WIKI_PGSRC);
139 $pgsrc = new fileSet($path);
140 // fixme: verification, ...
142 foreach ($pgsrc->getFiles() as $filename) {
143 if (substr($filename,-1,1) == '~') continue;
144 $pagename = urldecode($filename);
145 // don't ever update the HomePage
146 if (defined(HOME_PAGE))
147 if ($pagename == HOME_PAGE) $isHomePage = true;
149 if ($pagename == _("HomePage")) $isHomePage = true;
150 if ($pagename == "HomePage") $isHomePage = true;
152 echo "$path/$pagename: ",_("always skip the HomePage."),
153 _(" skipped"),".<br />\n";
157 if (!isActionPage($filename)) {
158 doPgsrcUpdate($request,$pagename,$path,$filename);
165 * TODO: Search table definition in appropriate schema
167 * Supported: mysql and generic SQL, for ADODB and PearDB.
169 function installTable(&$dbh, $table, $backend_type) {
171 if (!in_array($DBParams['dbtype'],array('SQL','ADODB','PDO'))) return;
172 echo _("MISSING")," ... \n";
173 $backend = &$dbh->_backend->_dbh;
175 $schema = findFile("schemas/${backend_type}.sql");
177 echo " ",_("FAILED"),": ",sprintf(_("no schema %s found"),
178 "schemas/${backend_type}.sql")," ... <br />\n";
182 extract($dbh->_backend->_table_names);
183 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
186 assert($session_tbl);
187 if ($backend_type == 'mysql') {
188 $dbh->genericSqlQuery("
189 CREATE TABLE $session_tbl (
190 sess_id CHAR(32) NOT NULL DEFAULT '',
191 sess_data BLOB NOT NULL,
192 sess_date INT UNSIGNED NOT NULL,
193 sess_ip CHAR(15) NOT NULL,
194 PRIMARY KEY (sess_id),
198 $dbh->genericSqlQuery("
199 CREATE TABLE $session_tbl (
200 sess_id CHAR(32) NOT NULL DEFAULT '',
201 sess_data ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
203 sess_ip CHAR(15) NOT NULL
205 $dbh->genericSqlQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
207 $dbh->genericSqlQuery("CREATE INDEX sess_date on session (sess_date)");
208 echo " ",_("CREATED");
211 $user_tbl = $prefix.'user';
212 if ($backend_type == 'mysql') {
213 $dbh->genericSqlQuery("
214 CREATE TABLE $user_tbl (
215 userid CHAR(48) BINARY NOT NULL UNIQUE,
216 passwd CHAR(48) BINARY DEFAULT '',
220 $dbh->genericSqlQuery("
221 CREATE TABLE $user_tbl (
222 userid CHAR(48) NOT NULL,
223 passwd CHAR(48) DEFAULT ''
225 $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
227 echo " ",_("CREATED");
230 $pref_tbl = $prefix.'pref';
231 if ($backend_type == 'mysql') {
232 $dbh->genericSqlQuery("
233 CREATE TABLE $pref_tbl (
234 userid CHAR(48) BINARY NOT NULL UNIQUE,
235 prefs TEXT NULL DEFAULT '',
239 $dbh->genericSqlQuery("
240 CREATE TABLE $pref_tbl (
241 userid CHAR(48) NOT NULL,
242 prefs TEXT NULL DEFAULT '',
244 $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
246 echo " ",_("CREATED");
249 $member_tbl = $prefix.'member';
250 if ($backend_type == 'mysql') {
251 $dbh->genericSqlQuery("
252 CREATE TABLE $member_tbl (
253 userid CHAR(48) BINARY NOT NULL,
254 groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
259 $dbh->genericSqlQuery("
260 CREATE TABLE $member_tbl (
261 userid CHAR(48) NOT NULL,
262 groupname CHAR(48) NOT NULL DEFAULT 'users',
264 $dbh->genericSqlQuery("CREATE INDEX userid ON $member_tbl (userid)");
265 $dbh->genericSqlQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
267 echo " ",_("CREATED");
270 $rating_tbl = $prefix.'rating';
271 if ($backend_type == 'mysql') {
272 $dbh->genericSqlQuery("
273 CREATE TABLE $rating_tbl (
274 dimension INT(4) NOT NULL,
275 raterpage INT(11) NOT NULL,
276 rateepage INT(11) NOT NULL,
277 ratingvalue FLOAT NOT NULL,
278 rateeversion INT(11) NOT NULL,
279 tstamp TIMESTAMP(14) NOT NULL,
280 PRIMARY KEY (dimension, raterpage, rateepage)
283 $dbh->genericSqlQuery("
284 CREATE TABLE $rating_tbl (
285 dimension INT(4) NOT NULL,
286 raterpage INT(11) NOT NULL,
287 rateepage INT(11) NOT NULL,
288 ratingvalue FLOAT NOT NULL,
289 rateeversion INT(11) NOT NULL,
290 tstamp TIMESTAMP(14) NOT NULL,
292 $dbh->genericSqlQuery("CREATE UNIQUE INDEX rating"
293 ." ON $rating_tbl (dimension, raterpage, rateepage)");
295 echo " ",_("CREATED");
298 $log_tbl = $prefix.'accesslog';
299 // fields according to http://www.outoforder.cc/projects/apache/mod_log_sql/docs-2.0/#id2756178
301 A User Agent agent varchar(255) Mozilla/4.0 (compat; MSIE 6.0; Windows)
302 a CGi request arguments request_args varchar(255) user=Smith&cart=1231&item=532
303 b Bytes transfered bytes_sent int unsigned 32561
304 c??? Text of cookie cookie varchar(255) Apache=sdyn.fooonline.net 1300102700823
305 f Local filename requested request_file varchar(255) /var/www/html/books-cycroad.html
306 H HTTP request_protocol request_protocol varchar(10) HTTP/1.1
307 h Name of remote host remote_host varchar(50) blah.foobar.com
308 I Request ID (from modd_unique_id) id char(19) POlFcUBRH30AAALdBG8
309 l Ident user info remote_logname varcgar(50) bobby
310 M Machine ID??? machine_id varchar(25) web01
311 m HTTP request method request_method varchar(10) GET
312 P httpd cchild PID child_pid smallint unsigned 3215
313 p http port server_port smallint unsigned 80
314 R Referer referer varchar(255) http://www.biglinks4u.com/linkpage.html
315 r Request in full form request_line varchar(255) GET /books-cycroad.html HTTP/1.1
316 S Time of request in UNIX time_t format time_stamp int unsigned 1005598029
317 T Seconds to service request request_duration smallint unsigned 2
318 t Time of request in human format request_time char(28) [02/Dec/2001:15:01:26 -0800]
319 U Request in simple form request_uri varchar(255) /books-cycroad.html
320 u User info from HTTP auth remote_user varchar(50) bobby
321 v Virtual host servicing the request virtual_host varchar(255)
323 $dbh->genericSqlQuery("
324 CREATE TABLE $log_tbl (
325 time_stamp int unsigned,
326 remote_host varchar(50),
327 remote_user varchar(50),
328 request_method varchar(10),
329 request_line varchar(255),
330 request_args varchar(255),
331 request_uri varchar(255),
332 request_time char(28),
333 status smallint unsigned,
334 bytes_sent smallint unsigned,
335 referer varchar(255),
337 request_duration float
339 $dbh->genericSqlQuery("CREATE INDEX log_time ON $log_tbl (time_stamp)");
340 $dbh->genericSqlQuery("CREATE INDEX log_host ON $log_tbl (remote_host)");
341 echo " ",_("CREATED");
348 * Update from ~1.3.4 to current.
349 * Only session, user, pref and member
350 * jeffs-hacks database api (around 1.3.2) later:
351 * people should export/import their pages if using that old versions.
353 function CheckDatabaseUpdate(&$request) {
354 global $DBParams, $DBAuthParams;
355 if (!in_array($DBParams['dbtype'], array('SQL','ADODB','PDO'))) return;
356 echo "<h3>",_("check for necessary database updates"), " - ", $DBParams['dbtype'], "</h3>\n";
358 $dbh = $request->getDbh();
359 $dbadmin = $request->getArg('dbadmin');
360 _upgrade_db_init($dbh);
361 if (isset($dbadmin['cancel'])) {
362 echo _("CANCEL")," <br />\n";
366 $tables = $dbh->_backend->listOfTables();
367 $backend_type = $dbh->_backend->backendType();
368 echo "<h4>",_("Backend type: "),$backend_type,"</h4>\n";
369 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
370 foreach (explode(':','session:user:pref:member') as $table) {
371 echo sprintf(_("check for table %s"), $table)," ...";
372 if (!in_array($prefix.$table, $tables)) {
373 installTable($dbh, $table, $backend_type);
375 echo _("OK")," <br />\n";
378 if (ACCESS_LOG_SQL) {
379 $table = "accesslog";
380 echo sprintf(_("check for table %s"), $table)," ...";
381 if (!in_array($prefix.$table, $tables)) {
382 installTable($dbh, $table, $backend_type);
384 echo _("OK")," <br />\n";
387 if ((class_exists("RatingsUserFactory") or $dbh->isWikiPage(_("RateIt")))) {
389 echo sprintf(_("check for table %s"), $table)," ...";
390 if (!in_array($prefix.$table, $tables)) {
391 installTable($dbh, $table, $backend_type);
393 echo _("OK")," <br />\n";
396 $backend = &$dbh->_backend->_dbh;
397 extract($dbh->_backend->_table_names);
399 // 1.3.8 added session.sess_ip
400 if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
401 echo _("check for new session.sess_ip column")," ... ";
402 $database = $dbh->_backend->database();
403 assert(!empty($DBParams['db_session_table']));
404 $session_tbl = $prefix . $DBParams['db_session_table'];
405 $sess_fields = $dbh->_backend->listOfFields($database, $session_tbl);
406 if (!strstr(strtolower(join(':', $sess_fields)), "sess_ip")) {
407 // TODO: postgres test (should be able to add columns at the end, but not in between)
408 echo "<b>",_("ADDING"),"</b>"," ... ";
409 $dbh->genericSqlQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
410 $dbh->genericSqlQuery("CREATE INDEX sess_date ON $session_tbl (sess_date)");
415 if (substr($backend_type,0,5) == 'mysql') {
416 // upgrade to 4.1.8 destroyed my session table:
417 // sess_id => varchar(10), sess_data => varchar(5). For others obviously also.
418 echo _("check for mysql session.sess_id sanity")," ... ";
419 $result = $dbh->genericSqlQuery("DESCRIBE $session_tbl");
420 if ($DBParams['dbtype'] == 'SQL') {
421 $iter = new WikiDB_backend_PearDB_generic_iter($backend, $result);
422 } elseif ($DBParams['dbtype'] == 'ADODB') {
423 $iter = new WikiDB_backend_ADODB_generic_iter($backend, $result,
424 array("Field", "Type", "Null", "Key", "Default", "Extra"));
425 } elseif ($DBParams['dbtype'] == 'PDO') {
426 $iter = new WikiDB_backend_PDO_generic_iter($backend, $result);
428 while ($col = $iter->next()) {
429 if ($col["Field"] == 'sess_id' and !strstr(strtolower($col["Type"]), 'char(32)')) {
430 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_id"
431 ." sess_id CHAR(32) NOT NULL");
432 echo "sess_id ", $col["Type"], " ", _("fixed"), " => CHAR(32) ";
434 if ($col["Field"] == 'sess_ip' and !strstr(strtolower($col["Type"]), 'char(15)')) {
435 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_ip"
436 ." sess_ip CHAR(15) NOT NULL");
437 echo "sess_ip ", $col["Type"], " ", _("fixed"), " => CHAR(15) ";
440 echo _("OK"), "<br />\n";
444 // mysql >= 4.0.4 requires LOCK TABLE privileges
445 if (substr($backend_type,0,5) == 'mysql'/* and $DBParams['dbtype'] != 'PDO' */) {
446 echo _("check for mysql LOCK TABLE privilege")," ...";
447 $mysql_version = $dbh->_backend->_serverinfo['version'];
448 if ($mysql_version > 400.40) {
449 if (!empty($dbh->_backend->_parsedDSN))
450 $parseDSN = $dbh->_backend->_parsedDSN;
451 elseif (function_exists('parseDSN')) // ADODB or PDO
452 $parseDSN = parseDSN($DBParams['dsn']);
454 $parseDSN = DB::parseDSN($DBParams['dsn']);
455 $username = $dbh->_backend->qstr($parseDSN['username']);
457 $query = "SELECT lock_tables_priv FROM mysql.db WHERE user='$username'";
458 //mysql_select_db("mysql", $dbh->_backend->connection());
459 $db_fields = $dbh->_backend->listOfFields("mysql", "db");
460 if (!strstr(strtolower(join(':', $db_fields)), "lock_tables_priv")) {
461 echo join(':', $db_fields);
462 die("lock_tables_priv missing. The DB Admin must run mysql_fix_privilege_tables");
464 $row = $dbh->_backend->getRow($query);
465 if (isset($row[0]) and $row[0] == 'N') {
466 $dbh->genericSqlQuery("UPDATE mysql.db SET lock_tables_priv='Y'"
467 ." WHERE mysql.user='$username'");
468 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
469 echo "mysql.db user='$username'", _("fixed"), "<br />\n";
472 $query = "SELECT lock_tables_priv FROM mysql.user WHERE user='$username'";
473 $row = $dbh->_backend->getRow($query);
474 if ($row and $row[0] == 'N') {
475 $dbh->genericSqlQuery("UPDATE mysql.user SET lock_tables_priv='Y'"
476 ." WHERE mysql.user='$username'");
477 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
478 echo "mysql.user user='$username'", _("fixed"), "<br />\n";
480 echo " <b><font color=\"red\">", _("FAILED"), "</font></b>: ",
481 "Neither mysql.db nor mysql.user has a user='$username'"
482 ." or the lock_tables_priv field",
485 echo _("OK"), "<br />\n";
488 echo _("OK"), "<br />\n";
490 //mysql_select_db($dbh->_backend->database(), $dbh->_backend->connection());
492 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
496 // 1.3.10 mysql requires page.id auto_increment
497 // mysql, mysqli or mysqlt
498 if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql'
499 and $DBParams['dbtype'] != 'PDO') {
500 echo _("check for mysql page.id auto_increment flag")," ...";
501 assert(!empty($page_tbl));
502 $database = $dbh->_backend->database();
503 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
504 $columns = mysql_num_fields($fields);
505 for ($i = 0; $i < $columns; $i++) {
506 if (mysql_field_name($fields, $i) == 'id') {
507 $flags = mysql_field_flags($fields, $i);
508 //DONE: something was wrong with ADODB here.
509 if (!strstr(strtolower($flags), "auto_increment")) {
510 echo "<b>",_("ADDING"),"</b>"," ... ";
511 // MODIFY col_def valid since mysql 3.22.16,
512 // older mysql's need CHANGE old_col col_def
513 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE id"
514 ." id INT NOT NULL AUTO_INCREMENT");
515 $fields = mysql_list_fields($database, $page_tbl);
516 if (!strstr(strtolower(mysql_field_flags($fields, $i)), "auto_increment"))
517 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
519 echo _("OK"), "<br />\n";
521 echo _("OK"), "<br />\n";
526 mysql_free_result($fields);
529 // Check for mysql 4.1.x/5.0.0a binary search problem.
530 // http://bugs.mysql.com/bug.php?id=4398
531 // "select * from page where LOWER(pagename) like '%search%'" does not apply LOWER!
532 // Confirmed for 4.1.0alpha,4.1.3-beta,5.0.0a; not yet tested for 4.1.2alpha,
533 // On windows only, though utf8 would be useful elsewhere also.
534 // Illegal mix of collations (latin1_bin,IMPLICIT) and
535 // (utf8_general_ci, COERCIBLE) for operation '='])
536 if (isWindows() and substr($backend_type,0,5) == 'mysql') {
537 echo _("check for mysql 4.1.x/5.0.0 binary search on windows problem")," ...";
538 $mysql_version = $dbh->_backend->_serverinfo['version'];
539 if ($mysql_version < 401.0) {
540 echo sprintf(_("version <em>%s</em>"), $mysql_version)," ",
541 _("not affected"),"<br />\n";
542 } elseif ($mysql_version >= 401.6) { // FIXME: since which version?
543 $row = $dbh->_backend->getRow("SHOW CREATE TABLE $page_tbl");
544 $result = join(" ", $row);
545 if (strstr(strtolower($result), "character set")
546 and strstr(strtolower($result), "collate"))
548 echo _("OK"), "<br />\n";
550 //SET CHARACTER SET latin1
552 if ($charset == 'iso-8859-1') $charset = 'latin1';
553 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename "
554 ."pagename VARCHAR(100) "
555 ."CHARACTER SET '$charset' COLLATE '$charset"."_bin' NOT NULL");
556 echo sprintf(_("version <em>%s</em>"), $mysql_version),
557 " <b>",_("FIXED"),"</b>",
560 } elseif ($DBParams['dbtype'] != 'PDO') {
561 // check if already fixed
562 extract($dbh->_backend->_table_names);
563 assert(!empty($page_tbl));
564 $database = $dbh->_backend->database();
565 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
566 $columns = mysql_num_fields($fields);
567 for ($i = 0; $i < $columns; $i++) {
568 if (mysql_field_name($fields, $i) == 'pagename') {
569 $flags = mysql_field_flags($fields, $i);
570 // I think it was fixed with 4.1.6, but I tested it only with 4.1.8
571 if ($mysql_version > 401.0 and $mysql_version < 401.6) {
572 // remove the binary flag
573 if (strstr(strtolower($flags), "binary")) {
574 // FIXME: on duplicate pagenames this will fail!
575 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename"
576 ." pagename VARCHAR(100) NOT NULL");
577 echo sprintf(_("version <em>%s</em>"), $mysql_version),
578 "<b>",_("FIXED"),"</b>"
587 if ((ACCESS_LOG_SQL & 2)) {
588 echo _("check for ACCESS_LOG_SQL passwords in POST requests")," ...";
589 // Don't display passwords in POST requests (up to 2005-02-04 12:03:20)
590 $result = $dbh->genericSqlQuery(
591 "UPDATE ".$prefix."accesslog"
592 .' SET request_args=CONCAT(left(request_args, LOCATE("s:6:\"passwd\"",request_args)+12),"...")'
593 .' WHERE LOCATE("s:6:\"passwd\"", request_args)'
594 .' AND NOT(LOCATE("s:6:\"passwd\";s:15:\"<not displayed>\"", request_args))'
595 .' AND request_method="POST"');
596 if ((DATABASE_TYPE == 'SQL' and $backend->AffectedRows())
597 or (DATABASE_TYPE == 'ADODB' and $backend->Affected_Rows())
598 or (DATABASE_TYPE == 'PDO' and $result))
599 echo "<b>",_("FIXED"),"</b>", "<br />\n";
601 echo _("OK"),"<br />\n";
603 _upgrade_cached_html($dbh);
608 function _upgrade_db_init (&$dbh) {
609 global $request, $DBParams, $DBAuthParams;
610 if (!in_array($DBParams['dbtype'], array('SQL','ADODB','PDO'))) return;
613 // if need to connect as the root user, for CREATE and ALTER privileges
614 $AdminParams = $DBParams;
615 if ($DBParams['dbtype'] == 'SQL')
616 $dsn = DB::parseDSN($AdminParams['dsn']);
618 $dsn = parseDSN($AdminParams['dsn']);
619 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
625 if (DEBUG & _DEBUG_SQL and $DBParams['dbtype'] == 'PDO') {
626 echo "<br>\nDBParams['dsn']: '", $DBParams['dsn'], "'";
627 echo "<br>\ndsn: '", print_r($dsn), "'";
628 echo "<br>\nAdminParams['dsn']: '", $AdminParams['dsn'], "'";
630 $dbh = WikiDB::open($AdminParams);
631 } elseif ($dbadmin = $request->getArg('dbadmin')) {
632 if (empty($dbadmin['user']) or isset($dbadmin['cancel']))
633 $dbh = &$request->_dbi;
635 $AdminParams = $DBParams;
636 if ($DBParams['dbtype'] == 'SQL')
637 $dsn = DB::parseDSN($AdminParams['dsn']);
639 $dsn = parseDSN($AdminParams['dsn']);
640 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
646 $dbh = WikiDB::open($AdminParams);
649 // Check if the privileges are enough. Need CREATE and ALTER perms.
650 // And on windows: SELECT FROM mysql, possibly: UPDATE mysql.
651 $form = HTML::form(array("method" => "post",
652 "action" => $request->getPostURL(),
653 "accept-charset"=>$GLOBALS['charset']),
654 HTML::p(_("Upgrade requires database privileges to CREATE and ALTER the phpwiki database."),
656 _("And on windows at least the privilege to SELECT FROM mysql, and possibly UPDATE mysql")),
657 HiddenInputs(array('action' => 'upgrade')),
658 HTML::table(array("cellspacing"=>4),
659 HTML::tr(HTML::td(array('align'=>'right'),
660 _("DB admin user:")),
661 HTML::td(HTML::input(array('name'=>"dbadmin[user]",
665 HTML::tr(HTML::td(array('align'=>'right'),
666 _("DB admin password:")),
667 HTML::td(HTML::input(array('name'=>"dbadmin[passwd]",
670 'maxlength'=>256)))),
671 HTML::tr(HTML::td(array('align'=>'center', 'colspan' => 2),
672 Button("submit:", _("Submit"), 'wikiaction'),
674 Button("submit:dbadmin[cancel]", _("Cancel"),
677 echo "</div><!-- content -->\n";
678 echo asXML(Template("bottom"));
679 echo "</body></html>\n";
686 * if page.cached_html does not exists:
687 * put _cached_html from pagedata into a new seperate blob, not huge serialized string.
689 * it is only rarelely needed: for current page only, if-not-modified
690 * but was extracetd for every simple page iteration.
692 function _upgrade_cached_html (&$dbh, $verbose=true) {
694 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
696 if (phpwiki_version() >= 1030.10) {
698 echo _("check for extra page.cached_html column")," ... ";
699 $database = $dbh->_backend->database();
700 extract($dbh->_backend->_table_names);
701 $fields = $dbh->_backend->listOfFields($database, $page_tbl);
702 if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
704 echo "<b>",_("ADDING"),"</b>"," ... ";
705 $backend_type = $dbh->_backend->backendType();
706 if (substr($backend_type,0,5) == 'mysql')
707 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
709 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
711 echo "<b>",_("CONVERTING"),"</b>"," ... ";
712 $count = _convert_cached_html($dbh);
714 echo $count, " ", _("OK"), "<br />\n";
717 echo _("OK"), "<br />\n";
724 * move _cached_html for all pages from pagedata into a new seperate blob.
725 * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
727 function _convert_cached_html (&$dbh) {
729 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
731 $pages = $dbh->getAllPages();
732 $cache =& $dbh->_cache;
734 extract($dbh->_backend->_table_names);
735 while ($page = $pages->next()) {
736 $pagename = $page->getName();
737 $data = $dbh->_backend->get_pagedata($pagename);
738 if (!empty($data['_cached_html'])) {
739 $cached_html = $data['_cached_html'];
740 $data['_cached_html'] = '';
741 $cache->update_pagedata($pagename, $data);
742 // store as blob, not serialized
743 $dbh->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
744 array($cached_html, $pagename));
751 function CheckPluginUpdate(&$request) {
752 echo "<h3>",_("check for necessary plugin argument updates"),"</h3>\n";
753 $process = array('msg' => _("change RandomPage pages => numpages"),
754 'match' => "/(<\?\s*plugin\s+ RandomPage\s+)pages/",
755 'replace' => "\\1numpages");
756 $dbi = $request->getDbh();
757 $allpages = $dbi->getAllPages(false);
758 while ($page = $allpages->next()) {
759 $current = $page->getCurrentRevision();
760 $pagetext = $current->getPackedContent();
761 foreach ($process as $p) {
762 if (preg_match($p['match'], $pagetext)) {
763 echo $page->getName()," ",$p['msg']," ... ";
764 if ($newtext = preg_replace($p['match'], $p['replace'], $pagetext)) {
765 $meta = $current->_data;
766 $meta['summary'] = "upgrade: ".$p['msg'];
767 $page->save($newtext, $current->getVersion() + 1, $meta);
768 echo _("OK"), "<br />\n";
770 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
777 function fixConfigIni($match, $new) {
778 $file = FindFile("config/config.ini");
780 if (is_writable($file)) {
781 $in = fopen($file,"rb");
782 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
784 $tmp = str_replace("/","\\",$tmp);
785 while ($s = fgets($in)) {
786 if (preg_match($match, $s)) {
787 $s = $new . (isWindows() ? "\r\n" : "\n");
795 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
796 sprintf(_("%s not found"), $match);
799 @unlink("$file.bak");
800 @rename($file,"$file.bak");
801 if (rename($tmp, $file))
802 echo " <b>",_("FIXED"),"</b>";
804 echo " <b>",_("FAILED"),"</b>: ";
805 sprintf(_("couldn't move %s to %s"), $tmp, $file);
811 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
812 sprintf(_("%s is not writable"), $file);
817 function CheckConfigUpdate(&$request) {
818 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
819 echo _("check for old CACHE_CONTROL = NONE")," ... ";
820 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
821 echo "<br /> ",
822 _("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'"),
824 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
829 echo _("check for GROUP_METHOD = NONE")," ... ";
830 if (defined('GROUP_METHOD') and GROUP_METHOD == '') {
831 echo "<br /> ",
832 _("GROUP_METHOD is set to NONE, and must be changed to \"NONE\""),
834 fixConfigIni("/^\s*GROUP_METHOD\s*=\s*NONE/","GROUP_METHOD = \"NONE\"");
844 * Upgrade: Base class for multipage worksteps
845 * identify, validate, display options, next step
851 class Upgrade_CheckPgsrc extends Upgrade {
854 class Upgrade_CheckDatabaseUpdate extends Upgrade {
858 // TODO: At which step are we?
859 // validate and do it again or go on with next step.
861 /** entry function from lib/main.php
863 function DoUpgrade($request) {
865 if (!$request->_user->isAdmin()) {
866 $request->_notAuthorized(WIKIAUTH_ADMIN);
868 HTML::div(array('class' => 'disabled-plugin'),
869 fmt("Upgrade disabled: user != isAdmin")));
873 StartLoadDump($request, _("Upgrading this PhpWiki"));
874 //CheckOldIndexUpdate($request); // to upgrade from < 1.3.10
875 CheckDatabaseUpdate($request); // first check cached_html and friends
876 CheckActionPageUpdate($request);
877 CheckPgsrcUpdate($request);
878 //CheckThemeUpdate($request);
879 //CheckPluginUpdate($request);
880 CheckConfigUpdate($request);
881 EndLoadDump($request);
886 $Log: not supported by cvs2svn $
887 Revision 1.46 2005/02/12 17:22:18 rurban
888 locale update: missing . : fixed. unified strings
891 Revision 1.45 2005/02/10 19:01:19 rurban
894 Revision 1.44 2005/02/07 15:40:42 rurban
895 use defined CHARSET for db. more comments
897 Revision 1.43 2005/02/04 11:44:07 rurban
898 check passwd in access_log
900 Revision 1.42 2005/02/02 19:38:13 rurban
901 prefer utf8 pagenames for collate issues
903 Revision 1.41 2005/01/31 12:15:29 rurban
906 Revision 1.40 2005/01/30 23:22:17 rurban
909 Revision 1.39 2005/01/30 23:09:17 rurban
910 sanify session fields
912 Revision 1.38 2005/01/25 07:57:02 rurban
913 add dbadmin form, add mysql LOCK TABLES check, add plugin args updater (not yet activated)
915 Revision 1.37 2005/01/20 10:19:08 rurban
916 add InterWikiMap to special pages
918 Revision 1.36 2004/12/20 12:56:11 rurban
919 patch #1088128 by Kai Krakow. avoid chicken & egg problem
921 Revision 1.35 2004/12/13 14:35:41 rurban
924 Revision 1.34 2004/12/11 09:39:28 rurban
927 Revision 1.33 2004/12/10 22:33:39 rurban
928 add WikiAdminUtils method for convert-cached-html
931 Revision 1.32 2004/12/10 22:15:00 rurban
932 fix $page->get('_cached_html)
933 refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
934 support 2nd genericSqlQuery param (bind huge arg)
936 Revision 1.31 2004/12/10 02:45:26 rurban
938 put _cached_html from pagedata into a new seperate blob, not huge serialized string.
939 it is only rarelely needed: for current page only, if-not-modified
940 but was extracted for every simple page iteration.
942 Revision 1.30 2004/11/29 17:58:57 rurban
945 Revision 1.29 2004/11/29 16:08:31 rurban
948 Revision 1.28 2004/11/16 16:25:14 rurban
949 fix accesslog tablename, print CREATED only if really done
951 Revision 1.27 2004/11/07 16:02:52 rurban
952 new sql access log (for spam prevention), and restructured access log class
954 pear_db: mysql specific parts seperated (using replace)
956 Revision 1.26 2004/10/14 19:19:34 rurban
957 loadsave: check if the dumped file will be accessible from outside.
958 and some other minor fixes. (cvsclient native not yet ready)
960 Revision 1.25 2004/09/06 08:28:00 rurban
961 rename genericQuery to genericSqlQuery
963 Revision 1.24 2004/07/05 13:56:22 rurban
964 sqlite autoincrement fix
966 Revision 1.23 2004/07/04 10:28:06 rurban
969 Revision 1.22 2004/07/03 17:21:28 rurban
970 updated docs: submitted new mysql bugreport (#1491 did not fix it)
972 Revision 1.21 2004/07/03 16:51:05 rurban
973 optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
974 added atomic mysql REPLACE for PearDB as in ADODB
975 fixed _lock_tables typo links => link
976 fixes unserialize ADODB bug in line 180
978 Revision 1.20 2004/07/03 14:48:18 rurban
979 Tested new mysql 4.1.3-beta: binary search bug as fixed.
980 => fixed action=upgrade,
981 => version check in PearDB also (as in ADODB)
983 Revision 1.19 2004/06/19 12:19:09 rurban
984 slightly improved docs
986 Revision 1.18 2004/06/19 11:47:17 rurban
987 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
989 Revision 1.17 2004/06/17 11:31:50 rurban
990 check necessary localized actionpages
992 Revision 1.16 2004/06/16 10:38:58 rurban
993 Disallow refernces in calls if the declaration is a reference
994 ("allow_call_time_pass_reference clean").
995 PhpWiki is now allow_call_time_pass_reference = Off clean,
996 but several external libraries may not.
997 In detail these libs look to be affected (not tested):
1001 Revision 1.15 2004/06/07 19:50:40 rurban
1002 add owner field to mimified dump
1004 Revision 1.14 2004/06/07 18:38:18 rurban
1005 added mysql 4.1.x search fix
1007 Revision 1.13 2004/06/04 20:32:53 rurban
1008 Several locale related improvements suggested by Pierrick Meignen
1009 LDAP fix by John Cole
1010 reanable admin check without ENABLE_PAGEPERM in the admin plugins
1012 Revision 1.12 2004/05/18 13:59:15 rurban
1013 rename simpleQuery to genericSqlQuery
1015 Revision 1.11 2004/05/15 13:06:17 rurban
1016 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
1018 Revision 1.10 2004/05/15 01:19:41 rurban
1019 upgrade prefix fix by Kai Krakow
1021 Revision 1.9 2004/05/14 11:33:03 rurban
1022 version updated to 1.3.11pre
1023 upgrade stability fix
1025 Revision 1.8 2004/05/12 10:49:55 rurban
1026 require_once fix for those libs which are loaded before FileFinder and
1027 its automatic include_path fix, and where require_once doesn't grok
1028 dirname(__FILE__) != './lib'
1029 upgrade fix with PearDB
1030 navbar.tmpl: remove spaces for IE button alignment
1032 Revision 1.7 2004/05/06 17:30:38 rurban
1033 CategoryGroup: oops, dos2unix eol
1034 improved phpwiki_version:
1035 pre -= .0001 (1.3.10pre: 1030.099)
1036 -p1 += .001 (1.3.9-p1: 1030.091)
1037 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
1038 abstracted more ADODB/PearDB methods for action=upgrade stuff:
1039 backend->backendType(), backend->database(),
1040 backend->listOfFields(),
1041 backend->listOfTables(),
1043 Revision 1.6 2004/05/03 15:05:36 rurban
1046 Revision 1.4 2004/05/02 21:26:38 rurban
1047 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1048 because they will not survive db sessions, if too large.
1049 extended action=upgrade
1050 some WikiTranslation button work
1051 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1052 some temp. session debug statements
1054 Revision 1.3 2004/04/29 22:33:30 rurban
1055 fixed sf.net bug #943366 (Kai Krakow)
1056 couldn't load localized url-undecoded pagenames
1058 Revision 1.2 2004/03/12 15:48:07 rurban
1059 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
1060 simplified lib/stdlib.php:explodePageList
1068 // c-basic-offset: 4
1069 // c-hanging-comment-ender-p: nil
1070 // indent-tabs-mode: nil