4 * Copyright 2004,2005,2006,2007 $ThePhpWikiProgrammingTeam
5 * Copyright 2008 Marc-Etienne Vargenau, Alcatel-Lucent
7 * This file is part of PhpWiki.
9 * PhpWiki is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * PhpWiki is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * Upgrade existing WikiDB and config settings after installing a new PhpWiki sofwtare version.
26 * Status: almost no queries for verification.
27 * simple merge conflict resolution, or Overwrite All.
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. (for newer changes since 1.3.11, not yet)
40 * 3a. Convert old-style index.php into config/config.ini. (easy, not yet)
41 * 4. Check for changed plugin invocation arguments. (medium, done)
42 * 5. Check for changed theme variables. (hard, not yet)
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';
55 function Upgrade(&$request)
57 $this->request =& $request;
58 $this->dbi =& $request->_dbi; // no reference for dbadmin ?
59 $this->phpwiki_version = $this->current_db_version = phpwiki_version();
60 //$this->current_db_version = 1030.13; // should be stored in the db. should be phpwiki_version
62 $this->db_version = $this->dbi->get_db_version();
63 $this->isSQL = $this->dbi->_backend->isSQL();
66 function doPgsrcUpdate($pagename, $path, $filename)
68 // don't ever update the HomePage
69 if ((defined(HOME_PAGE) and ($pagename == HOME_PAGE))
70 or ($pagename == _("HomePage"))
71 or ($pagename == "HomePage")
73 echo "$path/$pagename: " . _("always skip the HomePage.") . " " . _("Skipped."), "<br />\n";
77 $page = $this->dbi->getPage($pagename);
78 if ($page->exists()) {
79 // check mtime: update automatically if pgsrc is newer
80 $rev = $page->getCurrentRevision();
81 $page_mtime = $rev->get('mtime');
82 $data = implode("", file($path . "/" . $filename));
83 if (($parts = ParseMimeifiedPages($data))) {
84 usort($parts, 'SortByPageVersion');
86 $pageinfo = $parts[0];
87 $stat = stat($path . "/" . $filename);
89 if (isset($pageinfo['versiondata']['mtime']))
90 $new_mtime = $pageinfo['versiondata']['mtime'];
91 if (!$new_mtime and isset($pageinfo['versiondata']['lastmodified']))
92 $new_mtime = $pageinfo['versiondata']['lastmodified'];
93 if (!$new_mtime and isset($pageinfo['pagedata']['date']))
94 $new_mtime = $pageinfo['pagedata']['date'];
96 $new_mtime = $stat[9];
97 if ($new_mtime > $page_mtime) {
98 echo "$path/$pagename" . _(": ") . _("newer than the existing page.")
99 . " " . _("Replace") . " " . "($new_mtime > $page_mtime)" . "<br />\n";
100 LoadAny($this->request, $path . "/" . $filename);
103 echo "$path/$pagename" . _(": ") . _("older than the existing page.")
104 . " " . _("Skipped."), "<br />\n";
107 echo "$path/$pagename" . _(": ") . _("unknown format.") . " " . _("Skipped.") . "<br />\n";
110 echo sprintf(_("%s does not exist"), $pagename), "<br />\n";
111 LoadAny($this->request, $path . "/" . $filename);
116 function CheckActionPageUpdate()
118 echo "<h2>", sprintf(_("Check for necessary %s updates"), _("ActionPage")), "</h2>\n";
119 // 1.3.13 before we pull in all missing pages, we rename existing ones
120 $this->_rename_page_helper("_AuthInfo", "DebugAuthInfo");
121 $this->_rename_page_helper("Help/_AuthInfoPlugin", "Help/DebugAuthInfoPlugin");
122 $this->_rename_page_helper("_GroupInfo", "DebugGroupInfo");
123 $this->_rename_page_helper("Help/_GroupInfoPlugin", "Help/DebugGroupInfoPlugin");
124 $this->_rename_page_helper("_BackendInfo", "DebugBackendInfo");
125 $this->_rename_page_helper("Help/_BackendInfoPlugin", "Help/DebugBackendInfoPlugin");
126 $this->_rename_page_helper("Help/_WikiTranslationPlugin", "Help/WikiTranslationPlugin");
127 $this->_rename_page_helper("Help/Advice Mediawiki users", "Help/Advice for Mediawiki users");
128 // this is in some templates. so we keep the old name
129 //$this->_rename_page_helper($this->dbi, _("DebugInfo"), _("DebugBackendInfo"));
130 $this->_rename_page_helper("_GroupInfo", "GroupAuthInfo"); //never officially existed
131 $this->_rename_page_helper("InterWikiKarte", "InterWikiListe"); // german only
133 $path = FindFile('pgsrc');
134 $pgsrc = new fileSet($path);
135 // most actionpages have the same name as the plugin
136 $loc_path = FindLocalizedFile('pgsrc');
137 foreach ($pgsrc->getFiles() as $filename) {
138 if (substr($filename, -1, 1) == '~') continue;
139 if (substr($filename, -5, 5) == '.orig') continue;
140 $pagename = urldecode($filename);
141 if (isActionPage($pagename)) {
142 $translation = gettext($pagename);
143 if ($translation == $pagename)
144 $this->doPgsrcUpdate($pagename, $path, $filename);
145 elseif (FindLocalizedFile('pgsrc/' . urlencode($translation), 1))
146 $this->doPgsrcUpdate($translation, $loc_path, urlencode($translation)); else
147 $this->doPgsrcUpdate($pagename, $path, $filename);
152 // see loadsave.php for saving new pages.
153 function CheckPgsrcUpdate()
155 // Check some theme specific pgsrc files (blog, wikilens, fusionforge, custom).
156 // We check theme specific pgsrc first in case the page is present in both
157 // theme specific and global pgsrc
159 $path = $WikiTheme->file("pgsrc");
160 // TBD: the call to fileSet prints a warning:
161 // Notice: Unable to open directory 'themes/MonoBook/pgsrc' for reading
162 $pgsrc = new fileSet($path);
163 if ($pgsrc->getFiles()) {
164 echo "<h2>", sprintf(_("Check for necessary theme %s updates"),
166 foreach ($pgsrc->getFiles() as $filename) {
167 if (substr($filename, -1, 1) == '~') continue;
168 if (substr($filename, -5, 5) == '.orig') continue;
169 $pagename = urldecode($filename);
170 $this->doPgsrcUpdate($pagename, $path, $filename);
174 echo "<h2>", sprintf(_("Check for necessary %s updates"),
176 if ($this->db_version < 1030.12200612) {
177 echo "<h4>", _("rename to Help: pages"), "</h4>\n";
179 $path = FindLocalizedFile(WIKI_PGSRC);
180 $pgsrc = new fileSet($path);
181 // fixme: verification, ...
182 foreach ($pgsrc->getFiles() as $filename) {
183 if (substr($filename, -1, 1) == '~') continue;
184 if (substr($filename, -5, 5) == '.orig') continue;
185 $pagename = urldecode($filename);
186 if (!isActionPage($filename)) {
187 // There're a lot of now unneeded pages around.
188 // At first rename the BlaPlugin pages to Help/<pagename> and then to the update.
189 if ($this->db_version < 1030.12200612) {
190 $this->_rename_to_help_page($pagename);
192 $this->doPgsrcUpdate($pagename, $path, $filename);
197 function _rename_page_helper($oldname, $pagename)
199 echo sprintf(_("rename %s to %s"), $oldname, $pagename), " ...";
200 if ($this->dbi->isWikiPage($oldname) and !$this->dbi->isWikiPage($pagename)) {
201 if ($this->dbi->_backend->rename_page($oldname, $pagename)) {
202 echo _("OK"), " <br />\n";
204 echo ' <span style="color: red; font-weight: bold;">' . _("FAILED") . "</span><br />\n";
207 echo " " . _("Skipped.") . "<br />\n";
211 function _rename_to_help_page($pagename)
213 $newprefix = _("Help") . "/";
214 if (substr($pagename, 0, strlen($newprefix)) != $newprefix) return;
215 $oldname = substr($pagename, strlen($newprefix));
216 $this->_rename_page_helper($oldname, $pagename);
220 * TODO: Search table definition in appropriate schema
222 * Supported: mysql and generic SQL, for ADODB and PearDB.
224 function installTable($table, $backend_type)
227 if (!$this->isSQL) return;
228 echo _("MISSING"), " ... \n";
229 $backend = &$this->dbi->_backend->_dbh;
231 $schema = findFile("schemas/${backend_type}.sql");
233 echo " ",_("FAILED"),": ",sprintf(_("no schema %s found"),
234 "schemas/${backend_type}.sql")," ... <br />\n";
238 extract($this->dbi->_backend->_table_names);
239 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
242 assert($session_tbl);
243 if ($backend_type == 'mysql') {
244 $this->dbi->genericSqlQuery("
245 CREATE TABLE $session_tbl (
246 sess_id CHAR(32) NOT NULL DEFAULT '',
247 sess_data BLOB NOT NULL,
248 sess_date INT UNSIGNED NOT NULL,
249 sess_ip CHAR(15) NOT NULL,
250 PRIMARY KEY (sess_id),
254 $this->dbi->genericSqlQuery("
255 CREATE TABLE $session_tbl (
256 sess_id CHAR(32) NOT NULL DEFAULT '',
257 sess_data " . ($backend_type == 'pgsql' ? 'TEXT' : 'BLOB') . " NOT NULL,
259 sess_ip CHAR(15) NOT NULL
261 $this->dbi->genericSqlQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
263 $this->dbi->genericSqlQuery("CREATE INDEX sess_date on session (sess_date)");
264 echo " ", _("CREATED");
267 $pref_tbl = $prefix . 'pref';
268 if ($backend_type == 'mysql') {
269 $this->dbi->genericSqlQuery("
270 CREATE TABLE $pref_tbl (
271 userid CHAR(48) BINARY NOT NULL UNIQUE,
272 prefs TEXT NULL DEFAULT '',
276 $this->dbi->genericSqlQuery("
277 CREATE TABLE $pref_tbl (
278 userid CHAR(48) NOT NULL,
279 prefs TEXT NULL DEFAULT ''
281 $this->dbi->genericSqlQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
283 echo " ", _("CREATED");
286 $member_tbl = $prefix . 'member';
287 if ($backend_type == 'mysql') {
288 $this->dbi->genericSqlQuery("
289 CREATE TABLE $member_tbl (
290 userid CHAR(48) BINARY NOT NULL,
291 groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
296 $this->dbi->genericSqlQuery("
297 CREATE TABLE $member_tbl (
298 userid CHAR(48) NOT NULL,
299 groupname CHAR(48) NOT NULL DEFAULT 'users'
301 $this->dbi->genericSqlQuery("CREATE INDEX userid ON $member_tbl (userid)");
302 $this->dbi->genericSqlQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
304 echo " ", _("CREATED");
307 $rating_tbl = $prefix . 'rating';
308 if ($backend_type == 'mysql') {
309 $this->dbi->genericSqlQuery("
310 CREATE TABLE $rating_tbl (
311 dimension INT(4) NOT NULL,
312 raterpage INT(11) NOT NULL,
313 rateepage INT(11) NOT NULL,
314 ratingvalue FLOAT NOT NULL,
315 rateeversion INT(11) NOT NULL,
316 tstamp TIMESTAMP(14) NOT NULL,
317 PRIMARY KEY (dimension, raterpage, rateepage)
320 $this->dbi->genericSqlQuery("
321 CREATE TABLE $rating_tbl (
322 dimension INT(4) NOT NULL,
323 raterpage INT(11) NOT NULL,
324 rateepage INT(11) NOT NULL,
325 ratingvalue FLOAT NOT NULL,
326 rateeversion INT(11) NOT NULL,
327 tstamp TIMESTAMP(14) NOT NULL
329 $this->dbi->genericSqlQuery("CREATE UNIQUE INDEX rating"
330 . " ON $rating_tbl (dimension, raterpage, rateepage)");
332 echo " ", _("CREATED");
335 $log_tbl = $prefix . 'accesslog';
336 // fields according to http://www.outoforder.cc/projects/apache/mod_log_sql/docs-2.0/#id2756178
338 A User Agent agent varchar(255) Mozilla/4.0 (compat; MSIE 6.0; Windows)
339 a CGi request arguments request_args varchar(255) user=Smith&cart=1231&item=532
340 b Bytes transfered bytes_sent int unsigned 32561
341 c??? Text of cookie cookie varchar(255) Apache=sdyn.fooonline.net 1300102700823
342 f Local filename requested request_file varchar(255) /var/www/html/books-cycroad.html
343 H HTTP request_protocol request_protocol varchar(10) HTTP/1.1
344 h Name of remote host remote_host varchar(50) blah.foobar.com
345 I Request ID (from modd_unique_id) id char(19) POlFcUBRH30AAALdBG8
346 l Ident user info remote_logname varcgar(50) bobby
347 M Machine ID??? machine_id varchar(25) web01
348 m HTTP request method request_method varchar(10) GET
349 P httpd cchild PID child_pid smallint unsigned 3215
350 p http port server_port smallint unsigned 80
351 R Referer referer varchar(255) http://www.biglinks4u.com/linkpage.html
352 r Request in full form request_line varchar(255) GET /books-cycroad.html HTTP/1.1
353 S Time of request in UNIX time_t format time_stamp int unsigned 1005598029
354 T Seconds to service request request_duration smallint unsigned 2
355 t Time of request in human format request_time char(28) [02/Dec/2001:15:01:26 -0800]
356 U Request in simple form request_uri varchar(255) /books-cycroad.html
357 u User info from HTTP auth remote_user varchar(50) bobby
358 v Virtual host servicing the request virtual_host varchar(255)
360 $this->dbi->genericSqlQuery("
361 CREATE TABLE $log_tbl (
362 time_stamp int unsigned,
363 remote_host varchar(100),
364 remote_user varchar(50),
365 request_method varchar(10),
366 request_line varchar(255),
367 request_args varchar(255),
368 request_uri varchar(255),
369 request_time char(28),
370 status smallint unsigned,
371 bytes_sent smallint unsigned,
372 referer varchar(255),
374 request_duration float
376 $this->dbi->genericSqlQuery("CREATE INDEX log_time ON $log_tbl (time_stamp)");
377 $this->dbi->genericSqlQuery("CREATE INDEX log_host ON $log_tbl (remote_host)");
378 echo " ", _("CREATED");
385 * Update from ~1.3.4 to current.
386 * tables: Only session, user, pref and member
387 * jeffs-hacks database api (around 1.3.2) later:
388 * people should export/import their pages if using that old versions.
390 function CheckDatabaseUpdate()
392 global $DBAuthParams, $DBParams;
394 echo "<h2>", sprintf(_("Check for necessary %s updates"),
396 " - ", DATABASE_TYPE, "</h2>\n";
397 $dbadmin = $this->request->getArg('dbadmin');
400 if (isset($dbadmin['cancel'])) {
401 echo _("Cancel"), " <br />\n";
405 echo "db version: we want ", $this->current_db_version, "\n<br />";
406 echo "db version: we have ", $this->db_version, "\n<br />";
407 if ($this->db_version >= $this->current_db_version) {
408 echo _("OK"), "<br />\n";
412 $backend_type = $this->dbi->_backend->backendType();
414 echo "<h4>", _("Backend type: "), $backend_type, "</h4>\n";
415 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
416 $tables = $this->dbi->_backend->listOfTables();
417 foreach (explode(':', 'session:pref:member') as $table) {
418 echo sprintf(_("Check for table %s"), $table), " ...";
419 if (!in_array($prefix . $table, $tables)) {
420 $this->installTable($table, $backend_type);
422 echo _("OK"), " <br />\n";
427 if ($this->phpwiki_version >= 1030.12200612 and $this->db_version < 1030.13) {
428 if ($this->isSQL and preg_match("/(pgsql|postgres)/", $backend_type)) {
429 trigger_error("You need to upgrade to schema/psql-initialize.sql manually!",
431 // $this->_upgrade_psql_tsearch2();
433 $this->_upgrade_relation_links();
436 if (ACCESS_LOG_SQL and $this->isSQL) {
437 $table = "accesslog";
438 echo sprintf(_("Check for table %s"), $table), " ...";
439 if (!in_array($prefix . $table, $tables)) {
440 $this->installTable($table, $backend_type);
442 echo _("OK"), " <br />\n";
445 if ($this->isSQL and (class_exists("RatingsUserFactory") or $this->dbi->isWikiPage(_("RateIt")))) {
447 echo sprintf(_("Check for table %s"), $table), " ...";
448 if (!in_array($prefix . $table, $tables)) {
449 $this->installTable($table, $backend_type);
451 echo _("OK"), " <br />\n";
454 $backend = &$this->dbi->_backend->_dbh;
456 extract($this->dbi->_backend->_table_names);
458 // 1.3.8 added session.sess_ip
459 if ($this->isSQL and $this->phpwiki_version >= 1030.08 and USE_DB_SESSION
460 and isset($this->request->_dbsession)
462 echo _("Check for new session.sess_ip column"), " ... ";
463 $database = $this->dbi->_backend->database();
464 assert(!empty($DBParams['db_session_table']));
465 $session_tbl = $prefix . $DBParams['db_session_table'];
466 $sess_fields = $this->dbi->_backend->listOfFields($database, $session_tbl);
469 } elseif (!strstr(strtolower(join(':', $sess_fields)), "sess_ip")) {
470 // TODO: postgres test (should be able to add columns at the end, but not in between)
471 echo "<b>", _("ADDING"), "</b>", " ... ";
472 $this->dbi->genericSqlQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
473 $this->dbi->genericSqlQuery("CREATE INDEX sess_date ON $session_tbl (sess_date)");
478 if (substr($backend_type, 0, 5) == 'mysql') {
479 // upgrade to 4.1.8 destroyed my session table:
480 // sess_id => varchar(10), sess_data => varchar(5). For others obviously also.
481 echo _("Check for mysql session.sess_id sanity"), " ... ";
482 $result = $this->dbi->genericSqlQuery("DESCRIBE $session_tbl");
483 if (DATABASE_TYPE == 'SQL') {
484 $iter = new WikiDB_backend_PearDB_generic_iter($backend, $result);
485 } elseif (DATABASE_TYPE == 'ADODB') {
486 $iter = new WikiDB_backend_ADODB_generic_iter($backend, $result,
487 array("Field", "Type", "Null", "Key", "Default", "Extra"));
488 } elseif (DATABASE_TYPE == 'PDO') {
489 $iter = new WikiDB_backend_PDO_generic_iter($backend, $result);
491 while ($col = $iter->next()) {
492 if ($col["Field"] == 'sess_id' and !strstr(strtolower($col["Type"]), 'char(32)')) {
493 $this->dbi->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_id"
494 . " sess_id CHAR(32) NOT NULL");
495 echo "sess_id ", $col["Type"], " ", _("fixed"), " => CHAR(32) ";
497 if ($col["Field"] == 'sess_ip' and !strstr(strtolower($col["Type"]), 'char(15)')) {
498 $this->dbi->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_ip"
499 . " sess_ip CHAR(15) NOT NULL");
500 echo "sess_ip ", $col["Type"], " ", _("fixed"), " => CHAR(15) ";
503 echo _("OK"), "<br />\n";
508 ALTER TABLE link ADD relation INT DEFAULT 0;
509 CREATE INDEX linkrelation ON link (relation);
512 // mysql >= 4.0.4 requires LOCK TABLE privileges
513 if (substr($backend_type, 0, 5) == 'mysql') {
514 echo _("Check for mysql LOCK TABLE privilege"), " ...";
515 $mysql_version = $this->dbi->_backend->_serverinfo['version'];
516 if ($mysql_version > 400.40) {
517 if (!empty($this->dbi->_backend->_parsedDSN))
518 $parseDSN = $this->dbi->_backend->_parsedDSN;
519 elseif (function_exists('parseDSN')) // ADODB or PDO
520 $parseDSN = parseDSN($DBParams['dsn']); else // pear
521 $parseDSN = DB::parseDSN($DBParams['dsn']);
522 $username = $this->dbi->_backend->qstr($parseDSN['username']);
524 $query = "SELECT lock_tables_priv FROM mysql.db WHERE user='$username'";
525 //mysql_select_db("mysql", $this->dbi->_backend->connection());
526 $db_fields = $this->dbi->_backend->listOfFields("mysql", "db");
527 if (!strstr(strtolower(join(':', $db_fields)), "lock_tables_priv")) {
528 echo join(':', $db_fields);
529 die("lock_tables_priv missing. The DB Admin must run mysql_fix_privilege_tables");
531 $row = $this->dbi->_backend->getRow($query);
532 if (isset($row[0]) and $row[0] == 'N') {
533 $this->dbi->genericSqlQuery("UPDATE mysql.db SET lock_tables_priv='Y'"
534 . " WHERE mysql.user='$username'");
535 $this->dbi->genericSqlQuery("FLUSH PRIVILEGES");
536 echo "mysql.db user='$username'", _("fixed"), "<br />\n";
539 $query = "SELECT lock_tables_priv FROM mysql.user WHERE user='$username'";
540 $row = $this->dbi->_backend->getRow($query);
541 if ($row and $row[0] == 'N') {
542 $this->dbi->genericSqlQuery("UPDATE mysql.user SET lock_tables_priv='Y'"
543 . " WHERE mysql.user='$username'");
544 $this->dbi->genericSqlQuery("FLUSH PRIVILEGES");
545 echo "mysql.user user='$username'", _("fixed"), "<br />\n";
547 echo ' <span style="color: red; font-weight: bold;">' . _("FAILED") . "</span>"
548 . " Neither mysql.db nor mysql.user has a user='$username'"
549 . " or the lock_tables_priv field",
552 echo _("OK"), "<br />\n";
555 echo _("OK"), "<br />\n";
557 //mysql_select_db($this->dbi->_backend->database(), $this->dbi->_backend->connection());
559 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version), "<br />\n";
563 // 1.3.10 mysql requires page.id auto_increment
564 // mysql, mysqli or mysqlt
565 if ($this->phpwiki_version >= 1030.099 and substr($backend_type, 0, 5) == 'mysql'
566 and DATABASE_TYPE != 'PDO'
568 echo _("Check for mysql page.id auto_increment flag"), " ...";
569 assert(!empty($page_tbl));
570 $database = $this->dbi->_backend->database();
571 $fields = mysql_list_fields($database, $page_tbl, $this->dbi->_backend->connection());
572 $columns = mysql_num_fields($fields);
573 for ($i = 0; $i < $columns; $i++) {
574 if (mysql_field_name($fields, $i) == 'id') {
575 $flags = mysql_field_flags($fields, $i);
576 //DONE: something was wrong with ADODB here.
577 if (!strstr(strtolower($flags), "auto_increment")) {
578 echo "<b>", _("ADDING"), "</b>", " ... ";
579 // MODIFY col_def valid since mysql 3.22.16,
580 // older mysql's need CHANGE old_col col_def
581 $this->dbi->genericSqlQuery("ALTER TABLE $page_tbl CHANGE id"
582 . " id INT NOT NULL AUTO_INCREMENT");
583 $fields = mysql_list_fields($database, $page_tbl);
584 if (!strstr(strtolower(mysql_field_flags($fields, $i)), "auto_increment"))
585 echo ' <span style="color: red; font-weight: bold;">' . _("FAILED") . "</span><br />\n";
587 echo _("OK"), "<br />\n";
589 echo _("OK"), "<br />\n";
594 mysql_free_result($fields);
597 // Check for mysql 4.1.x/5.0.0a binary search problem.
598 // http://bugs.mysql.com/bug.php?id=4398
599 // "select * from page where LOWER(pagename) like '%search%'" does not apply LOWER!
600 // Confirmed for 4.1.0alpha,4.1.3-beta,5.0.0a; not yet tested for 4.1.2alpha,
601 // On windows only, though utf8 would be useful elsewhere also.
602 // Illegal mix of collations (latin1_bin,IMPLICIT) and
603 // (utf8_general_ci, COERCIBLE) for operation '='])
604 if (isWindows() and substr($backend_type, 0, 5) == 'mysql') {
605 echo _("Check for mysql 4.1.x/5.0.0 binary search on Windows problem"), " ...";
606 $mysql_version = $this->dbi->_backend->_serverinfo['version'];
607 if ($mysql_version < 401.0) {
608 echo sprintf(_("version <em>%s</em>"), $mysql_version), " ",
609 _("not affected"), "<br />\n";
610 } elseif ($mysql_version >= 401.6) { // FIXME: since which version?
611 $row = $this->dbi->_backend->getRow("SHOW CREATE TABLE $page_tbl");
612 $result = join(" ", $row);
613 if (strstr(strtolower($result), "character set")
614 and strstr(strtolower($result), "collate")
616 echo _("OK"), "<br />\n";
619 $this->dbi->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename "
620 . "pagename VARCHAR(100) "
621 . "CHARACTER SET '$charset' COLLATE '$charset" . "_bin' NOT NULL");
622 echo sprintf(_("version <em>%s</em>"), $mysql_version),
623 " <b>", _("FIXED"), "</b>",
626 } elseif (DATABASE_TYPE != 'PDO') {
627 // check if already fixed
628 extract($this->dbi->_backend->_table_names);
629 assert(!empty($page_tbl));
630 $database = $this->dbi->_backend->database();
631 $fields = mysql_list_fields($database, $page_tbl, $this->dbi->_backend->connection());
632 $columns = mysql_num_fields($fields);
633 for ($i = 0; $i < $columns; $i++) {
634 if (mysql_field_name($fields, $i) == 'pagename') {
635 $flags = mysql_field_flags($fields, $i);
636 // I think it was fixed with 4.1.6, but I tested it only with 4.1.8
637 if ($mysql_version > 401.0 and $mysql_version < 401.6) {
638 // remove the binary flag
639 if (strstr(strtolower($flags), "binary")) {
640 // FIXME: on duplicate pagenames this will fail!
641 $this->dbi->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename"
642 . " pagename VARCHAR(100) NOT NULL");
643 echo sprintf(_("version <em>%s</em>"), $mysql_version),
644 "<b>", _("FIXED"), "</b>"
653 if ($this->isSQL and ACCESS_LOG_SQL & 2) {
654 echo _("Check for ACCESS_LOG_SQL passwords in POST requests"), " ...";
655 // Don't display passwords in POST requests (up to 2005-02-04 12:03:20)
656 $res = $this->dbi->genericSqlIter("SELECT time_stamp, remote_host, " .
657 "request_args FROM ${prefix}accesslog WHERE request_args LIKE " .
658 "'%s:6:\"passwd\"%' AND request_args NOT LIKE '%s:6:\"passwd\";" .
659 "s:15:\"<not displayed>\"%'");
661 while ($row = $res->next()) {
662 $args = preg_replace("/(s:6:\"passwd\";s:15:\").*(\")/",
663 "$1<not displayed>$2", $row["request_args"]);
664 $ts = $row["time_stamp"];
665 $rh = $row["remote_host"];
666 $this->dbi->genericSqlQuery("UPDATE ${prefix}accesslog SET " .
667 "request_args='$args' WHERE time_stamp=$ts AND " .
668 "remote_host='$rh'");
672 echo "<b>", _("FIXED"), "</b>", "<br />\n";
674 echo _("OK"), "<br />\n";
676 if ($this->phpwiki_version >= 1030.13) {
677 echo _("Check for ACCESS_LOG_SQL remote_host varchar(50)"), " ...";
678 $database = $this->dbi->_backend->database();
679 $accesslog_tbl = $prefix . 'accesslog';
680 $fields = $this->dbi->_backend->listOfFields($database, $accesslog_tbl);
683 } elseif (strstr(strtolower(join(':', $sess_fields)), "remote_host")) {
684 // TODO: how to check size, already done?
685 echo "<b>", _("FIXING"), "remote_host</b>", " ... ";
686 $this->dbi->genericSqlQuery("ALTER TABLE $accesslog_tbl CHANGE remote_host VARCHAR(100)");
693 $this->_upgrade_cached_html();
695 if ($this->db_version < $this->current_db_version) {
696 $this->dbi->set_db_version($this->current_db_version);
697 $this->db_version = $this->dbi->get_db_version();
698 echo "db version: upgrade to ", $this->db_version, " ";
699 echo _("OK"), "<br />\n";
707 * Filter SQL missing permissions errors.
709 * A wrong DBADMIN user will not be able to connect
710 * @see _is_false_error, ErrorManager
712 public function _dbpermission_filter($err)
714 if ($err->isWarning()) {
715 global $ErrorManager;
716 $this->error_caught = 1;
717 $ErrorManager->_postponed_errors[] = $err;
723 function _try_dbadmin_user($user, $passwd)
725 global $DBParams, $DBAuthParams;
726 $AdminParams = $DBParams;
727 if (DATABASE_TYPE == 'SQL')
728 $dsn = DB::parseDSN($AdminParams['dsn']);
730 $dsn = parseDSN($AdminParams['dsn']);
732 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
738 $AdminParams['_tryroot_from_upgrade'] = 1;
739 // add error handler to warn about missing permissions for DBADMIN_USER
740 global $ErrorManager;
741 $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_dbpermission_filter'));
742 $this->error_caught = 0;
743 $this->dbi = WikiDB::open($AdminParams);
744 if (!$this->error_caught) return true;
745 // FAILED: redo our connection with the wikiuser
746 $this->dbi = WikiDB::open($DBParams);
747 $ErrorManager->flushPostponedErrors();
748 $ErrorManager->popErrorHandler();
754 if (!$this->isSQL) return;
756 /* SQLite never needs admin params */
757 $backend_type = $this->dbi->_backend->backendType();
758 if (substr($backend_type, 0, 6) == "sqlite") {
761 $dbadmin_user = 'root';
762 if ($dbadmin = $this->request->getArg('dbadmin')) {
763 $dbadmin_user = $dbadmin['user'];
764 if (isset($dbadmin['cancel'])) {
766 } elseif (!empty($dbadmin_user)) {
767 if ($this->_try_dbadmin_user($dbadmin['user'], $dbadmin['passwd']))
770 } elseif (DBADMIN_USER) {
771 if ($this->_try_dbadmin_user(DBADMIN_USER, DBADMIN_PASSWD)) {
775 // Check if the privileges are enough. Need CREATE and ALTER perms.
776 // And on Windows: SELECT FROM mysql, possibly: UPDATE mysql.
777 $form = HTML::form(array("method" => "post",
778 "action" => $this->request->getPostURL(),
779 "accept-charset" => 'UTF-8'),
780 HTML::p(_("Upgrade requires database privileges to CREATE and ALTER the phpwiki database."),
782 _("And on Windows at least the privilege to SELECT FROM mysql, and possibly UPDATE mysql")),
783 HiddenInputs(array('action' => 'upgrade',
784 'overwrite' => $this->request->getArg('overwrite'))),
785 HTML::table(array("cellspacing" => 4),
786 HTML::tr(HTML::td(array('align' => 'right'),
787 _("DB admin user:")),
788 HTML::td(HTML::input(array('name' => "dbadmin[user]",
791 'value' => $dbadmin_user)))),
792 HTML::tr(HTML::td(array('align' => 'right'),
793 _("DB admin password:")),
794 HTML::td(HTML::input(array('name' => "dbadmin[passwd]",
795 'type' => 'password',
797 'maxlength' => 256)))),
798 HTML::tr(HTML::td(array('align' => 'center', 'colspan' => 2),
799 Button("submit:", _("Submit"), 'wikiaction'),
801 Button("submit:dbadmin[cancel]", _("Cancel"),
804 echo "</div><!-- content -->\n";
805 echo asXML(Template("bottom"));
806 echo "</body></html>\n";
807 $this->request->finish();
812 * if page.cached_html does not exists:
813 * put _cached_html from pagedata into a new separate blob,
814 * not into the huge serialized string.
816 * It is only rarelely needed: for current page only, if-not-modified,
817 * but was extracetd for every simple page iteration.
819 function _upgrade_cached_html($verbose = true)
822 if (!$this->isSQL) return 0;
824 if ($this->phpwiki_version >= 1030.10) {
826 echo _("Check for extra page.cached_html column"), " ... ";
827 $database = $this->dbi->_backend->database();
828 extract($this->dbi->_backend->_table_names);
829 $fields = $this->dbi->_backend->listOfFields($database, $page_tbl);
831 echo _("SKIP"), "<br />\n";
834 if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
836 echo "<b>", _("ADDING"), "</b>", " ... ";
837 $backend_type = $this->dbi->_backend->backendType();
838 if (substr($backend_type, 0, 5) == 'mysql')
839 $this->dbi->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
841 $this->dbi->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
843 echo "<b>", _("CONVERTING"), "</b>", " ... ";
844 $count = _convert_cached_html();
846 echo $count, " ", _("OK"), "<br />\n";
849 echo _("OK"), "<br />\n";
856 * move _cached_html for all pages from pagedata into a new separate blob.
857 * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
859 function _convert_cached_html()
862 if (!$this->isSQL) return 0;
863 //if (!in_array(DATABASE_TYPE, array('SQL','ADODB'))) return;
865 $pages = $this->dbi->getAllPages();
866 $cache =& $this->dbi->_cache;
868 extract($this->dbi->_backend->_table_names);
869 while ($page = $pages->next()) {
870 $pagename = $page->getName();
871 $data = $this->dbi->_backend->get_pagedata($pagename);
872 if (!empty($data['_cached_html'])) {
873 $cached_html = $data['_cached_html'];
874 $data['_cached_html'] = '';
875 $cache->update_pagedata($pagename, $data);
876 // store as blob, not serialized
877 $this->dbi->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
878 array($cached_html, $pagename));
886 * upgrade to 1.3.13 link structure.
888 function _upgrade_relation_links($verbose = true)
890 if ($this->phpwiki_version >= 1030.12200610 and $this->isSQL) {
891 echo _("Check for relation field in link table"), " ...";
892 $database = $this->dbi->_backend->database();
893 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
894 $link_tbl = $prefix . 'link';
895 $fields = $this->dbi->_backend->listOfFields($database, $link_tbl);
898 } elseif (strstr(strtolower(join(':', $fields)), "link")) {
899 echo "<b>", _("ADDING"), " relation</b>", " ... ";
900 $this->dbi->genericSqlQuery("ALTER TABLE $link_tbl ADD relation INT DEFAULT 0;");
901 $this->dbi->genericSqlQuery("CREATE INDEX link_relation ON $link_tbl (relation);");
907 if ($this->phpwiki_version >= 1030.12200610) {
908 echo _("Rebuild entire database to upgrade relation links"), " ... ";
909 if (DATABASE_TYPE == 'dba') {
910 echo "<b>", _("CONVERTING"), " dba linktable</b>", "(~2 min, max 4 min) ... ";
913 $this->dbi->_backend->_linkdb->rebuild();
917 $this->dbi->_backend->rebuild();
919 echo _("OK"), "<br />\n";
923 function CheckPluginUpdate()
925 echo "<h2>", sprintf(_("Check for necessary %s updates"),
926 _("plugin argument")), "</h2>\n";
928 $this->_configUpdates = array();
929 $this->_configUpdates[] = new UpgradePluginEntry
930 ($this, array('key' => 'plugin_randompage_numpages',
931 'fixed_with' => 1012.0,
932 //'header' => _("change RandomPage pages => numpages"),
933 //'notice' =>_("found RandomPage plugin"),
934 'check_args' => array("plugin RandomPage pages",
935 "/(<\?\s*plugin\s+ RandomPage\s+)pages/",
937 $this->_configUpdates[] = new UpgradePluginEntry
938 ($this, array('key' => 'plugin_createtoc_position',
939 'fixed_with' => 1013.0,
940 //'header' => _("change CreateToc align => position"),
941 //'notice' =>_("found CreateToc plugin"),
942 'check_args' => array("plugin CreateToc align",
943 "/(<\?\s*plugin\s+ CreateToc[^\?]+)align/",
946 if (empty($this->_configUpdates)) return;
947 foreach ($this->_configUpdates as $update) {
948 $pages = $this->dbi->fullSearch($this->check_args[0]);
949 while ($page = $allpages->next()) {
950 $current = $page->getCurrentRevision();
951 $pagetext = $current->getPackedContent();
952 $update->check($this->check_args[1], $this->check_args[2], $pagetext, $page, $current);
962 * preg_replace over local file.
963 * Only line-orientated matches possible.
965 function fixLocalFile($match, $replace, $filename)
967 $o_filename = $filename;
968 if (!file_exists($filename))
969 $filename = FindFile($filename);
970 if (!file_exists($filename))
971 return array(false, sprintf(_("File “%s” not found."), $o_filename));
973 if (is_writable($filename)) {
974 $in = fopen($filename, "rb");
975 $out = fopen($tmp = tempnam(getUploadFilePath(), "cfg"), "wb");
977 $tmp = str_replace("/", "\\", $tmp);
978 // Detect the existing linesep at first line. fgets strips it even if 'rb'.
979 // Before we simply assumed \r\n on Windows local files.
980 $s = fread($in, 1024);
982 $linesep = (substr_count($s, "\r\n") > substr_count($s, "\n")) ? "\r\n" : "\n";
983 //$linesep = isWindows() ? "\r\n" : "\n";
984 while ($s = fgets($in)) {
985 // =>php-5.0.1 can fill count
986 //$new = preg_replace($match, $replace, $s, -1, $count);
987 $new = preg_replace($match, $replace, $s);
989 $s = $new . $linesep;
998 $reason = sprintf(_("%s not found in %s"), $match, $filename);
1000 return array($found, $reason);
1002 @unlink("$file.bak");
1003 @rename($file, "$file.bak");
1004 if (!rename($tmp, $file))
1005 return array(false, sprintf(_("couldn't move %s to %s"), $tmp, $filename));
1009 return array(false, sprintf(_("file %s is not writable"), $filename));
1013 function CheckConfigUpdate()
1015 echo "<h2>", sprintf(_("Check for necessary %s updates"),
1016 "config.ini"), "</h2>\n";
1017 $entry = new UpgradeConfigEntry
1018 ($this, array('key' => 'cache_control_none',
1019 'fixed_with' => 1012.0,
1020 'header' => sprintf(_("Check for %s"), "CACHE_CONTROL = NONE"),
1021 'applicable_args' => 'CACHE_CONTROL',
1022 'notice' => _("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'"),
1023 'check_args' => array("/^\s*CACHE_CONTROL\s*=\s*NONE/", "CACHE_CONTROL = NO_CACHE")));
1024 $entry->setApplicableCb(new WikiMethodCb($entry, '_applicable_defined_and_empty'));
1025 $this->_configUpdates[] = $entry;
1027 $entry = new UpgradeConfigEntry
1028 ($this, array('key' => 'group_method_none',
1029 'fixed_with' => 1012.0,
1030 'header' => sprintf(_("Check for %s"), "GROUP_METHOD = NONE"),
1031 'applicable_args' => 'GROUP_METHOD',
1032 'notice' => _("GROUP_METHOD is set to NONE, and must be changed to \"NONE\""),
1033 'check_args' => array("/^\s*GROUP_METHOD\s*=\s*NONE/", "GROUP_METHOD = \"NONE\"")));
1034 $entry->setApplicableCb(new WikiMethodCb($entry, '_applicable_defined_and_empty'));
1035 $this->_configUpdates[] = $entry;
1037 $entry = new UpgradeConfigEntry
1038 ($this, array('key' => 'blog_empty_default_prefix',
1039 'fixed_with' => 1013.0,
1040 'header' => sprintf(_("Check for %s"), "BLOG_EMPTY_DEFAULT_PREFIX"),
1041 'applicable_args' => 'BLOG_EMPTY_DEFAULT_PREFIX',
1042 'notice' => _("fix BLOG_EMPTY_DEFAULT_PREFIX into BLOG_DEFAULT_EMPTY_PREFIX"),
1043 'check_args' => array("/BLOG_EMPTY_DEFAULT_PREFIX\s*=/", "BLOG_DEFAULT_EMPTY_PREFIX =")));
1044 $entry->setApplicableCb(new WikiMethodCb($entry, '_applicable_defined'));
1045 $this->_configUpdates[] = $entry;
1047 // TODO: find extra file updates
1048 if (empty($this->_configUpdates)) return;
1049 foreach ($this->_configUpdates as $update) {
1059 * Add an upgrade item to be checked.
1061 * @param object $parent The parent Upgrade class to inherit the version properties
1062 * @param array $params
1064 function UpgradeEntry(&$parent, $params)
1066 $this->parent =& $parent; // get the properties db_version
1067 foreach (array('key' => 'required',
1068 // the wikidb stores the version when we actually fixed that.
1069 'fixed_with' => 'required',
1070 'header' => '', // always printed
1071 'applicable_cb' => null, // method to check if applicable
1072 'applicable_args' => array(), // might be the config name
1074 'check_cb' => null, // method to apply
1075 'check_args' => array())
1077 if (!isset($params[$k])) { // default
1078 if ($v == 'required') trigger_error("Required arg $k missing", E_USER_ERROR);
1079 else $this->{$k} = $v;
1081 $this->{$k} = $params[$k];
1084 if (!is_array($this->applicable_args)) // single arg convenience shortcut
1085 $this->applicable_args = array($this->applicable_args);
1086 if (!is_array($this->check_args)) // single arg convenience shortcut
1087 $this->check_args = array($this->check_args);
1088 if ($this->notice === '' and count($this->applicable_args) > 0)
1089 $this->notice = 'Check for ' . join(', ', $this->applicable_args);
1090 $this->_db_key = "_upgrade";
1091 $this->upgrade = $this->parent->dbi->get($this->_db_key);
1095 function setApplicableCb($object)
1097 $this->applicable_cb =& $object;
1100 function _check_if_already_fixed()
1103 if (!isset($this->upgrade['name'])) return false;
1104 // override with force?
1105 if ($this->parent->request->getArg('force')) return false;
1106 // already fixed and with an ok version
1107 if ($this->upgrade['name'] >= $this->fixed_with) return $this->upgrade['name'];
1108 // already fixed but with an older version. do it again.
1114 // store in db no to fix again
1115 $this->upgrade['name'] = $this->parent->phpwiki_version;
1116 $this->parent->dbi->set($this->_db_key, $this->upgrade);
1117 echo "<b>", _("FIXED"), "</b>";
1118 if (isset($this->reason))
1119 echo _(": "), $this->reason;
1127 echo '<span style="color: red; font-weight: bold; ">' . _("FAILED") . "</span>";
1128 if (isset($this->reason))
1129 echo _(": "), $this->reason;
1137 if (isset($this->silent_skip)) return true;
1138 echo " " . _("Skipped.") . "<br />\n";
1143 function check($args = null)
1145 if ($this->header) echo $this->header, ' ... ';
1146 if ($when = $this->_check_if_already_fixed()) {
1147 // be totally silent if no header is defined.
1148 if ($this->header) echo _("fixed with"), " ", $when, "<br />\n";
1152 if (is_object($this->applicable_cb)) {
1153 if (!$this->applicable_cb->call_array($this->applicable_args))
1154 return $this->skip();
1156 if ($this->notice) {
1159 echo $this->notice, " ";
1162 if (!is_null($args)) $this->check_args =& $args;
1163 if (is_object($this->check_cb))
1164 $do = $this->method_cb->call_array($this->check_args);
1166 $do = $this->default_method($this->check_args);
1167 if (is_array($do)) {
1168 $this->reason = $do[1];
1171 return $do ? $this->pass() : $this->fail();
1173 } // class UpgradeEntry
1175 class UpgradeConfigEntry extends UpgradeEntry
1177 function _applicable_defined()
1179 return (boolean)defined($this->applicable_args[0]);
1182 function _applicable_defined_and_empty()
1184 $const = $this->applicable_args[0];
1185 return (boolean)(defined($const) and !constant($const));
1188 function default_method($args)
1191 $replace = $args[1];
1192 return $this->parent->fixLocalFile($match, $replace, "config/config.ini");
1194 } // class UpdateConfigEntry
1196 /* This is different */
1197 class UpgradePluginEntry extends UpgradeEntry
1201 * check all pages for a plugin match
1203 public $silent_skip = 1;
1205 function default_method(&$args)
1208 $replace = $args[1];
1209 $pagetext =& $args[2];
1211 $current =& $args[4];
1212 if (preg_match($match, $pagetext)) {
1213 echo $page->getName(), " ", $this->notice, " ... ";
1214 if ($newtext = preg_replace($match, $replace, $pagetext)) {
1215 $meta = $current->_data;
1216 $meta['summary'] = "upgrade: " . $this->header;
1217 $page->save($newtext, $current->getVersion() + 1, $meta);
1224 } // class UpdatePluginEntry
1227 * fix custom themes which are not in our distribution
1228 * this should be optional
1230 class UpgradeThemeEntry extends UpgradeEntry
1233 function default_method(&$args)
1236 $replace = $args[1];
1237 $template = $args[2];
1240 function fixThemeTemplate($match, $new, $template)
1242 // for all custom themes
1243 $ourthemes = explode(":", "blog:Crao:default:Hawaiian:MacOSX:MonoBook:Portland:shamino_com:SpaceWiki:wikilens:Wordpress");
1244 $themedir = NormalizeLocalFileName("themes");
1245 $dh = opendir($themedir);
1246 while ($r = readdir($dh)) {
1247 if (filetype($r) == 'dir' and $r[0] != '.' and !is_array($r, $ourthemes))
1248 $customthemes[] = $r;
1252 foreach ($customthemes as $customtheme) {
1253 $template = FindFile("themes/$customtheme/templates/$template");
1254 $do = $this->parent->fixLocalFile($match, $new, template);
1257 $errors .= $do[1] . " ";
1261 return array($success, $errors);
1268 * Upgrade: Base class for multipage worksteps
1269 * identify, validate, display options, next step
1274 // TODO: At which step are we?
1275 // validate and do it again or go on with next step.
1277 /** entry function from lib/main.php
1279 function DoUpgrade(&$request)
1282 if (!$request->_user->isAdmin()) {
1283 $request->_notAuthorized(WIKIAUTH_ADMIN);
1285 HTML::div(array('class' => 'disabled-plugin'),
1286 fmt("Upgrade disabled: user != isAdmin")));
1289 // TODO: StartLoadDump should turn on implicit_flush.
1290 @ini_set("implicit_flush", true);
1291 StartLoadDump($request, _("Upgrading this PhpWiki"));
1292 $upgrade = new Upgrade($request);
1293 //if (!$request->getArg('noindex'))
1294 // CheckOldIndexUpdate($request); // index.php => config.ini to upgrade from < 1.3.10
1295 if (!$request->getArg('nodb')) {
1296 $upgrade->CheckDatabaseUpdate($request); // first check cached_html and friends
1298 if (!$request->getArg('nopgsrc')) {
1299 $upgrade->CheckPgsrcUpdate($request);
1300 $upgrade->CheckActionPageUpdate($request);
1302 // if (!$request->getArg('noplugin')) {
1303 // $upgrade->CheckPluginUpdate($request);
1305 if (!$request->getArg('noconfig')) {
1306 $upgrade->CheckConfigUpdate($request);
1308 // This is optional and should be linked. In EndLoadDump or PhpWikiAdministration?
1309 //if ($request->getArg('theme'))
1310 // $upgrade->CheckThemeUpdate($request);
1311 EndLoadDump($request);
1317 // c-basic-offset: 4
1318 // c-hanging-comment-ender-p: nil
1319 // indent-tabs-mode: nil