2 rcs_id('$Id: upgrade.php,v 1.40 2005-01-30 23:22:17 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) ";
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,
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 latin1 COLLATE latin1_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.39 2005/01/30 23:09:17 rurban
837 sanify session fields
839 Revision 1.38 2005/01/25 07:57:02 rurban
840 add dbadmin form, add mysql LOCK TABLES check, add plugin args updater (not yet activated)
842 Revision 1.37 2005/01/20 10:19:08 rurban
843 add InterWikiMap to special pages
845 Revision 1.36 2004/12/20 12:56:11 rurban
846 patch #1088128 by Kai Krakow. avoid chicken & egg problem
848 Revision 1.35 2004/12/13 14:35:41 rurban
851 Revision 1.34 2004/12/11 09:39:28 rurban
854 Revision 1.33 2004/12/10 22:33:39 rurban
855 add WikiAdminUtils method for convert-cached-html
858 Revision 1.32 2004/12/10 22:15:00 rurban
859 fix $page->get('_cached_html)
860 refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
861 support 2nd genericSqlQuery param (bind huge arg)
863 Revision 1.31 2004/12/10 02:45:26 rurban
865 put _cached_html from pagedata into a new seperate blob, not huge serialized string.
866 it is only rarelely needed: for current page only, if-not-modified
867 but was extracted for every simple page iteration.
869 Revision 1.30 2004/11/29 17:58:57 rurban
872 Revision 1.29 2004/11/29 16:08:31 rurban
875 Revision 1.28 2004/11/16 16:25:14 rurban
876 fix accesslog tablename, print CREATED only if really done
878 Revision 1.27 2004/11/07 16:02:52 rurban
879 new sql access log (for spam prevention), and restructured access log class
881 pear_db: mysql specific parts seperated (using replace)
883 Revision 1.26 2004/10/14 19:19:34 rurban
884 loadsave: check if the dumped file will be accessible from outside.
885 and some other minor fixes. (cvsclient native not yet ready)
887 Revision 1.25 2004/09/06 08:28:00 rurban
888 rename genericQuery to genericSqlQuery
890 Revision 1.24 2004/07/05 13:56:22 rurban
891 sqlite autoincrement fix
893 Revision 1.23 2004/07/04 10:28:06 rurban
896 Revision 1.22 2004/07/03 17:21:28 rurban
897 updated docs: submitted new mysql bugreport (#1491 did not fix it)
899 Revision 1.21 2004/07/03 16:51:05 rurban
900 optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
901 added atomic mysql REPLACE for PearDB as in ADODB
902 fixed _lock_tables typo links => link
903 fixes unserialize ADODB bug in line 180
905 Revision 1.20 2004/07/03 14:48:18 rurban
906 Tested new mysql 4.1.3-beta: binary search bug as fixed.
907 => fixed action=upgrade,
908 => version check in PearDB also (as in ADODB)
910 Revision 1.19 2004/06/19 12:19:09 rurban
911 slightly improved docs
913 Revision 1.18 2004/06/19 11:47:17 rurban
914 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
916 Revision 1.17 2004/06/17 11:31:50 rurban
917 check necessary localized actionpages
919 Revision 1.16 2004/06/16 10:38:58 rurban
920 Disallow refernces in calls if the declaration is a reference
921 ("allow_call_time_pass_reference clean").
922 PhpWiki is now allow_call_time_pass_reference = Off clean,
923 but several external libraries may not.
924 In detail these libs look to be affected (not tested):
928 Revision 1.15 2004/06/07 19:50:40 rurban
929 add owner field to mimified dump
931 Revision 1.14 2004/06/07 18:38:18 rurban
932 added mysql 4.1.x search fix
934 Revision 1.13 2004/06/04 20:32:53 rurban
935 Several locale related improvements suggested by Pierrick Meignen
936 LDAP fix by John Cole
937 reanable admin check without ENABLE_PAGEPERM in the admin plugins
939 Revision 1.12 2004/05/18 13:59:15 rurban
940 rename simpleQuery to genericSqlQuery
942 Revision 1.11 2004/05/15 13:06:17 rurban
943 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
945 Revision 1.10 2004/05/15 01:19:41 rurban
946 upgrade prefix fix by Kai Krakow
948 Revision 1.9 2004/05/14 11:33:03 rurban
949 version updated to 1.3.11pre
950 upgrade stability fix
952 Revision 1.8 2004/05/12 10:49:55 rurban
953 require_once fix for those libs which are loaded before FileFinder and
954 its automatic include_path fix, and where require_once doesn't grok
955 dirname(__FILE__) != './lib'
956 upgrade fix with PearDB
957 navbar.tmpl: remove spaces for IE button alignment
959 Revision 1.7 2004/05/06 17:30:38 rurban
960 CategoryGroup: oops, dos2unix eol
961 improved phpwiki_version:
962 pre -= .0001 (1.3.10pre: 1030.099)
963 -p1 += .001 (1.3.9-p1: 1030.091)
964 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
965 abstracted more ADODB/PearDB methods for action=upgrade stuff:
966 backend->backendType(), backend->database(),
967 backend->listOfFields(),
968 backend->listOfTables(),
970 Revision 1.6 2004/05/03 15:05:36 rurban
973 Revision 1.4 2004/05/02 21:26:38 rurban
974 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
975 because they will not survive db sessions, if too large.
976 extended action=upgrade
977 some WikiTranslation button work
978 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
979 some temp. session debug statements
981 Revision 1.3 2004/04/29 22:33:30 rurban
982 fixed sf.net bug #943366 (Kai Krakow)
983 couldn't load localized url-undecoded pagenames
985 Revision 1.2 2004/03/12 15:48:07 rurban
986 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
987 simplified lib/stdlib.php:explodePageList
996 // c-hanging-comment-ender-p: nil
997 // indent-tabs-mode: nil