]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/upgrade.php
Several locale related improvements suggested by Pierrick Meignen
[SourceForge/phpwiki.git] / lib / upgrade.php
1 <?php //-*-php-*-
2 rcs_id('$Id: upgrade.php,v 1.13 2004-06-04 20:32:53 rurban Exp $');
3
4 /*
5  Copyright 2004 $ThePhpWikiProgrammingTeam
6
7  This file is part of PhpWiki.
8
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.
13
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.
18
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
22  */
23
24
25 /**
26  * Upgrade the WikiDB and config settings after installing a new 
27  * PhpWiki upgrade.
28  * Status: experimental, no queries for verification yet, no db update,
29  *         no merge conflict
30  * Installation on an existing PhpWiki database needs some 
31  * additional worksteps. Each step will require multiple pages.
32  *
33  * This is the plan:
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)
43  *
44  * @author: Reini Urban
45  */
46 require_once("lib/loadsave.php");
47
48 /**
49  * TODO: check for the pgsrc_version number, not the revision
50  */
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');
61             reset($parts);
62             $pageinfo = $parts[0];
63             $stat  = stat($path."/".$filename);
64             $new_mtime = @$pageinfo['versiondata']['mtime'];
65             if (!$new_mtime)
66                 $new_mtime = @$pageinfo['versiondata']['lastmodified'];
67             if (!$new_mtime)
68                 $new_mtime = @$pageinfo['pagedata']['date'];
69             if (!$new_mtime)
70                 $new_mtime = $stat[9];
71             if ($new_mtime > $page_mtime) {
72                 echo "$path/$pagename: ",_("newer than the existing page."),
73                     _(" replace "),"($new_mtime &gt; $page_mtime)","<br />\n";
74                 LoadAny($request,$path."/".$filename);
75                 echo "<br />\n";
76             } else {
77                 echo "$path/$pagename: ",_("older than the existing page."),
78                     _(" skipped"),".<br />\n";
79             }
80         } else {
81             echo "$path/$pagename: ",("unknown format."),
82                     _(" skipped"),".<br />\n";
83         }
84     } else {
85         echo sprintf(_("%s does not exist"),$pagename),"<br />\n";
86         LoadAny($request,$path."/".$filename);
87         echo "<br />\n";
88     }
89 }
90
91 /** need the english filename (required precondition: urlencode == urldecode)
92  *  returns the plugin name.
93  */ 
94 function isActionPage($filename) {
95     static $special = array("DebugInfo"         => "_BackendInfo",
96                             "PhpWikiRecentChanges" => "RssFeed",
97                             "ProjectSummary"    => "RssFeed",
98                             "RecentReleases"    => "RssFeed",
99                             );
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;
103     else return false;
104 }
105
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     foreach ($pgsrc->getFiles() as $filename) {
113         if (substr($filename,-1,1) == '~') continue;
114         $pagename = urldecode($filename);
115         if (isActionPage($filename)) {
116             doPgsrcUpdate($request, $pagename, $path, $filename);
117         }
118     }
119 }
120
121 // see loadsave.php for saving new pages.
122 function CheckPgsrcUpdate(&$request) {
123     echo "<h3>",_("check for necessary pgsrc updates"),"</h3>\n";
124     $dbi = $request->getDbh(); 
125     $path = FindLocalizedFile(WIKI_PGSRC);
126     $pgsrc = new fileSet($path);
127     // fixme: verification, ...
128     $isHomePage = false;
129     foreach ($pgsrc->getFiles() as $filename) {
130         if (substr($filename,-1,1) == '~') continue;
131         $pagename = urldecode($filename);
132         // don't ever update the HomePage
133         if (defined(HOME_PAGE))
134             if ($pagename == HOME_PAGE) $isHomePage = true;
135         else
136             if ($pagename == _("HomePage")) $isHomePage = true;
137         if ($pagename == "HomePage") $isHomePage = true;
138         if ($isHomePage) {
139             echo "$path/$pagename: ",_("always skip the HomePage."),
140                 _(" skipped"),".<br />\n";
141             $isHomePage = false;
142             continue;
143         }
144         if (!isActionPage($filename)) {
145             doPgsrcUpdate($request,$pagename,$path,$filename);
146         }
147     }
148     return;
149 }
150
151 /**
152  * TODO: Search table definition in appropriate schema
153  *       and create it.
154  * Supported: mysql and generic SQL, for ADODB and PearDB.
155  */
156 function installTable(&$dbh, $table, $backend_type) {
157     global $DBParams;
158     if (!in_array($DBParams['dbtype'],array('SQL','ADODB'))) return;
159     echo _("MISSING")," ... \n";
160     $backend = &$dbh->_backend->_dbh;
161     /*
162     $schema = findFile("schemas/${backend_type}.sql");
163     if (!$schema) {
164         echo "  ",_("FAILED"),": ",sprintf(_("no schema %s found"),"schemas/${backend_type}.sql")," ... <br />\n";
165         return false;
166     }
167     */
168     extract($dbh->_backend->_table_names);
169     $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
170     switch ($table) {
171     case 'session':
172         assert($session_tbl);
173         if ($backend_type == 'mysql') {
174             $dbh->genericQuery("
175 CREATE TABLE $session_tbl (
176         sess_id         CHAR(32) NOT NULL DEFAULT '',
177         sess_data       BLOB NOT NULL,
178         sess_date       INT UNSIGNED NOT NULL,
179         sess_ip         CHAR(15) NOT NULL,
180         PRIMARY KEY (sess_id),
181         INDEX (sess_date)
182 )");
183         } else {
184             $dbh->genericQuery("
185 CREATE TABLE $session_tbl (
186         sess_id         CHAR(32) NOT NULL DEFAULT '',
187         sess_data       ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
188         sess_date       INT,
189         sess_ip         CHAR(15) NOT NULL
190 )");
191             $dbh->genericQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
192         }
193         $dbh->genericQuery("CREATE INDEX sess_date on session (sess_date)");
194         break;
195     case 'user':
196         $user_tbl = $prefix.'user';
197         if ($backend_type == 'mysql') {
198             $dbh->genericQuery("
199 CREATE TABLE $user_tbl (
200         userid  CHAR(48) BINARY NOT NULL UNIQUE,
201         passwd  CHAR(48) BINARY DEFAULT '',
202         PRIMARY KEY (userid)
203 )");
204         } else {
205             $dbh->genericQuery("
206 CREATE TABLE $user_tbl (
207         userid  CHAR(48) NOT NULL,
208         passwd  CHAR(48) DEFAULT ''
209 )");
210             $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
211         }
212         break;
213     case 'pref':
214         $pref_tbl = $prefix.'pref';
215         if ($backend_type == 'mysql') {
216             $dbh->genericQuery("
217 CREATE TABLE $pref_tbl (
218         userid  CHAR(48) BINARY NOT NULL UNIQUE,
219         prefs   TEXT NULL DEFAULT '',
220         PRIMARY KEY (userid)
221 )");
222         } else {
223             $dbh->genericQuery("
224 CREATE TABLE $pref_tbl (
225         userid  CHAR(48) NOT NULL,
226         prefs   TEXT NULL DEFAULT '',
227 )");
228             $dbh->genericQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
229         }
230         break;
231     case 'member':
232         $member_tbl = $prefix.'member';
233         if ($backend_type == 'mysql') {
234             $dbh->genericQuery("
235 CREATE TABLE $member_tbl (
236         userid    CHAR(48) BINARY NOT NULL,
237         groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
238         INDEX (userid),
239         INDEX (groupname)
240 )");
241         } else {
242             $dbh->genericQuery("
243 CREATE TABLE $member_tbl (
244         userid    CHAR(48) NOT NULL,
245         groupname CHAR(48) NOT NULL DEFAULT 'users',
246 )");
247             $dbh->genericQuery("CREATE INDEX userid ON $member_tbl (userid)");
248             $dbh->genericQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
249         }
250         break;
251     case 'rating':
252         $rating_tbl = $prefix.'rating';
253         if ($backend_type == 'mysql') {
254             $dbh->genericQuery("
255 CREATE TABLE $rating_tbl (
256         dimension INT(4) NOT NULL,
257         raterpage INT(11) NOT NULL,
258         rateepage INT(11) NOT NULL,
259         ratingvalue FLOAT NOT NULL,
260         rateeversion INT(11) NOT NULL,
261         tstamp TIMESTAMP(14) NOT NULL,
262         PRIMARY KEY (dimension, raterpage, rateepage)
263 )");
264         } else {
265             $dbh->genericQuery("
266 CREATE TABLE $rating_tbl (
267         dimension INT(4) NOT NULL,
268         raterpage INT(11) NOT NULL,
269         rateepage INT(11) NOT NULL,
270         ratingvalue FLOAT NOT NULL,
271         rateeversion INT(11) NOT NULL,
272         tstamp TIMESTAMP(14) NOT NULL,
273 )");
274             $dbh->genericQuery("CREATE UNIQUE INDEX rating ON $rating_tbl (dimension, raterpage, rateepage)");
275         }
276         break;
277     }
278     echo "  ",_("CREATED"),"<br />\n";
279 }
280
281 /**
282  * currently update only session, user, pref and member
283  * jeffs-hacks database api (around 1.3.2) later
284  *   people should export/import their pages if using that old versions.
285  */
286 function CheckDatabaseUpdate($request) {
287     global $DBParams, $DBAuthParams;
288     if (!in_array($DBParams['dbtype'],array('SQL','ADODB'))) return;
289     echo "<h3>",_("check for necessary database updates"),"</h3>\n";
290     $dbh = &$request->_dbi;
291     $tables = $dbh->_backend->listOfTables();
292     $backend_type = $dbh->_backend->backendType();
293     $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
294     extract($dbh->_backend->_table_names);
295     foreach (explode(':','session:user:pref:member') as $table) {
296         echo sprintf(_("check for table %s"),$table)," ...";
297         if (!in_array($prefix.$table,$tables)) {
298             installTable(&$dbh, $table, $backend_type);
299         } else {
300             echo _("OK")," <br />\n";
301         }
302     }
303     $backend = &$dbh->_backend->_dbh;
304     // 1.3.8 added session.sess_ip
305     if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
306         echo _("check for new session.sess_ip column")," ... ";
307         $database = $dbh->_backend->database();
308         assert(!empty($DBParams['db_session_table']));
309         $session_tbl = $prefix . $DBParams['db_session_table'];
310         $sess_fields = $dbh->_backend->listOfFields($database,$session_tbl);
311         //FIXME: adodb seem to uppercase the fields
312         if (!strstr(strtolower(join(':',$sess_fields)),"sess_ip")) {
313             echo "<b>",_("ADDING"),"</b>"," ... ";              
314             $dbh->genericQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
315         } else {
316             echo _("OK");
317         }
318         echo "<br />\n";
319     }
320     // 1.3.10 mysql requires page.id auto_increment
321     // mysql, mysqli or mysqlt
322     if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql') {
323         echo _("check for page.id auto_increment flag")," ...";
324         assert(!empty($page_tbl));
325         $database = $dbh->_backend->database();
326         $fields = mysql_list_fields($database,$page_tbl,$dbh->_backend->connection());
327         $columns = mysql_num_fields($fields); 
328         for ($i = 0; $i < $columns; $i++) {
329             if (mysql_field_name($fields, $i) == 'id') {
330                 $flags = mysql_field_flags($fields, $i);
331                 //FIXME: something wrong with ADODB here!
332                 if (!strstr(strtolower($flags),"auto_increment")) {
333                     echo "<b>",_("ADDING"),"</b>"," ... ";              
334                     // MODIFY col_def valid since mysql 3.22.16,
335                     // older mysql's need CHANGE old_col col_def
336                     $dbh->genericQuery("ALTER TABLE $page_tbl CHANGE id id INT NOT NULL AUTO_INCREMENT");
337                     $fields = mysql_list_fields($database,$page_tbl);
338                     if (!strstr(strtolower(mysql_field_flags($fields, $i)),"auto_increment"))
339                         echo " <b><font color=\"red\">",_("FAILED"),"</font></b><br />\n";              
340                     else     
341                         echo _("OK"),"<br />\n";                        
342                 } else {
343                     echo _("OK"),"<br />\n";                            
344                 }
345                 break;
346             }
347         }
348         mysql_free_result($fields);
349     }
350     return;
351 }
352
353 /**
354  * Upgrade: Base class for multipage worksteps
355  * identify, validate, display options, next step
356  */
357 class Upgrade {
358 }
359
360 class Upgrade_CheckPgsrc extends Upgrade {
361 }
362
363 class Upgrade_CheckDatabaseUpdate extends Upgrade {
364 }
365
366 // TODO: At which step are we? 
367 // validate and do it again or go on with next step.
368
369 /** entry function from lib/main.php
370  */
371 function DoUpgrade($request) {
372
373     if (!$request->_user->isAdmin()) {
374         $request->_notAuthorized(WIKIAUTH_ADMIN);
375         $request->finish(
376                          HTML::div(array('class' => 'disabled-plugin'),
377                                    fmt("Upgrade disabled: user != isAdmin")));
378         return;
379     }
380
381     StartLoadDump($request, _("Upgrading this PhpWiki"));
382     CheckActionPageUpdate($request);
383     CheckDatabaseUpdate($request);
384     CheckPgsrcUpdate($request);
385     //CheckThemeUpdate($request);
386     EndLoadDump($request);
387 }
388
389
390 /**
391  $Log: not supported by cvs2svn $
392  Revision 1.12  2004/05/18 13:59:15  rurban
393  rename simpleQuery to genericQuery
394
395  Revision 1.11  2004/05/15 13:06:17  rurban
396  skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
397
398  Revision 1.10  2004/05/15 01:19:41  rurban
399  upgrade prefix fix by Kai Krakow
400
401  Revision 1.9  2004/05/14 11:33:03  rurban
402  version updated to 1.3.11pre
403  upgrade stability fix
404
405  Revision 1.8  2004/05/12 10:49:55  rurban
406  require_once fix for those libs which are loaded before FileFinder and
407    its automatic include_path fix, and where require_once doesn't grok
408    dirname(__FILE__) != './lib'
409  upgrade fix with PearDB
410  navbar.tmpl: remove spaces for IE &nbsp; button alignment
411
412  Revision 1.7  2004/05/06 17:30:38  rurban
413  CategoryGroup: oops, dos2unix eol
414  improved phpwiki_version:
415    pre -= .0001 (1.3.10pre: 1030.099)
416    -p1 += .001 (1.3.9-p1: 1030.091)
417  improved InstallTable for mysql and generic SQL versions and all newer tables so far.
418  abstracted more ADODB/PearDB methods for action=upgrade stuff:
419    backend->backendType(), backend->database(),
420    backend->listOfFields(),
421    backend->listOfTables(),
422
423  Revision 1.6  2004/05/03 15:05:36  rurban
424  + table messages
425
426  Revision 1.4  2004/05/02 21:26:38  rurban
427  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
428    because they will not survive db sessions, if too large.
429  extended action=upgrade
430  some WikiTranslation button work
431  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
432  some temp. session debug statements
433
434  Revision 1.3  2004/04/29 22:33:30  rurban
435  fixed sf.net bug #943366 (Kai Krakow)
436    couldn't load localized url-undecoded pagenames
437
438  Revision 1.2  2004/03/12 15:48:07  rurban
439  fixed explodePageList: wrong sortby argument order in UnfoldSubpages
440  simplified lib/stdlib.php:explodePageList
441
442  */
443
444 // For emacs users
445 // Local Variables:
446 // mode: php
447 // tab-width: 8
448 // c-basic-offset: 4
449 // c-hanging-comment-ender-p: nil
450 // indent-tabs-mode: nil
451 // End:
452 ?>