2 rcs_id('$Id: upgrade.php,v 1.18 2004-06-19 11:47:17 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,
30 * Installation on an existing PhpWiki database needs some
31 * additional worksteps. Each step will require multiple pages.
34 * 1. Check for new or changed database schema and update it
35 * according to some predefined upgrade tables. (medium)
36 * 2. Check for new or changed (localized) pgsrc/ pages and ask
37 * for upgrading these. Check timestamps, upgrade silently or
38 * show diffs if existing. Overwrite or merge (easy)
39 * 3. Check for new or changed or deprecated index.php settings
40 * and help in upgrading these. (hard)
41 * 4. Check for changed plugin invocation arguments. (hard)
42 * 5. Check for changed theme variables. (hard)
44 * @author: Reini Urban
46 require_once("lib/loadsave.php");
49 * TODO: check for the pgsrc_version number, not the revision
51 function doPgsrcUpdate(&$request,$pagename,$path,$filename) {
52 $dbi = $request->getDbh();
53 $page = $dbi->getPage($pagename);
54 if ($page->exists()) {
55 // check mtime: update automatically if pgsrc is newer
56 $rev = $page->getCurrentRevision();
57 $page_mtime = $rev->get('mtime');
58 $data = implode("", file($path."/".$filename));
59 if (($parts = ParseMimeifiedPages($data))) {
60 usort($parts, 'SortByPageVersion');
62 $pageinfo = $parts[0];
63 $stat = stat($path."/".$filename);
64 $new_mtime = @$pageinfo['versiondata']['mtime'];
66 $new_mtime = @$pageinfo['versiondata']['lastmodified'];
68 $new_mtime = @$pageinfo['pagedata']['date'];
70 $new_mtime = $stat[9];
71 if ($new_mtime > $page_mtime) {
72 echo "$path/$pagename: ",_("newer than the existing page."),
73 _(" replace "),"($new_mtime > $page_mtime)","<br />\n";
74 LoadAny($request,$path."/".$filename);
77 echo "$path/$pagename: ",_("older than the existing page."),
78 _(" skipped"),".<br />\n";
81 echo "$path/$pagename: ",("unknown format."),
82 _(" skipped"),".<br />\n";
85 echo sprintf(_("%s does not exist"),$pagename),"<br />\n";
86 LoadAny($request,$path."/".$filename);
91 /** need the english filename (required precondition: urlencode == urldecode)
92 * returns the plugin name.
94 function isActionPage($filename) {
95 static $special = array("DebugInfo" => "_BackendInfo",
96 "PhpWikiRecentChanges" => "RssFeed",
97 "ProjectSummary" => "RssFeed",
98 "RecentReleases" => "RssFeed",
100 $base = preg_replace("/\..{1,4}$/","",basename($filename));
101 if (isset($special[$base])) return $special[$base];
102 if (FindFile("lib/plugin/".$base.".php",true)) return $base;
106 function CheckActionPageUpdate(&$request) {
107 echo "<h3>",_("check for necessary ActionPage updates"),"</h3>\n";
108 $dbi = $request->getDbh();
109 $path = FindFile('pgsrc');
110 $pgsrc = new fileSet($path);
111 // most actionpages have the same name as the plugin
112 $loc_path = FindLocalizedFile('pgsrc');
113 foreach ($pgsrc->getFiles() as $filename) {
114 if (substr($filename,-1,1) == '~') continue;
115 $pagename = urldecode($filename);
116 if (isActionPage($filename)) {
117 $translation = gettext($pagename);
118 if ($translation == $pagename)
119 doPgsrcUpdate($request, $pagename, $path, $filename);
120 elseif (FindLocalizedFile('pgsrc/'.urlencode($translation),1))
121 doPgsrcUpdate($request, $translation, $loc_path,
122 urlencode($translation));
124 doPgsrcUpdate($request, $pagename, $path, $filename);
129 // see loadsave.php for saving new pages.
130 function CheckPgsrcUpdate(&$request) {
131 echo "<h3>",_("check for necessary pgsrc updates"),"</h3>\n";
132 $dbi = $request->getDbh();
133 $path = FindLocalizedFile(WIKI_PGSRC);
134 $pgsrc = new fileSet($path);
135 // fixme: verification, ...
137 foreach ($pgsrc->getFiles() as $filename) {
138 if (substr($filename,-1,1) == '~') continue;
139 $pagename = urldecode($filename);
140 // don't ever update the HomePage
141 if (defined(HOME_PAGE))
142 if ($pagename == HOME_PAGE) $isHomePage = true;
144 if ($pagename == _("HomePage")) $isHomePage = true;
145 if ($pagename == "HomePage") $isHomePage = true;
147 echo "$path/$pagename: ",_("always skip the HomePage."),
148 _(" skipped"),".<br />\n";
152 if (!isActionPage($filename)) {
153 doPgsrcUpdate($request,$pagename,$path,$filename);
160 * TODO: Search table definition in appropriate schema
162 * Supported: mysql and generic SQL, for ADODB and PearDB.
164 function installTable(&$dbh, $table, $backend_type) {
166 if (!in_array($DBParams['dbtype'],array('SQL','ADODB'))) return;
167 echo _("MISSING")," ... \n";
168 $backend = &$dbh->_backend->_dbh;
170 $schema = findFile("schemas/${backend_type}.sql");
172 echo " ",_("FAILED"),": ",sprintf(_("no schema %s found"),"schemas/${backend_type}.sql")," ... <br />\n";
176 extract($dbh->_backend->_table_names);
177 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
180 assert($session_tbl);
181 if ($backend_type == 'mysql') {
183 CREATE TABLE $session_tbl (
184 sess_id CHAR(32) NOT NULL DEFAULT '',
185 sess_data BLOB NOT NULL,
186 sess_date INT UNSIGNED NOT NULL,
187 sess_ip CHAR(15) NOT NULL,
188 PRIMARY KEY (sess_id),
193 CREATE TABLE $session_tbl (
194 sess_id CHAR(32) NOT NULL DEFAULT '',
195 sess_data ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
197 sess_ip CHAR(15) NOT NULL
199 $dbh->genericQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
201 $dbh->genericQuery("CREATE INDEX sess_date on session (sess_date)");
204 $user_tbl = $prefix.'user';
205 if ($backend_type == 'mysql') {
207 CREATE TABLE $user_tbl (
208 userid CHAR(48) BINARY NOT NULL UNIQUE,
209 passwd CHAR(48) BINARY DEFAULT '',
214 CREATE TABLE $user_tbl (
215 userid CHAR(48) NOT NULL,
216 passwd CHAR(48) DEFAULT ''
218 $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
222 $pref_tbl = $prefix.'pref';
223 if ($backend_type == 'mysql') {
225 CREATE TABLE $pref_tbl (
226 userid CHAR(48) BINARY NOT NULL UNIQUE,
227 prefs TEXT NULL DEFAULT '',
232 CREATE TABLE $pref_tbl (
233 userid CHAR(48) NOT NULL,
234 prefs TEXT NULL DEFAULT '',
236 $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
240 $member_tbl = $prefix.'member';
241 if ($backend_type == 'mysql') {
243 CREATE TABLE $member_tbl (
244 userid CHAR(48) BINARY NOT NULL,
245 groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
251 CREATE TABLE $member_tbl (
252 userid CHAR(48) NOT NULL,
253 groupname CHAR(48) NOT NULL DEFAULT 'users',
255 $dbh->genericQuery("CREATE INDEX userid ON $member_tbl (userid)");
256 $dbh->genericQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
260 $rating_tbl = $prefix.'rating';
261 if ($backend_type == 'mysql') {
263 CREATE TABLE $rating_tbl (
264 dimension INT(4) NOT NULL,
265 raterpage INT(11) NOT NULL,
266 rateepage INT(11) NOT NULL,
267 ratingvalue FLOAT NOT NULL,
268 rateeversion INT(11) NOT NULL,
269 tstamp TIMESTAMP(14) NOT NULL,
270 PRIMARY KEY (dimension, raterpage, rateepage)
274 CREATE TABLE $rating_tbl (
275 dimension INT(4) NOT NULL,
276 raterpage INT(11) NOT NULL,
277 rateepage INT(11) NOT NULL,
278 ratingvalue FLOAT NOT NULL,
279 rateeversion INT(11) NOT NULL,
280 tstamp TIMESTAMP(14) NOT NULL,
282 $dbh->genericQuery("CREATE UNIQUE INDEX rating ON $rating_tbl (dimension, raterpage, rateepage)");
286 echo " ",_("CREATED"),"<br />\n";
290 * currently update only session, user, pref and member
291 * jeffs-hacks database api (around 1.3.2) later
292 * people should export/import their pages if using that old versions.
294 function CheckDatabaseUpdate(&$request) {
295 global $DBParams, $DBAuthParams;
296 if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
297 echo "<h3>",_("check for necessary database updates"),"</h3>\n";
298 $dbh = &$request->_dbi;
299 $tables = $dbh->_backend->listOfTables();
300 $backend_type = $dbh->_backend->backendType();
301 $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
302 extract($dbh->_backend->_table_names);
303 foreach (explode(':','session:user:pref:member') as $table) {
304 echo sprintf(_("check for table %s"), $table)," ...";
305 if (!in_array($prefix.$table, $tables)) {
306 installTable($dbh, $table, $backend_type);
308 echo _("OK")," <br />\n";
311 $backend = &$dbh->_backend->_dbh;
312 // 1.3.8 added session.sess_ip
313 if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
314 echo _("check for new session.sess_ip column")," ... ";
315 $database = $dbh->_backend->database();
316 assert(!empty($DBParams['db_session_table']));
317 $session_tbl = $prefix . $DBParams['db_session_table'];
318 $sess_fields = $dbh->_backend->listOfFields($database, $session_tbl);
319 if (!strstr(strtolower(join(':', $sess_fields)),"sess_ip")) {
320 echo "<b>",_("ADDING"),"</b>"," ... ";
321 $dbh->genericQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
327 // 1.3.10 mysql requires page.id auto_increment
328 // mysql, mysqli or mysqlt
329 if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql') {
330 echo _("check for page.id auto_increment flag")," ...";
331 assert(!empty($page_tbl));
332 $database = $dbh->_backend->database();
333 $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
334 $columns = mysql_num_fields($fields);
335 for ($i = 0; $i < $columns; $i++) {
336 if (mysql_field_name($fields, $i) == 'id') {
337 $flags = mysql_field_flags($fields, $i);
338 //FIXME: something wrong with ADODB here!
339 if (!strstr(strtolower($flags),"auto_increment")) {
340 echo "<b>",_("ADDING"),"</b>"," ... ";
341 // MODIFY col_def valid since mysql 3.22.16,
342 // older mysql's need CHANGE old_col col_def
343 $dbh->genericQuery("ALTER TABLE $page_tbl CHANGE id id INT NOT NULL AUTO_INCREMENT");
344 $fields = mysql_list_fields($database, $page_tbl);
345 if (!strstr(strtolower(mysql_field_flags($fields, $i)),"auto_increment"))
346 echo " <b><font color=\"red\">",_("FAILED"),"</font></b><br />\n";
348 echo _("OK"),"<br />\n";
350 echo _("OK"),"<br />\n";
355 mysql_free_result($fields);
357 // check for mysql 4.1.x binary search bug
358 // http://bugs.mysql.com/bug.php?id=1491
359 // not yet tested for 4.1.2alpha, but confirmed for 4.1.0alpha
360 if (substr($backend_type,0,5) == 'mysql') {
361 echo _("check for mysql 4.1.x binary search bug")," ...";
362 $result = mysql_query("SELECT VERSION()",$dbh->_backend->connection());
363 $row = mysql_fetch_row($result);
364 $mysql_version = $row[0];
365 $arr = explode('.',$mysql_version);
366 $version = (string)(($arr[0] * 100) + $arr[1]) . "." . $arr[2];
367 if ($version > 410.0 and $version < 420.0) {
368 $dbh->genericQuery("ALTER TABLE $page_tbl CHANGE pagename pagename VARCHAR(100) NOT NULL;");
369 echo sprintf(_("version <em>%s</em> <b>FIXED</b>"), $mysql_version),"<br />\n";
371 echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
377 function fixConfigIni($match, $new) {
378 $file = FindFile("config/config.ini");
380 if (is_writable($file)) {
381 $in = fopen($file,"rb");
382 $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
384 $tmp = str_replace("/","\\",$tmp);
385 while ($s = fgets($in)) {
386 if (preg_match($match, $s)) {
387 $s = $new . (isWindows() ? "\r\n" : "\n");
395 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
396 sprintf(_("%s not found"), $match);
399 @unlink("$file.bak");
400 @rename($file,"$file.bak");
401 if (rename($tmp, $file))
402 echo " <b>",_("FIXED"),"</b>";
404 echo " <b>",_("FAILED"),"</b>: ";
405 sprintf(_("couldn't move %s to %s"), $tmp, $file);
411 echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
412 sprintf(_("%s is not writable"), $file);
417 function CheckConfigUpdate(&$request) {
418 echo "<h3>",_("check for necessary config updates"),"</h3>\n";
419 echo _("check for old CACHE_CONTROL = NONE")," ... ";
420 if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
421 echo "<br /> ",_("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'")," ...";
422 fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
430 * Upgrade: Base class for multipage worksteps
431 * identify, validate, display options, next step
436 class Upgrade_CheckPgsrc extends Upgrade {
439 class Upgrade_CheckDatabaseUpdate extends Upgrade {
442 // TODO: At which step are we?
443 // validate and do it again or go on with next step.
445 /** entry function from lib/main.php
447 function DoUpgrade($request) {
449 if (!$request->_user->isAdmin()) {
450 $request->_notAuthorized(WIKIAUTH_ADMIN);
452 HTML::div(array('class' => 'disabled-plugin'),
453 fmt("Upgrade disabled: user != isAdmin")));
457 StartLoadDump($request, _("Upgrading this PhpWiki"));
458 CheckActionPageUpdate($request);
459 CheckDatabaseUpdate($request);
460 CheckPgsrcUpdate($request);
461 //CheckThemeUpdate($request);
462 CheckConfigUpdate($request);
463 EndLoadDump($request);
468 $Log: not supported by cvs2svn $
469 Revision 1.17 2004/06/17 11:31:50 rurban
470 check necessary localized actionpages
472 Revision 1.16 2004/06/16 10:38:58 rurban
473 Disallow refernces in calls if the declaration is a reference
474 ("allow_call_time_pass_reference clean").
475 PhpWiki is now allow_call_time_pass_reference = Off clean,
476 but several external libraries may not.
477 In detail these libs look to be affected (not tested):
481 Revision 1.15 2004/06/07 19:50:40 rurban
482 add owner field to mimified dump
484 Revision 1.14 2004/06/07 18:38:18 rurban
485 added mysql 4.1.x search fix
487 Revision 1.13 2004/06/04 20:32:53 rurban
488 Several locale related improvements suggested by Pierrick Meignen
489 LDAP fix by John Cole
490 reanable admin check without ENABLE_PAGEPERM in the admin plugins
492 Revision 1.12 2004/05/18 13:59:15 rurban
493 rename simpleQuery to genericQuery
495 Revision 1.11 2004/05/15 13:06:17 rurban
496 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
498 Revision 1.10 2004/05/15 01:19:41 rurban
499 upgrade prefix fix by Kai Krakow
501 Revision 1.9 2004/05/14 11:33:03 rurban
502 version updated to 1.3.11pre
503 upgrade stability fix
505 Revision 1.8 2004/05/12 10:49:55 rurban
506 require_once fix for those libs which are loaded before FileFinder and
507 its automatic include_path fix, and where require_once doesn't grok
508 dirname(__FILE__) != './lib'
509 upgrade fix with PearDB
510 navbar.tmpl: remove spaces for IE button alignment
512 Revision 1.7 2004/05/06 17:30:38 rurban
513 CategoryGroup: oops, dos2unix eol
514 improved phpwiki_version:
515 pre -= .0001 (1.3.10pre: 1030.099)
516 -p1 += .001 (1.3.9-p1: 1030.091)
517 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
518 abstracted more ADODB/PearDB methods for action=upgrade stuff:
519 backend->backendType(), backend->database(),
520 backend->listOfFields(),
521 backend->listOfTables(),
523 Revision 1.6 2004/05/03 15:05:36 rurban
526 Revision 1.4 2004/05/02 21:26:38 rurban
527 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
528 because they will not survive db sessions, if too large.
529 extended action=upgrade
530 some WikiTranslation button work
531 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
532 some temp. session debug statements
534 Revision 1.3 2004/04/29 22:33:30 rurban
535 fixed sf.net bug #943366 (Kai Krakow)
536 couldn't load localized url-undecoded pagenames
538 Revision 1.2 2004/03/12 15:48:07 rurban
539 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
540 simplified lib/stdlib.php:explodePageList
549 // c-hanging-comment-ender-p: nil
550 // indent-tabs-mode: nil