2 rcs_id('$Id: upgrade.php,v 1.42 2005-02-02 19:38:13 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'))) 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"),"schemas/${backend_type}.sql")," ... <br />\n";
181 extract($dbh->_backend->_table_names);
182 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
185 assert($session_tbl);
186 if ($backend_type == 'mysql') {
187 $dbh->genericSqlQuery("
188 CREATE TABLE $session_tbl (
189 sess_id CHAR(32) NOT NULL DEFAULT '',
190 sess_data BLOB NOT NULL,
191 sess_date INT UNSIGNED NOT NULL,
192 sess_ip CHAR(15) NOT NULL,
193 PRIMARY KEY (sess_id),
197 $dbh->genericSqlQuery("
198 CREATE TABLE $session_tbl (
199 sess_id CHAR(32) NOT NULL DEFAULT '',
200 sess_data ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
202 sess_ip CHAR(15) NOT NULL
204 $dbh->genericSqlQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
206 $dbh->genericSqlQuery("CREATE INDEX sess_date on session (sess_date)");
207 echo " ",_("CREATED");
210 $user_tbl = $prefix.'user';
211 if ($backend_type == 'mysql') {
212 $dbh->genericSqlQuery("
213 CREATE TABLE $user_tbl (
214 userid CHAR(48) BINARY NOT NULL UNIQUE,
215 passwd CHAR(48) BINARY DEFAULT '',
219 $dbh->genericSqlQuery("
220 CREATE TABLE $user_tbl (
221 userid CHAR(48) NOT NULL,
222 passwd CHAR(48) DEFAULT ''
224 $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
226 echo " ",_("CREATED");
229 $pref_tbl = $prefix.'pref';
230 if ($backend_type == 'mysql') {
231 $dbh->genericSqlQuery("
232 CREATE TABLE $pref_tbl (
233 userid CHAR(48) BINARY NOT NULL UNIQUE,
234 prefs TEXT NULL DEFAULT '',
238 $dbh->genericSqlQuery("
239 CREATE TABLE $pref_tbl (
240 userid CHAR(48) NOT NULL,
241 prefs TEXT NULL DEFAULT '',
243 $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
245 echo " ",_("CREATED");
248 $member_tbl = $prefix.'member';
249 if ($backend_type == 'mysql') {
250 $dbh->genericSqlQuery("
251 CREATE TABLE $member_tbl (
252 userid CHAR(48) BINARY NOT NULL,
253 groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
258 $dbh->genericSqlQuery("
259 CREATE TABLE $member_tbl (
260 userid CHAR(48) NOT NULL,
261 groupname CHAR(48) NOT NULL DEFAULT 'users',
263 $dbh->genericSqlQuery("CREATE INDEX userid ON $member_tbl (userid)");
264 $dbh->genericSqlQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
266 echo " ",_("CREATED");
269 $rating_tbl = $prefix.'rating';
270 if ($backend_type == 'mysql') {
271 $dbh->genericSqlQuery("
272 CREATE TABLE $rating_tbl (
273 dimension INT(4) NOT NULL,
274 raterpage INT(11) NOT NULL,
275 rateepage INT(11) NOT NULL,
276 ratingvalue FLOAT NOT NULL,
277 rateeversion INT(11) NOT NULL,
278 tstamp TIMESTAMP(14) NOT NULL,
279 PRIMARY KEY (dimension, raterpage, rateepage)
282 $dbh->genericSqlQuery("
283 CREATE TABLE $rating_tbl (
284 dimension INT(4) NOT NULL,
285 raterpage INT(11) NOT NULL,
286 rateepage INT(11) NOT NULL,
287 ratingvalue FLOAT NOT NULL,
288 rateeversion INT(11) NOT NULL,
289 tstamp TIMESTAMP(14) NOT NULL,
291 $dbh->genericSqlQuery("CREATE UNIQUE INDEX rating ON $rating_tbl (dimension, raterpage, rateepage)");
293 echo " ",_("CREATED");
296 $log_tbl = $prefix.'accesslog';
297 // fields according to http://www.outoforder.cc/projects/apache/mod_log_sql/docs-2.0/#id2756178
299 A User Agent agent varchar(255) Mozilla/4.0 (compat; MSIE 6.0; Windows)
300 a CGi request arguments request_args varchar(255) user=Smith&cart=1231&item=532
301 b Bytes transfered bytes_sent int unsigned 32561
302 c??? Text of cookie cookie varchar(255) Apache=sdyn.fooonline.net 1300102700823
303 f Local filename requested request_file varchar(255) /var/www/html/books-cycroad.html
304 H HTTP request_protocol request_protocol varchar(10) HTTP/1.1
305 h Name of remote host remote_host varchar(50) blah.foobar.com
306 I Request ID (from modd_unique_id) id char(19) POlFcUBRH30AAALdBG8
307 l Ident user info remote_logname varcgar(50) bobby
308 M Machine ID??? machine_id varchar(25) web01
309 m HTTP request method request_method varchar(10) GET
310 P httpd cchild PID child_pid smallint unsigned 3215
311 p http port server_port smallint unsigned 80
312 R Referer referer varchar(255) http://www.biglinks4u.com/linkpage.html
313 r Request in full form request_line varchar(255) GET /books-cycroad.html HTTP/1.1
314 S Time of request in UNIX time_t format time_stamp int unsigned 1005598029
315 T Seconds to service request request_duration smallint unsigned 2
316 t Time of request in human format request_time char(28) [02/Dec/2001:15:01:26 -0800]
317 U Request in simple form request_uri varchar(255) /books-cycroad.html
318 u User info from HTTP auth remote_user varchar(50) bobby
319 v Virtual host servicing the request virtual_host varchar(255)
321 $dbh->genericSqlQuery("
322 CREATE TABLE $log_tbl (
323 time_stamp int unsigned,
324 remote_host varchar(50),
325 remote_user varchar(50),
326 request_method varchar(10),
327 request_line varchar(255),
328 request_args varchar(255),
329 request_uri varchar(255),
330 request_time char(28),
331 status smallint unsigned,
332 bytes_sent smallint unsigned,
333 referer varchar(255),
335 request_duration float
337 $dbh->genericSqlQuery("CREATE INDEX log_time ON $log_tbl (time_stamp)");
338 $dbh->genericSqlQuery("CREATE INDEX log_host ON $log_tbl (remote_host)");
339 echo " ",_("CREATED");
346 * Update from ~1.3.4 to current.
347 * Only session, user, pref and member
348 * jeffs-hacks database api (around 1.3.2) later:
349 * people should export/import their pages if using that old versions.
351 function CheckDatabaseUpdate(&$request) {
352 global $DBParams, $DBAuthParams;
353 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
354 echo "<h3>",_("check for necessary database updates"), " - ", $DBParams['dbtype'], "</h3>\n";
356 $dbh = $request->getDbh();
357 $dbadmin = $request->getArg('dbadmin');
358 _upgrade_db_init($dbh);
359 if (isset($dbadmin['cancel'])) {
360 echo _("CANCEL")," <br />\n";
364 $tables = $dbh->_backend->listOfTables();
365 $backend_type = $dbh->_backend->backendType();
366 echo "<h4>",_("Backend type: "),$backend_type,"</h4>\n";
367 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
368 foreach (explode(':','session:user:pref:member') as $table) {
369 echo sprintf(_("check for table %s"), $table)," ...";
370 if (!in_array($prefix.$table, $tables)) {
371 installTable($dbh, $table, $backend_type);
373 echo _("OK")," <br />\n";
376 if (ACCESS_LOG_SQL) {
377 $table = "accesslog";
378 echo sprintf(_("check for table %s"), $table)," ...";
379 if (!in_array($prefix.$table, $tables)) {
380 installTable($dbh, $table, $backend_type);
382 echo _("OK")," <br />\n";
385 if ((class_exists("RatingsUserFactory") or $dbh->isWikiPage(_("RateIt")))) {
387 echo sprintf(_("check for table %s"), $table)," ...";
388 if (!in_array($prefix.$table, $tables)) {
389 installTable($dbh, $table, $backend_type);
391 echo _("OK")," <br />\n";
394 $backend = &$dbh->_backend->_dbh;
396 // 1.3.8 added session.sess_ip
397 if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
398 echo _("check for new session.sess_ip column")," ... ";
399 $database = $dbh->_backend->database();
400 assert(!empty($DBParams['db_session_table']));
401 $session_tbl = $prefix . $DBParams['db_session_table'];
402 $sess_fields = $dbh->_backend->listOfFields($database, $session_tbl);
403 if (!strstr(strtolower(join(':', $sess_fields)), "sess_ip")) {
404 // TODO: postgres test (should be able to add columns at the end, but not in between)
405 echo "<b>",_("ADDING"),"</b>"," ... ";
406 $dbh->genericSqlQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
407 $dbh->genericSqlQuery("CREATE INDEX sess_date ON $session_tbl (sess_date)");
412 if (substr($backend_type,0,5) == 'mysql') {
413 // upgrade to 4.1.8 destroyed my session table:
414 // sess_id => varchar(10), sess_data => varchar(5). For others obviously also.
415 echo _("check for mysql session.sess_id sanity")," ... ";
416 $result = $dbh->genericSqlQuery("DESCRIBE $session_tbl");
417 if ($DBParams['dbtype'] == 'SQL') {
418 $iter = new WikiDB_backend_PearDB_generic_iter($backend, $result);
420 $iter = new WikiDB_backend_ADODB_generic_iter($backend, $result,
421 array("Field", "Type", "Null", "Key", "Default", "Extra"));
423 while ($col = $iter->next()) {
424 if ($col["Field"] == 'sess_id' and !strstr(strtolower($col["Type"]), 'char(32)')) {
425 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_id sess_id CHAR(32) NOT NULL");
426 echo "sess_id ", $col["Type"], " ", _("fixed"), " => CHAR(32) ";
428 if ($col["Field"] == 'sess_ip' and !strstr(strtolower($col["Type"]), 'char(15)')) {
429 $dbh->genericSqlQuery("ALTER TABLE $session_tbl CHANGE sess_ip sess_ip CHAR(15) NOT NULL");
430 echo "sess_ip ", $col["Type"], " ", _("fixed"), " => CHAR(15) ";
433 echo _("OK"), "<br />\n";
437 // mysql >= 4.0.4 requires LOCK TABLE privileges
438 if (substr($backend_type,0,5) == 'mysql') {
439 echo _("check for mysql LOCK TABLE privilege")," ...";
440 $mysql_version = $dbh->_backend->_serverinfo['version'];
441 if ($mysql_version > 400.40) {
442 if (function_exists('parseDSN')) // ADODB
443 $parseDSN = parseDSN($DBParams['dsn']);
445 $parseDSN = DB::parseDSN($DBParams['dsn']);
446 $username = $dbh->_backend->qstr($parseDSN['username']);
448 $query = "SELECT lock_tables_priv FROM mysql.db WHERE user='$username'";
449 //mysql_select_db("mysql", $dbh->_backend->connection());
450 $db_fields = $dbh->_backend->listOfFields("mysql", "db");
451 if (!strstr(strtolower(join(':', $db_fields)), "lock_tables_priv")) {
452 die("lock_tables_priv missing. The DB Admin must run mysql_fix_privilege_tables");
454 $row = $backend->getRow($query);
455 if ($row and $row[0] == 'N') {
456 $dbh->genericSqlQuery("UPDATE mysql.db SET lock_tables_priv='Y' WHERE mysql.user='$username'");
457 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
458 echo "mysql.db user='$username'", _("fixed"), "<br />\n";
461 $query = "SELECT lock_tables_priv FROM mysql.user WHERE user='$username'";
462 $row = $backend->getRow($query);
463 if ($row and $row[0] == 'N') {
464 $dbh->genericSqlQuery("UPDATE mysql.user SET lock_tables_priv='Y' WHERE mysql.user='$username'");
465 $dbh->genericSqlQuery("FLUSH PRIVILEGES");
466 echo "mysql.user user='$username'", _("fixed"), "<br />\n";
468 echo " <b><font color=\"red\">", _("FAILED"), "</font></b>: ",
469 "Neither mysql.db nor mysql.user has a user='$username' or the lock_tables_priv field",
472 echo _("OK"), "<br />\n";
475 echo _("OK"), "<br />\n";
477 //mysql_select_db($dbh->_backend->database(), $dbh->_backend->connection());
479 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
483 // 1.3.10 mysql requires page.id auto_increment
484 // mysql, mysqli or mysqlt
485 if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql') {
486 echo _("check for mysql page.id auto_increment flag")," ...";
487 extract($dbh->_backend->_table_names);
488 assert(!empty($page_tbl));
489 $database = $dbh->_backend->database();
490 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
491 $columns = mysql_num_fields($fields);
492 for ($i = 0; $i < $columns; $i++) {
493 if (mysql_field_name($fields, $i) == 'id') {
494 $flags = mysql_field_flags($fields, $i);
495 //DONE: something was wrong with ADODB here.
496 if (!strstr(strtolower($flags), "auto_increment")) {
497 echo "<b>",_("ADDING"),"</b>"," ... ";
498 // MODIFY col_def valid since mysql 3.22.16,
499 // older mysql's need CHANGE old_col col_def
500 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE id id INT NOT NULL AUTO_INCREMENT");
501 $fields = mysql_list_fields($database, $page_tbl);
502 if (!strstr(strtolower(mysql_field_flags($fields, $i)), "auto_increment"))
503 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
505 echo _("OK"), "<br />\n";
507 echo _("OK"), "<br />\n";
512 mysql_free_result($fields);
515 // Check for mysql 4.1.x/5.0.0a binary search problem.
516 // http://bugs.mysql.com/bug.php?id=4398
517 // "select * from page where LOWER(pagename) like '%search%'" does not apply LOWER!
518 // Confirmed for 4.1.0alpha,4.1.3-beta,5.0.0a; not yet tested for 4.1.2alpha,
519 // On windows only, though utf8 would be useful elsewhere also.
520 if (isWindows() and substr($backend_type,0,5) == 'mysql') {
521 echo _("check for mysql 4.1.x/5.0.0 binary search on windows problem")," ...";
522 $mysql_version = $dbh->_backend->_serverinfo['version'];
523 if ($mysql_version < 401.0) {
524 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
525 } elseif ($mysql_version >= 401.6) {
526 $row = $backend->getRow("SHOW CREATE TABLE $page_tbl");
527 $result = join(" ", $row);
528 if (strstr(strtolower($result), "character set")
529 and strstr(strtolower($result), "collate"))
531 echo _("OK"), "<br />\n";
533 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename "
534 ."pagename VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL");
535 echo sprintf(_("version <em>%s</em> <b>FIXED</b>"), $mysql_version),"<br />\n";
538 // check if already fixed
539 extract($dbh->_backend->_table_names);
540 assert(!empty($page_tbl));
541 $database = $dbh->_backend->database();
542 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
543 $columns = mysql_num_fields($fields);
544 for ($i = 0; $i < $columns; $i++) {
545 if (mysql_field_name($fields, $i) == 'pagename') {
546 $flags = mysql_field_flags($fields, $i);
547 // I think it was fixed with 4.1.6, but I tested it only with 4.1.8
548 if ($mysql_version > 401.0 and $mysql_version < 401.6) {
549 // remove the binary flag
550 if (strstr(strtolower($flags), "binary")) {
551 // FIXME: on duplicate pagenames this will fail!
552 $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename pagename VARCHAR(100) NOT NULL");
553 echo sprintf(_("version <em>%s</em> <b>FIXED</b>"), $mysql_version),"<br />\n";
562 _upgrade_cached_html($dbh);
567 function _upgrade_db_init (&$dbh) {
568 global $request, $DBParams, $DBAuthParams;
569 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
572 // if need to connect as the root user, for CREATE and ALTER privileges
573 $AdminParams = $DBParams;
574 if ($DBParams['dbtype'] == 'SQL')
575 $dsn = DB::parseDSN($AdminParams['dsn']);
577 $dsn = parseDSN($AdminParams['dsn']);
578 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
584 $dbh = WikiDB::open($AdminParams);
585 } elseif ($dbadmin = $request->getArg('dbadmin')) {
586 if (empty($dbadmin['user']) or isset($dbadmin['cancel']))
587 $dbh = &$request->_dbi;
589 $AdminParams = $DBParams;
590 if ($DBParams['dbtype'] == 'SQL')
591 $dsn = DB::parseDSN($AdminParams['dsn']);
593 $dsn = parseDSN($AdminParams['dsn']);
594 $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
600 $dbh = WikiDB::open($AdminParams);
603 // Check if the privileges are enough. Need CREATE and ALTER perms.
604 // And on windows: SELECT FROM mysql, possibly: UPDATE mysql.
605 $form = HTML::form(array("method" => "post",
606 "action" => $request->getPostURL(),
607 "accept-charset"=>$GLOBALS['charset']),
608 HTML::p(_("Upgrade requires database privileges to CREATE and ALTER the phpwiki database."),
610 _("And on windows at least the privilege to SELECT FROM mysql, and possibly UPDATE mysql")),
611 HiddenInputs(array('action' => 'upgrade')),
612 HTML::table(array("cellspacing"=>4),
613 HTML::tr(HTML::td(array('align'=>'right'),
614 _("DB admin user:")),
615 HTML::td(HTML::input(array('name'=>"dbadmin[user]",
619 HTML::tr(HTML::td(array('align'=>'right'),
620 _("DB admin password:")),
621 HTML::td(HTML::input(array('name'=>"dbadmin[passwd]",
624 'maxlength'=>256)))),
625 HTML::tr(HTML::td(array('align'=>'center', 'colspan' => 2),
626 Button("submit:", _("Submit"), 'wikiaction'),
628 Button("submit:dbadmin[cancel]", _("Cancel"), 'button')))));
630 echo "</div><!-- content -->\n";
631 echo asXML(Template("bottom"));
632 echo "</body></html>\n";
639 * if page.cached_html does not exists:
640 * put _cached_html from pagedata into a new seperate blob, not huge serialized string.
642 * it is only rarelely needed: for current page only, if-not-modified
643 * but was extracetd for every simple page iteration.
645 function _upgrade_cached_html (&$dbh, $verbose=true) {
647 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
649 if (phpwiki_version() >= 1030.10) {
651 echo _("check for extra page.cached_html column")," ... ";
652 $database = $dbh->_backend->database();
653 extract($dbh->_backend->_table_names);
654 $fields = $dbh->_backend->listOfFields($database, $page_tbl);
655 if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
657 echo "<b>",_("ADDING"),"</b>"," ... ";
658 $backend_type = $dbh->_backend->backendType();
659 if (substr($backend_type,0,5) == 'mysql')
660 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
662 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
664 echo "<b>",_("CONVERTING"),"</b>"," ... ";
665 $count = _convert_cached_html($dbh);
667 echo $count, " ", _("OK"), "<br />\n";
670 echo _("OK"), "<br />\n";
677 * move _cached_html for all pages from pagedata into a new seperate blob.
678 * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
680 function _convert_cached_html (&$dbh) {
682 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
684 $pages = $dbh->getAllPages();
685 $cache =& $dbh->_cache;
687 extract($dbh->_backend->_table_names);
688 while ($page = $pages->next()) {
689 $pagename = $page->getName();
690 $data = $dbh->_backend->get_pagedata($pagename);
691 if (!empty($data['_cached_html'])) {
692 $cached_html = $data['_cached_html'];
693 $data['_cached_html'] = '';
694 $cache->update_pagedata($pagename, $data);
695 // store as blob, not serialized
696 $dbh->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
697 array($cached_html, $pagename));
704 function CheckPluginUpdate(&$request) {
705 echo "<h3>",_("check for necessary plugin argument updates"),"</h3>\n";
706 $process = array('msg' => _("change RandomPage pages => numpages"),
707 'match' => "/(<\?\s*plugin\s+ RandomPage\s+)pages/",
708 'replace' => "\\1numpages");
709 $dbi = $request->getDbh();
710 $allpages = $dbi->getAllPages(false);
711 while ($page = $allpages->next()) {
712 $current = $page->getCurrentRevision();
713 $pagetext = $current->getPackedContent();
714 foreach ($process as $p) {
715 if (preg_match($p['match'], $pagetext)) {
716 echo $page->getName()," ",$p['msg']," ... ";
717 if ($newtext = preg_replace($p['match'], $p['replace'], $pagetext)) {
718 $meta = $current->_data;
719 $meta['summary'] = "upgrade: ".$p['msg'];
720 $page->save($newtext, $current->getVersion() + 1, $meta);
721 echo _("OK"), "<br />\n";
723 echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
730 function fixConfigIni($match, $new) {
731 $file = FindFile("config/config.ini");
733 if (is_writable($file)) {
734 $in = fopen($file,"rb");
735 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
737 $tmp = str_replace("/","\\",$tmp);
738 while ($s = fgets($in)) {
739 if (preg_match($match, $s)) {
740 $s = $new . (isWindows() ? "\r\n" : "\n");
748 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
749 sprintf(_("%s not found"), $match);
752 @unlink("$file.bak");
753 @rename($file,"$file.bak");
754 if (rename($tmp, $file))
755 echo " <b>",_("FIXED"),"</b>";
757 echo " <b>",_("FAILED"),"</b>: ";
758 sprintf(_("couldn't move %s to %s"), $tmp, $file);
764 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
765 sprintf(_("%s is not writable"), $file);
770 function CheckConfigUpdate(&$request) {
771 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
772 echo _("check for old CACHE_CONTROL = NONE")," ... ";
773 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
774 echo "<br /> ",_("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'")," ...";
775 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
780 echo _("check for GROUP_METHOD = NONE")," ... ";
781 if (defined('GROUP_METHOD') and GROUP_METHOD == '') {
782 echo "<br /> ",_("GROUP_METHOD is set to NONE, and must be changed to \"NONE\"")," ...";
783 fixConfigIni("/^\s*GROUP_METHOD\s*=\s*NONE/","GROUP_METHOD = \"NONE\"");
793 * Upgrade: Base class for multipage worksteps
794 * identify, validate, display options, next step
800 class Upgrade_CheckPgsrc extends Upgrade {
803 class Upgrade_CheckDatabaseUpdate extends Upgrade {
807 // TODO: At which step are we?
808 // validate and do it again or go on with next step.
810 /** entry function from lib/main.php
812 function DoUpgrade($request) {
814 if (!$request->_user->isAdmin()) {
815 $request->_notAuthorized(WIKIAUTH_ADMIN);
817 HTML::div(array('class' => 'disabled-plugin'),
818 fmt("Upgrade disabled: user != isAdmin")));
822 StartLoadDump($request, _("Upgrading this PhpWiki"));
823 //CheckOldIndexUpdate($request); // to upgrade from < 1.3.10
824 CheckDatabaseUpdate($request); // first check cached_html and friends
825 CheckActionPageUpdate($request);
826 CheckPgsrcUpdate($request);
827 //CheckThemeUpdate($request);
828 //CheckPluginUpdate($request);
829 CheckConfigUpdate($request);
830 EndLoadDump($request);
835 $Log: not supported by cvs2svn $
836 Revision 1.41 2005/01/31 12:15:29 rurban
839 Revision 1.40 2005/01/30 23:22:17 rurban
842 Revision 1.39 2005/01/30 23:09:17 rurban
843 sanify session fields
845 Revision 1.38 2005/01/25 07:57:02 rurban
846 add dbadmin form, add mysql LOCK TABLES check, add plugin args updater (not yet activated)
848 Revision 1.37 2005/01/20 10:19:08 rurban
849 add InterWikiMap to special pages
851 Revision 1.36 2004/12/20 12:56:11 rurban
852 patch #1088128 by Kai Krakow. avoid chicken & egg problem
854 Revision 1.35 2004/12/13 14:35:41 rurban
857 Revision 1.34 2004/12/11 09:39:28 rurban
860 Revision 1.33 2004/12/10 22:33:39 rurban
861 add WikiAdminUtils method for convert-cached-html
864 Revision 1.32 2004/12/10 22:15:00 rurban
865 fix $page->get('_cached_html)
866 refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
867 support 2nd genericSqlQuery param (bind huge arg)
869 Revision 1.31 2004/12/10 02:45:26 rurban
871 put _cached_html from pagedata into a new seperate blob, not huge serialized string.
872 it is only rarelely needed: for current page only, if-not-modified
873 but was extracted for every simple page iteration.
875 Revision 1.30 2004/11/29 17:58:57 rurban
878 Revision 1.29 2004/11/29 16:08:31 rurban
881 Revision 1.28 2004/11/16 16:25:14 rurban
882 fix accesslog tablename, print CREATED only if really done
884 Revision 1.27 2004/11/07 16:02:52 rurban
885 new sql access log (for spam prevention), and restructured access log class
887 pear_db: mysql specific parts seperated (using replace)
889 Revision 1.26 2004/10/14 19:19:34 rurban
890 loadsave: check if the dumped file will be accessible from outside.
891 and some other minor fixes. (cvsclient native not yet ready)
893 Revision 1.25 2004/09/06 08:28:00 rurban
894 rename genericQuery to genericSqlQuery
896 Revision 1.24 2004/07/05 13:56:22 rurban
897 sqlite autoincrement fix
899 Revision 1.23 2004/07/04 10:28:06 rurban
902 Revision 1.22 2004/07/03 17:21:28 rurban
903 updated docs: submitted new mysql bugreport (#1491 did not fix it)
905 Revision 1.21 2004/07/03 16:51:05 rurban
906 optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
907 added atomic mysql REPLACE for PearDB as in ADODB
908 fixed _lock_tables typo links => link
909 fixes unserialize ADODB bug in line 180
911 Revision 1.20 2004/07/03 14:48:18 rurban
912 Tested new mysql 4.1.3-beta: binary search bug as fixed.
913 => fixed action=upgrade,
914 => version check in PearDB also (as in ADODB)
916 Revision 1.19 2004/06/19 12:19:09 rurban
917 slightly improved docs
919 Revision 1.18 2004/06/19 11:47:17 rurban
920 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
922 Revision 1.17 2004/06/17 11:31:50 rurban
923 check necessary localized actionpages
925 Revision 1.16 2004/06/16 10:38:58 rurban
926 Disallow refernces in calls if the declaration is a reference
927 ("allow_call_time_pass_reference clean").
928 PhpWiki is now allow_call_time_pass_reference = Off clean,
929 but several external libraries may not.
930 In detail these libs look to be affected (not tested):
934 Revision 1.15 2004/06/07 19:50:40 rurban
935 add owner field to mimified dump
937 Revision 1.14 2004/06/07 18:38:18 rurban
938 added mysql 4.1.x search fix
940 Revision 1.13 2004/06/04 20:32:53 rurban
941 Several locale related improvements suggested by Pierrick Meignen
942 LDAP fix by John Cole
943 reanable admin check without ENABLE_PAGEPERM in the admin plugins
945 Revision 1.12 2004/05/18 13:59:15 rurban
946 rename simpleQuery to genericSqlQuery
948 Revision 1.11 2004/05/15 13:06:17 rurban
949 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
951 Revision 1.10 2004/05/15 01:19:41 rurban
952 upgrade prefix fix by Kai Krakow
954 Revision 1.9 2004/05/14 11:33:03 rurban
955 version updated to 1.3.11pre
956 upgrade stability fix
958 Revision 1.8 2004/05/12 10:49:55 rurban
959 require_once fix for those libs which are loaded before FileFinder and
960 its automatic include_path fix, and where require_once doesn't grok
961 dirname(__FILE__) != './lib'
962 upgrade fix with PearDB
963 navbar.tmpl: remove spaces for IE button alignment
965 Revision 1.7 2004/05/06 17:30:38 rurban
966 CategoryGroup: oops, dos2unix eol
967 improved phpwiki_version:
968 pre -= .0001 (1.3.10pre: 1030.099)
969 -p1 += .001 (1.3.9-p1: 1030.091)
970 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
971 abstracted more ADODB/PearDB methods for action=upgrade stuff:
972 backend->backendType(), backend->database(),
973 backend->listOfFields(),
974 backend->listOfTables(),
976 Revision 1.6 2004/05/03 15:05:36 rurban
979 Revision 1.4 2004/05/02 21:26:38 rurban
980 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
981 because they will not survive db sessions, if too large.
982 extended action=upgrade
983 some WikiTranslation button work
984 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
985 some temp. session debug statements
987 Revision 1.3 2004/04/29 22:33:30 rurban
988 fixed sf.net bug #943366 (Kai Krakow)
989 couldn't load localized url-undecoded pagenames
991 Revision 1.2 2004/03/12 15:48:07 rurban
992 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
993 simplified lib/stdlib.php:explodePageList
1001 // c-basic-offset: 4
1002 // c-hanging-comment-ender-p: nil
1003 // indent-tabs-mode: nil