2 rcs_id('$Id: upgrade.php,v 1.17 2004-06-17 11:31:50 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";
378 * Upgrade: Base class for multipage worksteps
379 * identify, validate, display options, next step
384 class Upgrade_CheckPgsrc extends Upgrade {
387 class Upgrade_CheckDatabaseUpdate extends Upgrade {
390 // TODO: At which step are we?
391 // validate and do it again or go on with next step.
393 /** entry function from lib/main.php
395 function DoUpgrade($request) {
397 if (!$request->_user->isAdmin()) {
398 $request->_notAuthorized(WIKIAUTH_ADMIN);
400 HTML::div(array('class' => 'disabled-plugin'),
401 fmt("Upgrade disabled: user != isAdmin")));
405 StartLoadDump($request, _("Upgrading this PhpWiki"));
406 CheckActionPageUpdate($request);
407 CheckDatabaseUpdate($request);
408 CheckPgsrcUpdate($request);
409 //CheckThemeUpdate($request);
410 EndLoadDump($request);
415 $Log: not supported by cvs2svn $
416 Revision 1.16 2004/06/16 10:38:58 rurban
417 Disallow refernces in calls if the declaration is a reference
418 ("allow_call_time_pass_reference clean").
419 PhpWiki is now allow_call_time_pass_reference = Off clean,
420 but several external libraries may not.
421 In detail these libs look to be affected (not tested):
425 Revision 1.15 2004/06/07 19:50:40 rurban
426 add owner field to mimified dump
428 Revision 1.14 2004/06/07 18:38:18 rurban
429 added mysql 4.1.x search fix
431 Revision 1.13 2004/06/04 20:32:53 rurban
432 Several locale related improvements suggested by Pierrick Meignen
433 LDAP fix by John Cole
434 reanable admin check without ENABLE_PAGEPERM in the admin plugins
436 Revision 1.12 2004/05/18 13:59:15 rurban
437 rename simpleQuery to genericQuery
439 Revision 1.11 2004/05/15 13:06:17 rurban
440 skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
442 Revision 1.10 2004/05/15 01:19:41 rurban
443 upgrade prefix fix by Kai Krakow
445 Revision 1.9 2004/05/14 11:33:03 rurban
446 version updated to 1.3.11pre
447 upgrade stability fix
449 Revision 1.8 2004/05/12 10:49:55 rurban
450 require_once fix for those libs which are loaded before FileFinder and
451 its automatic include_path fix, and where require_once doesn't grok
452 dirname(__FILE__) != './lib'
453 upgrade fix with PearDB
454 navbar.tmpl: remove spaces for IE button alignment
456 Revision 1.7 2004/05/06 17:30:38 rurban
457 CategoryGroup: oops, dos2unix eol
458 improved phpwiki_version:
459 pre -= .0001 (1.3.10pre: 1030.099)
460 -p1 += .001 (1.3.9-p1: 1030.091)
461 improved InstallTable for mysql and generic SQL versions and all newer tables so far.
462 abstracted more ADODB/PearDB methods for action=upgrade stuff:
463 backend->backendType(), backend->database(),
464 backend->listOfFields(),
465 backend->listOfTables(),
467 Revision 1.6 2004/05/03 15:05:36 rurban
470 Revision 1.4 2004/05/02 21:26:38 rurban
471 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
472 because they will not survive db sessions, if too large.
473 extended action=upgrade
474 some WikiTranslation button work
475 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
476 some temp. session debug statements
478 Revision 1.3 2004/04/29 22:33:30 rurban
479 fixed sf.net bug #943366 (Kai Krakow)
480 couldn't load localized url-undecoded pagenames
482 Revision 1.2 2004/03/12 15:48:07 rurban
483 fixed explodePageList: wrong sortby argument order in UnfoldSubpages
484 simplified lib/stdlib.php:explodePageList
493 // c-hanging-comment-ender-p: nil
494 // indent-tabs-mode: nil