2 rcs_id('$Id: upgrade.php,v 1.19 2004-06-19 12:19:09 rurban Exp $');
5 Copyright 2004 $ThePhpWikiProgrammingTeam
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
20 along with PhpWiki; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Upgrade the WikiDB and config settings after installing a new
28 * Status: experimental, no queries for verification yet, no db update,
31 * Installation on an existing PhpWiki database needs some
32 * additional worksteps. Each step will require multiple pages.
35 * 1. Check for new or changed database schema and update it
36 * according to some predefined upgrade tables. (medium)
37 * 2. Check for new or changed (localized) pgsrc/ pages and ask
38 * for upgrading these. Check timestamps, upgrade silently or
39 * show diffs if existing. Overwrite or merge (easy)
40 * 3. Check for new or changed or deprecated index.php/config.ini settings
41 * and help in upgrading these. (hard)
42 * 3a Convert old-style index.php into config/config.ini. (easy)
43 * 4. Check for changed plugin invocation arguments. (hard)
44 * 5. Check for changed theme variables. (hard)
45 * 6. Convert the automatic update to a class-based multi-page
48 * @author: Reini Urban
50 require_once("lib/loadsave.php");
53 * TODO: check for the pgsrc_version number, not the revision
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",
104 $base = preg_replace("/\..{1,4}$/","",basename($filename));
105 if (isset($special[$base])) return $special[$base];
106 if (FindFile("lib/plugin/".$base.".php",true)) return $base;
110 function CheckActionPageUpdate(&$request) {
111 echo "<h3>",_("check for necessary ActionPage updates"),"</h3>\n";
112 $dbi = $request->getDbh();
113 $path = FindFile('pgsrc');
114 $pgsrc = new fileSet($path);
115 // most actionpages have the same name as the plugin
116 $loc_path = FindLocalizedFile('pgsrc');
117 foreach ($pgsrc->getFiles() as $filename) {
118 if (substr($filename,-1,1) == '~') continue;
119 $pagename = urldecode($filename);
120 if (isActionPage($filename)) {
121 $translation = gettext($pagename);
122 if ($translation == $pagename)
123 doPgsrcUpdate($request, $pagename, $path, $filename);
124 elseif (FindLocalizedFile('pgsrc/'.urlencode($translation),1))
125 doPgsrcUpdate($request, $translation, $loc_path,
126 urlencode($translation));
128 doPgsrcUpdate($request, $pagename, $path, $filename);
133 // see loadsave.php for saving new pages.
134 function CheckPgsrcUpdate(&$request) {
135 echo "<h3>",_("check for necessary pgsrc updates"),"</h3>\n";
136 $dbi = $request->getDbh();
137 $path = FindLocalizedFile(WIKI_PGSRC);
138 $pgsrc = new fileSet($path);
139 // fixme: verification, ...
141 foreach ($pgsrc->getFiles() as $filename) {
142 if (substr($filename,-1,1) == '~') continue;
143 $pagename = urldecode($filename);
144 // don't ever update the HomePage
145 if (defined(HOME_PAGE))
146 if ($pagename == HOME_PAGE) $isHomePage = true;
148 if ($pagename == _("HomePage")) $isHomePage = true;
149 if ($pagename == "HomePage") $isHomePage = true;
151 echo "$path/$pagename: ",_("always skip the HomePage."),
152 _(" skipped"),".<br />\n";
156 if (!isActionPage($filename)) {
157 doPgsrcUpdate($request,$pagename,$path,$filename);
164 * TODO: Search table definition in appropriate schema
166 * Supported: mysql and generic SQL, for ADODB and PearDB.
168 function installTable(&$dbh, $table, $backend_type) {
170 if (!in_array($DBParams['dbtype'],array('SQL','ADODB'))) return;
171 echo _("MISSING")," ... \n";
172 $backend = &$dbh->_backend->_dbh;
174 $schema = findFile("schemas/${backend_type}.sql");
176 echo " ",_("FAILED"),": ",sprintf(_("no schema %s found"),"schemas/${backend_type}.sql")," ... <br />\n";
180 extract($dbh->_backend->_table_names);
181 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
184 assert($session_tbl);
185 if ($backend_type == 'mysql') {
187 CREATE TABLE $session_tbl (
188 sess_id CHAR(32) NOT NULL DEFAULT '',
189 sess_data BLOB NOT NULL,
190 sess_date INT UNSIGNED NOT NULL,
191 sess_ip CHAR(15) NOT NULL,
192 PRIMARY KEY (sess_id),
197 CREATE TABLE $session_tbl (
198 sess_id CHAR(32) NOT NULL DEFAULT '',
199 sess_data ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
201 sess_ip CHAR(15) NOT NULL
203 $dbh->genericQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
205 $dbh->genericQuery("CREATE INDEX sess_date on session (sess_date)");
208 $user_tbl = $prefix.'user';
209 if ($backend_type == 'mysql') {
211 CREATE TABLE $user_tbl (
212 userid CHAR(48) BINARY NOT NULL UNIQUE,
213 passwd CHAR(48) BINARY DEFAULT '',
218 CREATE TABLE $user_tbl (
219 userid CHAR(48) NOT NULL,
220 passwd CHAR(48) DEFAULT ''
222 $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
226 $pref_tbl = $prefix.'pref';
227 if ($backend_type == 'mysql') {
229 CREATE TABLE $pref_tbl (
230 userid CHAR(48) BINARY NOT NULL UNIQUE,
231 prefs TEXT NULL DEFAULT '',
236 CREATE TABLE $pref_tbl (
237 userid CHAR(48) NOT NULL,
238 prefs TEXT NULL DEFAULT '',
240 $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
244 $member_tbl = $prefix.'member';
245 if ($backend_type == 'mysql') {
247 CREATE TABLE $member_tbl (
248 userid CHAR(48) BINARY NOT NULL,
249 groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
255 CREATE TABLE $member_tbl (
256 userid CHAR(48) NOT NULL,
257 groupname CHAR(48) NOT NULL DEFAULT 'users',
259 $dbh->genericQuery("CREATE INDEX userid ON $member_tbl (userid)");
260 $dbh->genericQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
264 $rating_tbl = $prefix.'rating';
265 if ($backend_type == 'mysql') {
267 CREATE TABLE $rating_tbl (
268 dimension INT(4) NOT NULL,
269 raterpage INT(11) NOT NULL,
270 rateepage INT(11) NOT NULL,
271 ratingvalue FLOAT NOT NULL,
272 rateeversion INT(11) NOT NULL,
273 tstamp TIMESTAMP(14) NOT NULL,
274 PRIMARY KEY (dimension, raterpage, rateepage)
278 CREATE TABLE $rating_tbl (
279 dimension INT(4) NOT NULL,
280 raterpage INT(11) NOT NULL,
281 rateepage INT(11) NOT NULL,
282 ratingvalue FLOAT NOT NULL,
283 rateeversion INT(11) NOT NULL,
284 tstamp TIMESTAMP(14) NOT NULL,
286 $dbh->genericQuery("CREATE UNIQUE INDEX rating ON $rating_tbl (dimension, raterpage, rateepage)");
290 echo " ",_("CREATED"),"<br />\n";
294 * currently update only session, user, pref and member
295 * jeffs-hacks database api (around 1.3.2) later
296 * people should export/import their pages if using that old versions.
298 function CheckDatabaseUpdate(&$request) {
299 global $DBParams, $DBAuthParams;
300 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
301 echo "<h3>",_("check for necessary database updates"),"</h3>\n";
302 $dbh = &$request->_dbi;
303 $tables = $dbh->_backend->listOfTables();
304 $backend_type = $dbh->_backend->backendType();
305 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
306 extract($dbh->_backend->_table_names);
307 foreach (explode(':','session:user:pref:member') as $table) {
308 echo sprintf(_("check for table %s"), $table)," ...";
309 if (!in_array($prefix.$table, $tables)) {
310 installTable($dbh, $table, $backend_type);
312 echo _("OK")," <br />\n";
315 $backend = &$dbh->_backend->_dbh;
316 // 1.3.8 added session.sess_ip
317 if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
318 echo _("check for new session.sess_ip column")," ... ";
319 $database = $dbh->_backend->database();
320 assert(!empty($DBParams['db_session_table']));
321 $session_tbl = $prefix . $DBParams['db_session_table'];
322 $sess_fields = $dbh->_backend->listOfFields($database, $session_tbl);
323 if (!strstr(strtolower(join(':', $sess_fields)),"sess_ip")) {
324 echo "<b>",_("ADDING"),"</b>"," ... ";
325 $dbh->genericQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
331 // 1.3.10 mysql requires page.id auto_increment
332 // mysql, mysqli or mysqlt
333 if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql') {
334 echo _("check for page.id auto_increment flag")," ...";
335 assert(!empty($page_tbl));
336 $database = $dbh->_backend->database();
337 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
338 $columns = mysql_num_fields($fields);
339 for ($i = 0; $i < $columns; $i++) {
340 if (mysql_field_name($fields, $i) == 'id') {
341 $flags = mysql_field_flags($fields, $i);
342 //FIXME: something wrong with ADODB here!
343 if (!strstr(strtolower($flags),"auto_increment")) {
344 echo "<b>",_("ADDING"),"</b>"," ... ";
345 // MODIFY col_def valid since mysql 3.22.16,
346 // older mysql's need CHANGE old_col col_def
347 $dbh->genericQuery("ALTER TABLE $page_tbl CHANGE id id INT NOT NULL AUTO_INCREMENT");
348 $fields = mysql_list_fields($database, $page_tbl);
349 if (!strstr(strtolower(mysql_field_flags($fields, $i)),"auto_increment"))
350 echo " <b><font color=\"red\">",_("FAILED"),"</font></b><br />\n";
352 echo _("OK"),"<br />\n";
354 echo _("OK"),"<br />\n";
359 mysql_free_result($fields);
361 // check for mysql 4.1.x binary search bug
362 // http://bugs.mysql.com/bug.php?id=1491
363 // not yet tested for 4.1.2alpha, but confirmed for 4.1.0alpha
364 if (substr($backend_type,0,5) == 'mysql') {
365 echo _("check for mysql 4.1.x binary search bug")," ...";
366 $result = mysql_query("SELECT VERSION()",$dbh->_backend->connection());
367 $row = mysql_fetch_row($result);
368 $mysql_version = $row[0];
369 $arr = explode('.',$mysql_version);
370 $version = (string)(($arr[0] * 100) + $arr[1]) . "." . $arr[2];
371 if ($version > 410.0 and $version < 420.0) {
372 $dbh->genericQuery("ALTER TABLE $page_tbl CHANGE pagename pagename VARCHAR(100) NOT NULL;");
373 echo sprintf(_("version <em>%s</em> <b>FIXED</b>"), $mysql_version),"<br />\n";
375 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
381 function fixConfigIni($match, $new) {
382 $file = FindFile("config/config.ini");
384 if (is_writable($file)) {
385 $in = fopen($file,"rb");
386 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
388 $tmp = str_replace("/","\\",$tmp);
389 while ($s = fgets($in)) {
390 if (preg_match($match, $s)) {
391 $s = $new . (isWindows() ? "\r\n" : "\n");
399 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
400 sprintf(_("%s not found"), $match);
403 @unlink("$file.bak");
404 @rename($file,"$file.bak");
405 if (rename($tmp, $file))
406 echo " <b>",_("FIXED"),"</b>";
408 echo " <b>",_("FAILED"),"</b>: ";
409 sprintf(_("couldn't move %s to %s"), $tmp, $file);
415 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
416 sprintf(_("%s is not writable"), $file);
421 function CheckConfigUpdate(&$request) {
422 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
423 echo _("check for old CACHE_CONTROL = NONE")," ... ";
424 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
425 echo "<br /> ",_("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'")," ...";
426 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
436 * Upgrade: Base class for multipage worksteps
437 * identify, validate, display options, next step
442 class Upgrade_CheckPgsrc extends Upgrade {
445 class Upgrade_CheckDatabaseUpdate extends Upgrade {
448 // TODO: At which step are we?
449 // validate and do it again or go on with next step.
451 /** entry function from lib/main.php
453 function DoUpgrade($request) {
455 if (!$request->_user->isAdmin()) {
456 $request->_notAuthorized(WIKIAUTH_ADMIN);
458 HTML::div(array('class' => 'disabled-plugin'),
459 fmt("Upgrade disabled: user != isAdmin")));
463 StartLoadDump($request, _("Upgrading this PhpWiki"));
464 CheckActionPageUpdate($request);
465 CheckDatabaseUpdate($request);
466 CheckPgsrcUpdate($request);
467 //CheckThemeUpdate($request);
468 CheckConfigUpdate($request);
469 EndLoadDump($request);
474 $Log: not supported by cvs2svn $
475 Revision 1.18 2004/06/19 11:47:17 rurban
476 added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
478 Revision 1.17 2004/06/17 11:31:50 rurban
479 check necessary localized actionpages
481 Revision 1.16 2004/06/16 10:38:58 rurban
482 Disallow refernces in calls if the declaration is a reference
483 ("allow_call_time_pass_reference clean").
484 PhpWiki is now allow_call_time_pass_reference = Off clean,
485 but several external libraries may not.
486 In detail these libs look to be affected (not tested):
490 Revision 1.15 2004/06/07 19:50:40 rurban
491 add owner field to mimified dump
493 Revision 1.14 2004/06/07 18:38:18 rurban
494 added mysql 4.1.x search fix
496 Revision 1.13 2004/06/04 20:32:53 rurban
497 Several locale related improvements suggested by Pierrick Meignen
498 LDAP fix by John Cole
499 reanable admin check without ENABLE_PAGEPERM in the admin plugins
501 Revision 1.12 2004/05/18 13:59:15 rurban
502 rename simpleQuery to genericQuery
504 Revision 1.11 2004/05/15 13:06:17 rurban
505 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
507 Revision 1.10 2004/05/15 01:19:41 rurban
508 upgrade prefix fix by Kai Krakow
510 Revision 1.9 2004/05/14 11:33:03 rurban
511 version updated to 1.3.11pre
512 upgrade stability fix
514 Revision 1.8 2004/05/12 10:49:55 rurban
515 require_once fix for those libs which are loaded before FileFinder and
516 its automatic include_path fix, and where require_once doesn't grok
517 dirname(__FILE__) != './lib'
518 upgrade fix with PearDB
519 navbar.tmpl: remove spaces for IE button alignment
521 Revision 1.7 2004/05/06 17:30:38 rurban
522 CategoryGroup: oops, dos2unix eol
523 improved phpwiki_version:
524 pre -= .0001 (1.3.10pre: 1030.099)
525 -p1 += .001 (1.3.9-p1: 1030.091)
526 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
527 abstracted more ADODB/PearDB methods for action=upgrade stuff:
528 backend->backendType(), backend->database(),
529 backend->listOfFields(),
530 backend->listOfTables(),
532 Revision 1.6 2004/05/03 15:05:36 rurban
535 Revision 1.4 2004/05/02 21:26:38 rurban
536 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
537 because they will not survive db sessions, if too large.
538 extended action=upgrade
539 some WikiTranslation button work
540 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
541 some temp. session debug statements
543 Revision 1.3 2004/04/29 22:33:30 rurban
544 fixed sf.net bug #943366 (Kai Krakow)
545 couldn't load localized url-undecoded pagenames
547 Revision 1.2 2004/03/12 15:48:07 rurban
548 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
549 simplified lib/stdlib.php:explodePageList
558 // c-hanging-comment-ender-p: nil
559 // indent-tabs-mode: nil