2 rcs_id('$Id: upgrade.php,v 1.50 2006-06-18 11:04:09 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 (!$dbh->_backend->isSQL()) 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 $DBAuthParams;
355 $dbh = $request->getDbh();
356 if (!$dbh->_backend->isSQL()) return;
357 echo "<h3>",_("check for necessary database updates"), " - ", DATABASE_TYPE, "</h3>\n";
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: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);
408 } elseif (!strstr(strtolower(join(':', $sess_fields)), "sess_ip")) {
409 // TODO: postgres test (should be able to add columns at the end, but not in between)
410 echo "<b>",_("ADDING"),"</b>"," ... ";
411 $dbh->genericSqlQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
412 $dbh->genericSqlQuery("CREATE INDEX sess_date ON $session_tbl (sess_date)");
417 if (substr($backend_type,0,5) == 'mysql') {
418 // upgrade to 4.1.8 destroyed my session table:
419 // sess_id => varchar(10), sess_data => varchar(5). For others obviously also.
420 echo _("check for mysql session.sess_id sanity")," ... ";
421 $result = $dbh->genericSqlQuery("DESCRIBE $session_tbl");
422 if (DATABASE_TYPE == 'SQL') {
423 $iter = new WikiDB_backend_PearDB_generic_iter($backend, $result);
424 } elseif (DATABASE_TYPE == 'ADODB') {
425 $iter = new WikiDB_backend_ADODB_generic_iter($backend, $result,
426 array("Field", "Type", "Null", "Key", "Default", "Extra"));
427 } elseif (DATABASE_TYPE == 'PDO') {
428 $iter = new WikiDB_backend_PDO_generic_iter($backend, $result);
430 while ($col = $iter->next()) {
431 if ($col["Field"] == 'sess_id' and !strstr(strtolower($col["Type"]), 'char(32)')) {
432 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_id"
433 ." sess_id CHAR(32) NOT NULL");
434 echo "sess_id ", $col["Type"], " ", _("fixed"), " => CHAR(32) ";
436 if ($col["Field"] == 'sess_ip' and !strstr(strtolower($col["Type"]), 'char(15)')) {
437 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_ip"
438 ." sess_ip CHAR(15) NOT NULL");
439 echo "sess_ip ", $col["Type"], " ", _("fixed"), " => CHAR(15) ";
442 echo _("OK"), "<br />\n";
447 ALTER TABLE link ADD relation INT DEFAULT 0;
448 CREATE INDEX linkrelation ON link (relation);
451 // mysql >= 4.0.4 requires LOCK TABLE privileges
452 if (0 and substr($backend_type,0,5) == 'mysql') {
453 echo _("check for mysql LOCK TABLE privilege")," ...";
454 $mysql_version = $dbh->_backend->_serverinfo['version'];
455 if ($mysql_version > 400.40) {
456 if (!empty($dbh->_backend->_parsedDSN))
457 $parseDSN = $dbh->_backend->_parsedDSN;
458 elseif (function_exists('parseDSN')) // ADODB or PDO
459 $parseDSN = parseDSN($DBParams['dsn']);
461 $parseDSN = DB::parseDSN($DBParams['dsn']);
462 $username = $dbh->_backend->qstr($parseDSN['username']);
464 $query = "SELECT lock_tables_priv FROM mysql.db WHERE user='$username'";
465 //mysql_select_db("mysql", $dbh->_backend->connection());
466 $db_fields = $dbh->_backend->listOfFields("mysql", "db");
467 if (!strstr(strtolower(join(':', $db_fields)), "lock_tables_priv")) {
468 echo join(':', $db_fields);
469 die("lock_tables_priv missing. The DB Admin must run mysql_fix_privilege_tables");
471 $row = $dbh->_backend->getRow($query);
472 if (isset($row[0]) and $row[0] == 'N') {
473 $dbh->genericSqlQuery("UPDATE mysql.db SET lock_tables_priv='Y'"
474 ." WHERE mysql.user='$username'");
475 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
476 echo "mysql.db user='$username'", _("fixed"), "<br />\n";
479 $query = "SELECT lock_tables_priv FROM mysql.user WHERE user='$username'";
480 $row = $dbh->_backend->getRow($query);
481 if ($row and $row[0] == 'N') {
482 $dbh->genericSqlQuery("UPDATE mysql.user SET lock_tables_priv='Y'"
483 ." WHERE mysql.user='$username'");
484 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
485 echo "mysql.user user='$username'", _("fixed"), "<br />\n";
487 echo " <b><font color=\"red\">", _("FAILED"), "</font></b>: ",
488 "Neither mysql.db nor mysql.user has a user='$username'"
489 ." or the lock_tables_priv field",
492 echo _("OK"), "<br />\n";
495 echo _("OK"), "<br />\n";
497 //mysql_select_db($dbh->_backend->database(), $dbh->_backend->connection());
499 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
503 // 1.3.10 mysql requires page.id auto_increment
504 // mysql, mysqli or mysqlt
505 if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql'
506 and DATABASE_TYPE != 'PDO') {
507 echo _("check for mysql page.id auto_increment flag")," ...";
508 assert(!empty($page_tbl));
509 $database = $dbh->_backend->database();
510 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
511 $columns = mysql_num_fields($fields);
512 for ($i = 0; $i < $columns; $i++) {
513 if (mysql_field_name($fields, $i) == 'id') {
514 $flags = mysql_field_flags($fields, $i);
515 //DONE: something was wrong with ADODB here.
516 if (!strstr(strtolower($flags), "auto_increment")) {
517 echo "<b>",_("ADDING"),"</b>"," ... ";
518 // MODIFY col_def valid since mysql 3.22.16,
519 // older mysql's need CHANGE old_col col_def
520 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE id"
521 ." id INT NOT NULL AUTO_INCREMENT");
522 $fields = mysql_list_fields($database, $page_tbl);
523 if (!strstr(strtolower(mysql_field_flags($fields, $i)), "auto_increment"))
524 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
526 echo _("OK"), "<br />\n";
528 echo _("OK"), "<br />\n";
533 mysql_free_result($fields);
536 // Check for mysql 4.1.x/5.0.0a binary search problem.
537 // http://bugs.mysql.com/bug.php?id=4398
538 // "select * from page where LOWER(pagename) like '%search%'" does not apply LOWER!
539 // Confirmed for 4.1.0alpha,4.1.3-beta,5.0.0a; not yet tested for 4.1.2alpha,
540 // On windows only, though utf8 would be useful elsewhere also.
541 // Illegal mix of collations (latin1_bin,IMPLICIT) and
542 // (utf8_general_ci, COERCIBLE) for operation '='])
543 if (isWindows() and substr($backend_type,0,5) == 'mysql') {
544 echo _("check for mysql 4.1.x/5.0.0 binary search on windows problem")," ...";
545 $mysql_version = $dbh->_backend->_serverinfo['version'];
546 if ($mysql_version < 401.0) {
547 echo sprintf(_("version <em>%s</em>"), $mysql_version)," ",
548 _("not affected"),"<br />\n";
549 } elseif ($mysql_version >= 401.6) { // FIXME: since which version?
550 $row = $dbh->_backend->getRow("SHOW CREATE TABLE $page_tbl");
551 $result = join(" ", $row);
552 if (strstr(strtolower($result), "character set")
553 and strstr(strtolower($result), "collate"))
555 echo _("OK"), "<br />\n";
557 //SET CHARACTER SET latin1
559 if ($charset == 'iso-8859-1') $charset = 'latin1';
560 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename "
561 ."pagename VARCHAR(100) "
562 ."CHARACTER SET '$charset' COLLATE '$charset"."_bin' NOT NULL");
563 echo sprintf(_("version <em>%s</em>"), $mysql_version),
564 " <b>",_("FIXED"),"</b>",
567 } elseif (DATABASE_TYPE != 'PDO') {
568 // check if already fixed
569 extract($dbh->_backend->_table_names);
570 assert(!empty($page_tbl));
571 $database = $dbh->_backend->database();
572 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
573 $columns = mysql_num_fields($fields);
574 for ($i = 0; $i < $columns; $i++) {
575 if (mysql_field_name($fields, $i) == 'pagename') {
576 $flags = mysql_field_flags($fields, $i);
577 // I think it was fixed with 4.1.6, but I tested it only with 4.1.8
578 if ($mysql_version > 401.0 and $mysql_version < 401.6) {
579 // remove the binary flag
580 if (strstr(strtolower($flags), "binary")) {
581 // FIXME: on duplicate pagenames this will fail!
582 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename"
583 ." pagename VARCHAR(100) NOT NULL");
584 echo sprintf(_("version <em>%s</em>"), $mysql_version),
585 "<b>",_("FIXED"),"</b>"
594 if ((ACCESS_LOG_SQL & 2)) {
595 echo _("check for ACCESS_LOG_SQL passwords in POST requests")," ...";
596 // Don't display passwords in POST requests (up to 2005-02-04 12:03:20)
597 $result = $dbh->genericSqlQuery(
598 "UPDATE ".$prefix."accesslog"
599 .' SET request_args=CONCAT(left(request_args, LOCATE("s:6:\"passwd\"",request_args)+12),"...")'
600 .' WHERE LOCATE("s:6:\"passwd\"", request_args)'
601 .' AND NOT(LOCATE("s:6:\"passwd\";s:15:\"<not displayed>\"", request_args))'
602 .' AND request_method="POST"');
603 if ((DATABASE_TYPE == 'SQL' and $backend->AffectedRows())
604 or (DATABASE_TYPE == 'ADODB' and $backend->Affected_Rows())
605 or (DATABASE_TYPE == 'PDO' and $result))
606 echo "<b>",_("FIXED"),"</b>", "<br />\n";
608 echo _("OK"),"<br />\n";
610 _upgrade_cached_html($dbh);
615 function _upgrade_db_init (&$dbh) {
616 global $request, $DBParams, $DBAuthParams;
617 if (!$dbh->_backend->isSQL()) return;
620 // if need to connect as the root user, for CREATE and ALTER privileges
621 $AdminParams = $DBParams;
622 if (DATABASE_TYPE == 'SQL')
623 $dsn = DB::parseDSN($AdminParams['dsn']);
625 $dsn = parseDSN($AdminParams['dsn']);
626 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
632 if (DEBUG & _DEBUG_SQL and DATABASE_TYPE == 'PDO') {
633 echo "<br>\nDBParams['dsn']: '", $DBParams['dsn'], "'";
634 echo "<br>\ndsn: '", print_r($dsn), "'";
635 echo "<br>\nAdminParams['dsn']: '", $AdminParams['dsn'], "'";
637 $dbh = WikiDB::open($AdminParams);
638 } elseif ($dbadmin = $request->getArg('dbadmin')) {
639 if (empty($dbadmin['user']) or isset($dbadmin['cancel']))
640 $dbh = &$request->_dbi;
642 $AdminParams = $DBParams;
643 if (DATABASE_TYPE == 'SQL')
644 $dsn = DB::parseDSN($AdminParams['dsn']);
646 $dsn = parseDSN($AdminParams['dsn']);
647 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
653 $dbh = WikiDB::open($AdminParams);
656 // Check if the privileges are enough. Need CREATE and ALTER perms.
657 // And on windows: SELECT FROM mysql, possibly: UPDATE mysql.
658 $form = HTML::form(array("method" => "post",
659 "action" => $request->getPostURL(),
660 "accept-charset"=>$GLOBALS['charset']),
661 HTML::p(_("Upgrade requires database privileges to CREATE and ALTER the phpwiki database."),
663 _("And on windows at least the privilege to SELECT FROM mysql, and possibly UPDATE mysql")),
664 HiddenInputs(array('action' => 'upgrade',
665 'overwrite' => $request->getArg('overwrite'))),
666 HTML::table(array("cellspacing"=>4),
667 HTML::tr(HTML::td(array('align'=>'right'),
668 _("DB admin user:")),
669 HTML::td(HTML::input(array('name'=>"dbadmin[user]",
673 HTML::tr(HTML::td(array('align'=>'right'),
674 _("DB admin password:")),
675 HTML::td(HTML::input(array('name'=>"dbadmin[passwd]",
678 'maxlength'=>256)))),
679 HTML::tr(HTML::td(array('align'=>'center', 'colspan' => 2),
680 Button("submit:", _("Submit"), 'wikiaction'),
682 Button("submit:dbadmin[cancel]", _("Cancel"),
685 echo "</div><!-- content -->\n";
686 echo asXML(Template("bottom"));
687 echo "</body></html>\n";
694 * if page.cached_html does not exists:
695 * put _cached_html from pagedata into a new seperate blob, not huge serialized string.
697 * it is only rarelely needed: for current page only, if-not-modified
698 * but was extracetd for every simple page iteration.
700 function _upgrade_cached_html (&$dbh, $verbose=true) {
702 if (!$dbh->_backend->isSQL()) return;
703 //if (!in_array(DATABASE_TYPE, array('SQL','ADODB','PDO'))) return;
705 if (phpwiki_version() >= 1030.10) {
707 echo _("check for extra page.cached_html column")," ... ";
708 $database = $dbh->_backend->database();
709 extract($dbh->_backend->_table_names);
710 $fields = $dbh->_backend->listOfFields($database, $page_tbl);
712 echo _("SKIP"), "<br />\n";
715 if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
717 echo "<b>",_("ADDING"),"</b>"," ... ";
718 $backend_type = $dbh->_backend->backendType();
719 if (substr($backend_type,0,5) == 'mysql')
720 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
722 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
724 echo "<b>",_("CONVERTING"),"</b>"," ... ";
725 $count = _convert_cached_html($dbh);
727 echo $count, " ", _("OK"), "<br />\n";
730 echo _("OK"), "<br />\n";
737 * move _cached_html for all pages from pagedata into a new seperate blob.
738 * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
740 function _convert_cached_html (&$dbh) {
742 if (!$dbh->_backend->isSQL()) return;
743 //if (!in_array(DATABASE_TYPE, array('SQL','ADODB'))) return;
745 $pages = $dbh->getAllPages();
746 $cache =& $dbh->_cache;
748 extract($dbh->_backend->_table_names);
749 while ($page = $pages->next()) {
750 $pagename = $page->getName();
751 $data = $dbh->_backend->get_pagedata($pagename);
752 if (!empty($data['_cached_html'])) {
753 $cached_html = $data['_cached_html'];
754 $data['_cached_html'] = '';
755 $cache->update_pagedata($pagename, $data);
756 // store as blob, not serialized
757 $dbh->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
758 array($cached_html, $pagename));
765 function CheckPluginUpdate(&$request) {
766 echo "<h3>",_("check for necessary plugin argument updates"),"</h3>\n";
767 $process = array('msg' => _("change RandomPage pages => numpages"),
768 'match' => "/(<\?\s*plugin\s+ RandomPage\s+)pages/",
769 'replace' => "\\1numpages");
770 $dbi = $request->getDbh();
771 $allpages = $dbi->getAllPages(false);
772 while ($page = $allpages->next()) {
773 $current = $page->getCurrentRevision();
774 $pagetext = $current->getPackedContent();
775 foreach ($process as $p) {
776 if (preg_match($p['match'], $pagetext)) {
777 echo $page->getName()," ",$p['msg']," ... ";
778 if ($newtext = preg_replace($p['match'], $p['replace'], $pagetext)) {
779 $meta = $current->_data;
780 $meta['summary'] = "upgrade: ".$p['msg'];
781 $page->save($newtext, $current->getVersion() + 1, $meta);
782 echo _("OK"), "<br />\n";
784 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
791 function fixConfigIni($match, $new) {
792 $file = FindFile("config/config.ini");
794 if (is_writable($file)) {
795 $in = fopen($file,"rb");
796 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
798 $tmp = str_replace("/","\\",$tmp);
799 while ($s = fgets($in)) {
800 if (preg_match($match, $s)) {
801 $s = $new . (isWindows() ? "\r\n" : "\n");
809 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
810 sprintf(_("%s not found"), $match);
813 @unlink("$file.bak");
814 @rename($file,"$file.bak");
815 if (rename($tmp, $file))
816 echo " <b>",_("FIXED"),"</b>";
818 echo " <b>",_("FAILED"),"</b>: ";
819 sprintf(_("couldn't move %s to %s"), $tmp, $file);
825 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
826 sprintf(_("%s is not writable"), $file);
831 function CheckConfigUpdate(&$request) {
832 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
833 echo _("check for old CACHE_CONTROL = NONE")," ... ";
834 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
835 echo "<br /> ",
836 _("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'"),
838 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
843 echo _("check for GROUP_METHOD = NONE")," ... ";
844 if (defined('GROUP_METHOD') and GROUP_METHOD == '') {
845 echo "<br /> ",
846 _("GROUP_METHOD is set to NONE, and must be changed to \"NONE\""),
848 fixConfigIni("/^\s*GROUP_METHOD\s*=\s*NONE/","GROUP_METHOD = \"NONE\"");
858 * Upgrade: Base class for multipage worksteps
859 * identify, validate, display options, next step
865 class Upgrade_CheckPgsrc extends Upgrade {
868 class Upgrade_CheckDatabaseUpdate extends Upgrade {
872 // TODO: At which step are we?
873 // validate and do it again or go on with next step.
875 /** entry function from lib/main.php
877 function DoUpgrade($request) {
879 if (!$request->_user->isAdmin()) {
880 $request->_notAuthorized(WIKIAUTH_ADMIN);
882 HTML::div(array('class' => 'disabled-plugin'),
883 fmt("Upgrade disabled: user != isAdmin")));
887 StartLoadDump($request, _("Upgrading this PhpWiki"));
888 //CheckOldIndexUpdate($request); // to upgrade from < 1.3.10
889 CheckDatabaseUpdate($request); // first check cached_html and friends
890 CheckActionPageUpdate($request);
891 CheckPgsrcUpdate($request);
892 //CheckThemeUpdate($request);
893 //CheckPluginUpdate($request);
894 CheckConfigUpdate($request);
895 EndLoadDump($request);
900 $Log: not supported by cvs2svn $
901 Revision 1.49 2006/05/18 06:03:39 rurban
902 use $dbh->_backend->isSQL
904 Revision 1.48 2005/11/14 22:32:38 rurban
905 remove user, SKIP on !session
907 Revision 1.47 2005/02/27 19:13:27 rurban
910 Revision 1.46 2005/02/12 17:22:18 rurban
911 locale update: missing . : fixed. unified strings
914 Revision 1.45 2005/02/10 19:01:19 rurban
917 Revision 1.44 2005/02/07 15:40:42 rurban
918 use defined CHARSET for db. more comments
920 Revision 1.43 2005/02/04 11:44:07 rurban
921 check passwd in access_log
923 Revision 1.42 2005/02/02 19:38:13 rurban
924 prefer utf8 pagenames for collate issues
926 Revision 1.41 2005/01/31 12:15:29 rurban
929 Revision 1.40 2005/01/30 23:22:17 rurban
932 Revision 1.39 2005/01/30 23:09:17 rurban
933 sanify session fields
935 Revision 1.38 2005/01/25 07:57:02 rurban
936 add dbadmin form, add mysql LOCK TABLES check, add plugin args updater (not yet activated)
938 Revision 1.37 2005/01/20 10:19:08 rurban
939 add InterWikiMap to special pages
941 Revision 1.36 2004/12/20 12:56:11 rurban
942 patch #1088128 by Kai Krakow. avoid chicken & egg problem
944 Revision 1.35 2004/12/13 14:35:41 rurban
947 Revision 1.34 2004/12/11 09:39:28 rurban
950 Revision 1.33 2004/12/10 22:33:39 rurban
951 add WikiAdminUtils method for convert-cached-html
954 Revision 1.32 2004/12/10 22:15:00 rurban
955 fix $page->get('_cached_html)
956 refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
957 support 2nd genericSqlQuery param (bind huge arg)
959 Revision 1.31 2004/12/10 02:45:26 rurban
961 put _cached_html from pagedata into a new seperate blob, not huge serialized string.
962 it is only rarelely needed: for current page only, if-not-modified
963 but was extracted for every simple page iteration.
965 Revision 1.30 2004/11/29 17:58:57 rurban
968 Revision 1.29 2004/11/29 16:08:31 rurban
971 Revision 1.28 2004/11/16 16:25:14 rurban
972 fix accesslog tablename, print CREATED only if really done
974 Revision 1.27 2004/11/07 16:02:52 rurban
975 new sql access log (for spam prevention), and restructured access log class
977 pear_db: mysql specific parts seperated (using replace)
979 Revision 1.26 2004/10/14 19:19:34 rurban
980 loadsave: check if the dumped file will be accessible from outside.
981 and some other minor fixes. (cvsclient native not yet ready)
983 Revision 1.25 2004/09/06 08:28:00 rurban
984 rename genericQuery to genericSqlQuery
986 Revision 1.24 2004/07/05 13:56:22 rurban
987 sqlite autoincrement fix
989 Revision 1.23 2004/07/04 10:28:06 rurban
992 Revision 1.22 2004/07/03 17:21:28 rurban
993 updated docs: submitted new mysql bugreport (#1491 did not fix it)
995 Revision 1.21 2004/07/03 16:51:05 rurban
996 optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
997 added atomic mysql REPLACE for PearDB as in ADODB
998 fixed _lock_tables typo links => link
999 fixes unserialize ADODB bug in line 180
1001 Revision 1.20 2004/07/03 14:48:18 rurban
1002 Tested new mysql 4.1.3-beta: binary search bug as fixed.
1003 => fixed action=upgrade,
1004 => version check in PearDB also (as in ADODB)
1006 Revision 1.19 2004/06/19 12:19:09 rurban
1007 slightly improved docs
1009 Revision 1.18 2004/06/19 11:47:17 rurban
1010 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
1012 Revision 1.17 2004/06/17 11:31:50 rurban
1013 check necessary localized actionpages
1015 Revision 1.16 2004/06/16 10:38:58 rurban
1016 Disallow refernces in calls if the declaration is a reference
1017 ("allow_call_time_pass_reference clean").
1018 PhpWiki is now allow_call_time_pass_reference = Off clean,
1019 but several external libraries may not.
1020 In detail these libs look to be affected (not tested):
1024 Revision 1.15 2004/06/07 19:50:40 rurban
1025 add owner field to mimified dump
1027 Revision 1.14 2004/06/07 18:38:18 rurban
1028 added mysql 4.1.x search fix
1030 Revision 1.13 2004/06/04 20:32:53 rurban
1031 Several locale related improvements suggested by Pierrick Meignen
1032 LDAP fix by John Cole
1033 reanable admin check without ENABLE_PAGEPERM in the admin plugins
1035 Revision 1.12 2004/05/18 13:59:15 rurban
1036 rename simpleQuery to genericSqlQuery
1038 Revision 1.11 2004/05/15 13:06:17 rurban
1039 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
1041 Revision 1.10 2004/05/15 01:19:41 rurban
1042 upgrade prefix fix by Kai Krakow
1044 Revision 1.9 2004/05/14 11:33:03 rurban
1045 version updated to 1.3.11pre
1046 upgrade stability fix
1048 Revision 1.8 2004/05/12 10:49:55 rurban
1049 require_once fix for those libs which are loaded before FileFinder and
1050 its automatic include_path fix, and where require_once doesn't grok
1051 dirname(__FILE__) != './lib'
1052 upgrade fix with PearDB
1053 navbar.tmpl: remove spaces for IE button alignment
1055 Revision 1.7 2004/05/06 17:30:38 rurban
1056 CategoryGroup: oops, dos2unix eol
1057 improved phpwiki_version:
1058 pre -= .0001 (1.3.10pre: 1030.099)
1059 -p1 += .001 (1.3.9-p1: 1030.091)
1060 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
1061 abstracted more ADODB/PearDB methods for action=upgrade stuff:
1062 backend->backendType(), backend->database(),
1063 backend->listOfFields(),
1064 backend->listOfTables(),
1066 Revision 1.6 2004/05/03 15:05:36 rurban
1069 Revision 1.4 2004/05/02 21:26:38 rurban
1070 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1071 because they will not survive db sessions, if too large.
1072 extended action=upgrade
1073 some WikiTranslation button work
1074 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1075 some temp. session debug statements
1077 Revision 1.3 2004/04/29 22:33:30 rurban
1078 fixed sf.net bug #943366 (Kai Krakow)
1079 couldn't load localized url-undecoded pagenames
1081 Revision 1.2 2004/03/12 15:48:07 rurban
1082 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
1083 simplified lib/stdlib.php:explodePageList
1091 // c-basic-offset: 4
1092 // c-hanging-comment-ender-p: nil
1093 // indent-tabs-mode: nil