2 rcs_id('$Id: upgrade.php,v 1.46 2005-02-12 17:22:18 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
551 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename "
552 ."pagename VARCHAR(100) CHARACTER SET ".CHARSET
553 ." COLLATE ".CHARSET."_bin NOT NULL");
554 echo sprintf(_("version <em>%s</em>"), $mysql_version),
555 "<b>",_("FIXED"),"</b>",
558 } elseif ($DBParams['dbtype'] != 'PDO') {
559 // check if already fixed
560 extract($dbh->_backend->_table_names);
561 assert(!empty($page_tbl));
562 $database = $dbh->_backend->database();
563 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
564 $columns = mysql_num_fields($fields);
565 for ($i = 0; $i < $columns; $i++) {
566 if (mysql_field_name($fields, $i) == 'pagename') {
567 $flags = mysql_field_flags($fields, $i);
568 // I think it was fixed with 4.1.6, but I tested it only with 4.1.8
569 if ($mysql_version > 401.0 and $mysql_version < 401.6) {
570 // remove the binary flag
571 if (strstr(strtolower($flags), "binary")) {
572 // FIXME: on duplicate pagenames this will fail!
573 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename"
574 ." pagename VARCHAR(100) NOT NULL");
575 echo sprintf(_("version <em>%s</em>"), $mysql_version),
576 "<b>",_("FIXED"),"</b>"
585 if ((ACCESS_LOG_SQL & 2)) {
586 echo _("check for ACCESS_LOG_SQL passwords in POST requests")," ...";
587 // Don't display passwords in POST requests (up to 2005-02-04 12:03:20)
588 $result = $dbh->genericSqlQuery(
589 "UPDATE ".$prefix."accesslog"
590 .' SET request_args=CONCAT(left(request_args, LOCATE("s:6:\"passwd\"",request_args)+12),"...")'
591 .' WHERE LOCATE("s:6:\"passwd\"", request_args)'
592 .' AND NOT(LOCATE("s:6:\"passwd\";s:15:\"<not displayed>\"", request_args))'
593 .' AND request_method="POST"');
594 if ((DATABASE_TYPE == 'SQL' and $backend->AffectedRows())
595 or (DATABASE_TYPE == 'ADODB' and $backend->Affected_Rows())
596 or (DATABASE_TYPE == 'PDO' and $result))
597 echo "<b>",_("FIXED"),"</b>", "<br />\n";
599 echo _("OK"),"<br />\n";
601 _upgrade_cached_html($dbh);
606 function _upgrade_db_init (&$dbh) {
607 global $request, $DBParams, $DBAuthParams;
608 if (!in_array($DBParams['dbtype'], array('SQL','ADODB','PDO'))) return;
611 // if need to connect as the root user, for CREATE and ALTER privileges
612 $AdminParams = $DBParams;
613 if ($DBParams['dbtype'] == 'SQL')
614 $dsn = DB::parseDSN($AdminParams['dsn']);
616 $dsn = parseDSN($AdminParams['dsn']);
617 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
623 if (DEBUG & _DEBUG_SQL and $DBParams['dbtype'] == 'PDO') {
624 echo "<br>\nDBParams['dsn']: '", $DBParams['dsn'], "'";
625 echo "<br>\ndsn: '", print_r($dsn), "'";
626 echo "<br>\nAdminParams['dsn']: '", $AdminParams['dsn'], "'";
628 $dbh = WikiDB::open($AdminParams);
629 } elseif ($dbadmin = $request->getArg('dbadmin')) {
630 if (empty($dbadmin['user']) or isset($dbadmin['cancel']))
631 $dbh = &$request->_dbi;
633 $AdminParams = $DBParams;
634 if ($DBParams['dbtype'] == 'SQL')
635 $dsn = DB::parseDSN($AdminParams['dsn']);
637 $dsn = parseDSN($AdminParams['dsn']);
638 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
644 $dbh = WikiDB::open($AdminParams);
647 // Check if the privileges are enough. Need CREATE and ALTER perms.
648 // And on windows: SELECT FROM mysql, possibly: UPDATE mysql.
649 $form = HTML::form(array("method" => "post",
650 "action" => $request->getPostURL(),
651 "accept-charset"=>$GLOBALS['charset']),
652 HTML::p(_("Upgrade requires database privileges to CREATE and ALTER the phpwiki database."),
654 _("And on windows at least the privilege to SELECT FROM mysql, and possibly UPDATE mysql")),
655 HiddenInputs(array('action' => 'upgrade')),
656 HTML::table(array("cellspacing"=>4),
657 HTML::tr(HTML::td(array('align'=>'right'),
658 _("DB admin user:")),
659 HTML::td(HTML::input(array('name'=>"dbadmin[user]",
663 HTML::tr(HTML::td(array('align'=>'right'),
664 _("DB admin password:")),
665 HTML::td(HTML::input(array('name'=>"dbadmin[passwd]",
668 'maxlength'=>256)))),
669 HTML::tr(HTML::td(array('align'=>'center', 'colspan' => 2),
670 Button("submit:", _("Submit"), 'wikiaction'),
672 Button("submit:dbadmin[cancel]", _("Cancel"),
675 echo "</div><!-- content -->\n";
676 echo asXML(Template("bottom"));
677 echo "</body></html>\n";
684 * if page.cached_html does not exists:
685 * put _cached_html from pagedata into a new seperate blob, not huge serialized string.
687 * it is only rarelely needed: for current page only, if-not-modified
688 * but was extracetd for every simple page iteration.
690 function _upgrade_cached_html (&$dbh, $verbose=true) {
692 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
694 if (phpwiki_version() >= 1030.10) {
696 echo _("check for extra page.cached_html column")," ... ";
697 $database = $dbh->_backend->database();
698 extract($dbh->_backend->_table_names);
699 $fields = $dbh->_backend->listOfFields($database, $page_tbl);
700 if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
702 echo "<b>",_("ADDING"),"</b>"," ... ";
703 $backend_type = $dbh->_backend->backendType();
704 if (substr($backend_type,0,5) == 'mysql')
705 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
707 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
709 echo "<b>",_("CONVERTING"),"</b>"," ... ";
710 $count = _convert_cached_html($dbh);
712 echo $count, " ", _("OK"), "<br />\n";
715 echo _("OK"), "<br />\n";
722 * move _cached_html for all pages from pagedata into a new seperate blob.
723 * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
725 function _convert_cached_html (&$dbh) {
727 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
729 $pages = $dbh->getAllPages();
730 $cache =& $dbh->_cache;
732 extract($dbh->_backend->_table_names);
733 while ($page = $pages->next()) {
734 $pagename = $page->getName();
735 $data = $dbh->_backend->get_pagedata($pagename);
736 if (!empty($data['_cached_html'])) {
737 $cached_html = $data['_cached_html'];
738 $data['_cached_html'] = '';
739 $cache->update_pagedata($pagename, $data);
740 // store as blob, not serialized
741 $dbh->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
742 array($cached_html, $pagename));
749 function CheckPluginUpdate(&$request) {
750 echo "<h3>",_("check for necessary plugin argument updates"),"</h3>\n";
751 $process = array('msg' => _("change RandomPage pages => numpages"),
752 'match' => "/(<\?\s*plugin\s+ RandomPage\s+)pages/",
753 'replace' => "\\1numpages");
754 $dbi = $request->getDbh();
755 $allpages = $dbi->getAllPages(false);
756 while ($page = $allpages->next()) {
757 $current = $page->getCurrentRevision();
758 $pagetext = $current->getPackedContent();
759 foreach ($process as $p) {
760 if (preg_match($p['match'], $pagetext)) {
761 echo $page->getName()," ",$p['msg']," ... ";
762 if ($newtext = preg_replace($p['match'], $p['replace'], $pagetext)) {
763 $meta = $current->_data;
764 $meta['summary'] = "upgrade: ".$p['msg'];
765 $page->save($newtext, $current->getVersion() + 1, $meta);
766 echo _("OK"), "<br />\n";
768 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
775 function fixConfigIni($match, $new) {
776 $file = FindFile("config/config.ini");
778 if (is_writable($file)) {
779 $in = fopen($file,"rb");
780 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
782 $tmp = str_replace("/","\\",$tmp);
783 while ($s = fgets($in)) {
784 if (preg_match($match, $s)) {
785 $s = $new . (isWindows() ? "\r\n" : "\n");
793 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
794 sprintf(_("%s not found"), $match);
797 @unlink("$file.bak");
798 @rename($file,"$file.bak");
799 if (rename($tmp, $file))
800 echo " <b>",_("FIXED"),"</b>";
802 echo " <b>",_("FAILED"),"</b>: ";
803 sprintf(_("couldn't move %s to %s"), $tmp, $file);
809 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
810 sprintf(_("%s is not writable"), $file);
815 function CheckConfigUpdate(&$request) {
816 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
817 echo _("check for old CACHE_CONTROL = NONE")," ... ";
818 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
819 echo "<br /> ",
820 _("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'"),
822 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
827 echo _("check for GROUP_METHOD = NONE")," ... ";
828 if (defined('GROUP_METHOD') and GROUP_METHOD == '') {
829 echo "<br /> ",
830 _("GROUP_METHOD is set to NONE, and must be changed to \"NONE\""),
832 fixConfigIni("/^\s*GROUP_METHOD\s*=\s*NONE/","GROUP_METHOD = \"NONE\"");
842 * Upgrade: Base class for multipage worksteps
843 * identify, validate, display options, next step
849 class Upgrade_CheckPgsrc extends Upgrade {
852 class Upgrade_CheckDatabaseUpdate extends Upgrade {
856 // TODO: At which step are we?
857 // validate and do it again or go on with next step.
859 /** entry function from lib/main.php
861 function DoUpgrade($request) {
863 if (!$request->_user->isAdmin()) {
864 $request->_notAuthorized(WIKIAUTH_ADMIN);
866 HTML::div(array('class' => 'disabled-plugin'),
867 fmt("Upgrade disabled: user != isAdmin")));
871 StartLoadDump($request, _("Upgrading this PhpWiki"));
872 //CheckOldIndexUpdate($request); // to upgrade from < 1.3.10
873 CheckDatabaseUpdate($request); // first check cached_html and friends
874 CheckActionPageUpdate($request);
875 CheckPgsrcUpdate($request);
876 //CheckThemeUpdate($request);
877 //CheckPluginUpdate($request);
878 CheckConfigUpdate($request);
879 EndLoadDump($request);
884 $Log: not supported by cvs2svn $
885 Revision 1.45 2005/02/10 19:01:19 rurban
888 Revision 1.44 2005/02/07 15:40:42 rurban
889 use defined CHARSET for db. more comments
891 Revision 1.43 2005/02/04 11:44:07 rurban
892 check passwd in access_log
894 Revision 1.42 2005/02/02 19:38:13 rurban
895 prefer utf8 pagenames for collate issues
897 Revision 1.41 2005/01/31 12:15:29 rurban
900 Revision 1.40 2005/01/30 23:22:17 rurban
903 Revision 1.39 2005/01/30 23:09:17 rurban
904 sanify session fields
906 Revision 1.38 2005/01/25 07:57:02 rurban
907 add dbadmin form, add mysql LOCK TABLES check, add plugin args updater (not yet activated)
909 Revision 1.37 2005/01/20 10:19:08 rurban
910 add InterWikiMap to special pages
912 Revision 1.36 2004/12/20 12:56:11 rurban
913 patch #1088128 by Kai Krakow. avoid chicken & egg problem
915 Revision 1.35 2004/12/13 14:35:41 rurban
918 Revision 1.34 2004/12/11 09:39:28 rurban
921 Revision 1.33 2004/12/10 22:33:39 rurban
922 add WikiAdminUtils method for convert-cached-html
925 Revision 1.32 2004/12/10 22:15:00 rurban
926 fix $page->get('_cached_html)
927 refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
928 support 2nd genericSqlQuery param (bind huge arg)
930 Revision 1.31 2004/12/10 02:45:26 rurban
932 put _cached_html from pagedata into a new seperate blob, not huge serialized string.
933 it is only rarelely needed: for current page only, if-not-modified
934 but was extracted for every simple page iteration.
936 Revision 1.30 2004/11/29 17:58:57 rurban
939 Revision 1.29 2004/11/29 16:08:31 rurban
942 Revision 1.28 2004/11/16 16:25:14 rurban
943 fix accesslog tablename, print CREATED only if really done
945 Revision 1.27 2004/11/07 16:02:52 rurban
946 new sql access log (for spam prevention), and restructured access log class
948 pear_db: mysql specific parts seperated (using replace)
950 Revision 1.26 2004/10/14 19:19:34 rurban
951 loadsave: check if the dumped file will be accessible from outside.
952 and some other minor fixes. (cvsclient native not yet ready)
954 Revision 1.25 2004/09/06 08:28:00 rurban
955 rename genericQuery to genericSqlQuery
957 Revision 1.24 2004/07/05 13:56:22 rurban
958 sqlite autoincrement fix
960 Revision 1.23 2004/07/04 10:28:06 rurban
963 Revision 1.22 2004/07/03 17:21:28 rurban
964 updated docs: submitted new mysql bugreport (#1491 did not fix it)
966 Revision 1.21 2004/07/03 16:51:05 rurban
967 optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
968 added atomic mysql REPLACE for PearDB as in ADODB
969 fixed _lock_tables typo links => link
970 fixes unserialize ADODB bug in line 180
972 Revision 1.20 2004/07/03 14:48:18 rurban
973 Tested new mysql 4.1.3-beta: binary search bug as fixed.
974 => fixed action=upgrade,
975 => version check in PearDB also (as in ADODB)
977 Revision 1.19 2004/06/19 12:19:09 rurban
978 slightly improved docs
980 Revision 1.18 2004/06/19 11:47:17 rurban
981 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
983 Revision 1.17 2004/06/17 11:31:50 rurban
984 check necessary localized actionpages
986 Revision 1.16 2004/06/16 10:38:58 rurban
987 Disallow refernces in calls if the declaration is a reference
988 ("allow_call_time_pass_reference clean").
989 PhpWiki is now allow_call_time_pass_reference = Off clean,
990 but several external libraries may not.
991 In detail these libs look to be affected (not tested):
995 Revision 1.15 2004/06/07 19:50:40 rurban
996 add owner field to mimified dump
998 Revision 1.14 2004/06/07 18:38:18 rurban
999 added mysql 4.1.x search fix
1001 Revision 1.13 2004/06/04 20:32:53 rurban
1002 Several locale related improvements suggested by Pierrick Meignen
1003 LDAP fix by John Cole
1004 reanable admin check without ENABLE_PAGEPERM in the admin plugins
1006 Revision 1.12 2004/05/18 13:59:15 rurban
1007 rename simpleQuery to genericSqlQuery
1009 Revision 1.11 2004/05/15 13:06:17 rurban
1010 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
1012 Revision 1.10 2004/05/15 01:19:41 rurban
1013 upgrade prefix fix by Kai Krakow
1015 Revision 1.9 2004/05/14 11:33:03 rurban
1016 version updated to 1.3.11pre
1017 upgrade stability fix
1019 Revision 1.8 2004/05/12 10:49:55 rurban
1020 require_once fix for those libs which are loaded before FileFinder and
1021 its automatic include_path fix, and where require_once doesn't grok
1022 dirname(__FILE__) != './lib'
1023 upgrade fix with PearDB
1024 navbar.tmpl: remove spaces for IE button alignment
1026 Revision 1.7 2004/05/06 17:30:38 rurban
1027 CategoryGroup: oops, dos2unix eol
1028 improved phpwiki_version:
1029 pre -= .0001 (1.3.10pre: 1030.099)
1030 -p1 += .001 (1.3.9-p1: 1030.091)
1031 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
1032 abstracted more ADODB/PearDB methods for action=upgrade stuff:
1033 backend->backendType(), backend->database(),
1034 backend->listOfFields(),
1035 backend->listOfTables(),
1037 Revision 1.6 2004/05/03 15:05:36 rurban
1040 Revision 1.4 2004/05/02 21:26:38 rurban
1041 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1042 because they will not survive db sessions, if too large.
1043 extended action=upgrade
1044 some WikiTranslation button work
1045 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1046 some temp. session debug statements
1048 Revision 1.3 2004/04/29 22:33:30 rurban
1049 fixed sf.net bug #943366 (Kai Krakow)
1050 couldn't load localized url-undecoded pagenames
1052 Revision 1.2 2004/03/12 15:48:07 rurban
1053 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
1054 simplified lib/stdlib.php:explodePageList
1062 // c-basic-offset: 4
1063 // c-hanging-comment-ender-p: nil
1064 // indent-tabs-mode: nil