]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/upgrade.php
add WikiAdminUtils method for convert-cached-html
[SourceForge/phpwiki.git] / lib / upgrade.php
1 <?php //-*-php-*-
2 rcs_id('$Id: upgrade.php,v 1.33 2004-12-10 22:33:39 rurban Exp $');
3 /*
4  Copyright 2004 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
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.
12
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.
17
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
21  */
22
23 /**
24  * Upgrade the WikiDB and config settings after installing a new 
25  * PhpWiki upgrade.
26  * Status: experimental, no queries for verification yet, 
27  *         no merge conflict resolution (patch?), just overwrite.
28  *
29  * Installation on an existing PhpWiki database needs some 
30  * additional worksteps. Each step will require multiple pages.
31  *
32  * This is the plan:
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 
44  *     version. (hard)
45
46  * Done: overwrite=1 link on edit conflicts at first occurence "Overwrite all".
47  *
48  * @author: Reini Urban
49  */
50 require_once("lib/loadsave.php");
51
52 /**
53  * TODO: check for the pgsrc_version number, not the revision mtime only
54  */
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');
65             reset($parts);
66             $pageinfo = $parts[0];
67             $stat  = stat($path."/".$filename);
68             $new_mtime = @$pageinfo['versiondata']['mtime'];
69             if (!$new_mtime)
70                 $new_mtime = @$pageinfo['versiondata']['lastmodified'];
71             if (!$new_mtime)
72                 $new_mtime = @$pageinfo['pagedata']['date'];
73             if (!$new_mtime)
74                 $new_mtime = $stat[9];
75             if ($new_mtime > $page_mtime) {
76                 echo "$path/$pagename: ",_("newer than the existing page."),
77                     _(" replace "),"($new_mtime &gt; $page_mtime)","<br />\n";
78                 LoadAny($request,$path."/".$filename);
79                 echo "<br />\n";
80             } else {
81                 echo "$path/$pagename: ",_("older than the existing page."),
82                     _(" skipped"),".<br />\n";
83             }
84         } else {
85             echo "$path/$pagename: ",("unknown format."),
86                     _(" skipped"),".<br />\n";
87         }
88     } else {
89         echo sprintf(_("%s does not exist"),$pagename),"<br />\n";
90         LoadAny($request,$path."/".$filename);
91         echo "<br />\n";
92     }
93 }
94
95 /** need the english filename (required precondition: urlencode == urldecode)
96  *  returns the plugin name.
97  */ 
98 function isActionPage($filename) {
99     static $special = array("DebugInfo"         => "_BackendInfo",
100                             "PhpWikiRecentChanges" => "RssFeed",
101                             "ProjectSummary"    => "RssFeed",
102                             "RecentReleases"    => "RssFeed",
103                             );
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;
107     else return false;
108 }
109
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));
127             else
128                 doPgsrcUpdate($request, $pagename, $path, $filename);
129         }
130     }
131 }
132
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, ...
140     $isHomePage = false;
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;
147         else
148             if ($pagename == _("HomePage")) $isHomePage = true;
149         if ($pagename == "HomePage") $isHomePage = true;
150         if ($isHomePage) {
151             echo "$path/$pagename: ",_("always skip the HomePage."),
152                 _(" skipped"),".<br />\n";
153             $isHomePage = false;
154             continue;
155         }
156         if (!isActionPage($filename)) {
157             doPgsrcUpdate($request,$pagename,$path,$filename);
158         }
159     }
160     return;
161 }
162
163 /**
164  * TODO: Search table definition in appropriate schema
165  *       and create it.
166  * Supported: mysql and generic SQL, for ADODB and PearDB.
167  */
168 function installTable(&$dbh, $table, $backend_type) {
169     global $DBParams;
170     if (!in_array($DBParams['dbtype'],array('SQL','ADODB'))) return;
171     echo _("MISSING")," ... \n";
172     $backend = &$dbh->_backend->_dbh;
173     /*
174     $schema = findFile("schemas/${backend_type}.sql");
175     if (!$schema) {
176         echo "  ",_("FAILED"),": ",sprintf(_("no schema %s found"),"schemas/${backend_type}.sql")," ... <br />\n";
177         return false;
178     }
179     */
180     extract($dbh->_backend->_table_names);
181     $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
182     switch ($table) {
183     case 'session':
184         assert($session_tbl);
185         if ($backend_type == 'mysql') {
186             $dbh->genericSqlQuery("
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),
193         INDEX (sess_date)
194 )");
195         } else {
196             $dbh->genericSqlQuery("
197 CREATE TABLE $session_tbl (
198         sess_id         CHAR(32) NOT NULL DEFAULT '',
199         sess_data       ".($backend_type == 'pgsql'?'TEXT':'BLOB')." NOT NULL,
200         sess_date       INT,
201         sess_ip         CHAR(15) NOT NULL
202 )");
203             $dbh->genericSqlQuery("CREATE UNIQUE INDEX sess_id ON $session_tbl (sess_id)");
204         }
205         $dbh->genericSqlQuery("CREATE INDEX sess_date on session (sess_date)");
206         echo "  ",_("CREATED");
207         break;
208     case 'user':
209         $user_tbl = $prefix.'user';
210         if ($backend_type == 'mysql') {
211             $dbh->genericSqlQuery("
212 CREATE TABLE $user_tbl (
213         userid  CHAR(48) BINARY NOT NULL UNIQUE,
214         passwd  CHAR(48) BINARY DEFAULT '',
215         PRIMARY KEY (userid)
216 )");
217         } else {
218             $dbh->genericSqlQuery("
219 CREATE TABLE $user_tbl (
220         userid  CHAR(48) NOT NULL,
221         passwd  CHAR(48) DEFAULT ''
222 )");
223             $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $user_tbl (userid)");
224         }
225         echo "  ",_("CREATED");
226         break;
227     case 'pref':
228         $pref_tbl = $prefix.'pref';
229         if ($backend_type == 'mysql') {
230             $dbh->genericSqlQuery("
231 CREATE TABLE $pref_tbl (
232         userid  CHAR(48) BINARY NOT NULL UNIQUE,
233         prefs   TEXT NULL DEFAULT '',
234         PRIMARY KEY (userid)
235 )");
236         } else {
237             $dbh->genericSqlQuery("
238 CREATE TABLE $pref_tbl (
239         userid  CHAR(48) NOT NULL,
240         prefs   TEXT NULL DEFAULT '',
241 )");
242             $dbh->genericSqlQuery("CREATE UNIQUE INDEX userid ON $pref_tbl (userid)");
243         }
244         echo "  ",_("CREATED");
245         break;
246     case 'member':
247         $member_tbl = $prefix.'member';
248         if ($backend_type == 'mysql') {
249             $dbh->genericSqlQuery("
250 CREATE TABLE $member_tbl (
251         userid    CHAR(48) BINARY NOT NULL,
252         groupname CHAR(48) BINARY NOT NULL DEFAULT 'users',
253         INDEX (userid),
254         INDEX (groupname)
255 )");
256         } else {
257             $dbh->genericSqlQuery("
258 CREATE TABLE $member_tbl (
259         userid    CHAR(48) NOT NULL,
260         groupname CHAR(48) NOT NULL DEFAULT 'users',
261 )");
262             $dbh->genericSqlQuery("CREATE INDEX userid ON $member_tbl (userid)");
263             $dbh->genericSqlQuery("CREATE INDEX groupname ON $member_tbl (groupname)");
264         }
265         echo "  ",_("CREATED");
266         break;
267     case 'rating':
268         $rating_tbl = $prefix.'rating';
269         if ($backend_type == 'mysql') {
270             $dbh->genericSqlQuery("
271 CREATE TABLE $rating_tbl (
272         dimension INT(4) NOT NULL,
273         raterpage INT(11) NOT NULL,
274         rateepage INT(11) NOT NULL,
275         ratingvalue FLOAT NOT NULL,
276         rateeversion INT(11) NOT NULL,
277         tstamp TIMESTAMP(14) NOT NULL,
278         PRIMARY KEY (dimension, raterpage, rateepage)
279 )");
280         } else {
281             $dbh->genericSqlQuery("
282 CREATE TABLE $rating_tbl (
283         dimension INT(4) NOT NULL,
284         raterpage INT(11) NOT NULL,
285         rateepage INT(11) NOT NULL,
286         ratingvalue FLOAT NOT NULL,
287         rateeversion INT(11) NOT NULL,
288         tstamp TIMESTAMP(14) NOT NULL,
289 )");
290             $dbh->genericSqlQuery("CREATE UNIQUE INDEX rating ON $rating_tbl (dimension, raterpage, rateepage)");
291         }
292         echo "  ",_("CREATED");
293         break;
294     case 'accesslog':
295         $log_tbl = $prefix.'accesslog';
296         // fields according to http://www.outoforder.cc/projects/apache/mod_log_sql/docs-2.0/#id2756178
297         /*
298 A       User Agent agent        varchar(255)    Mozilla/4.0 (compat; MSIE 6.0; Windows)
299 a       CGi request arguments   request_args    varchar(255)    user=Smith&cart=1231&item=532
300 b       Bytes transfered        bytes_sent      int unsigned    32561
301 c???    Text of cookie  cookie  varchar(255)    Apache=sdyn.fooonline.net 1300102700823
302 f       Local filename requested        request_file    varchar(255)    /var/www/html/books-cycroad.html
303 H       HTTP request_protocol   request_protocol        varchar(10)     HTTP/1.1
304 h       Name of remote host     remote_host     varchar(50)     blah.foobar.com
305 I       Request ID (from modd_unique_id)        id      char(19)        POlFcUBRH30AAALdBG8
306 l       Ident user info remote_logname  varcgar(50)     bobby
307 M       Machine ID???   machine_id      varchar(25)     web01
308 m       HTTP request method     request_method  varchar(10)     GET
309 P       httpd cchild PID        child_pid       smallint unsigned       3215
310 p       http port       server_port     smallint unsigned       80
311 R       Referer referer varchar(255)    http://www.biglinks4u.com/linkpage.html
312 r       Request in full form    request_line    varchar(255)    GET /books-cycroad.html HTTP/1.1
313 S       Time of request in UNIX time_t format   time_stamp      int unsigned    1005598029
314 T       Seconds to service request      request_duration        smallint unsigned       2
315 t       Time of request in human format request_time    char(28)        [02/Dec/2001:15:01:26 -0800]
316 U       Request in simple form  request_uri     varchar(255)    /books-cycroad.html
317 u       User info from HTTP auth        remote_user     varchar(50)     bobby
318 v       Virtual host servicing the request      virtual_host    varchar(255)
319         */
320         $dbh->genericSqlQuery("
321 CREATE TABLE $log_tbl (
322         time_stamp    int unsigned,
323         remote_host   varchar(50),
324         remote_user   varchar(50),
325         request_method varchar(10),
326         request_line  varchar(255),
327         request_args  varchar(255),
328         request_uri   varchar(255),
329         request_time  char(28),
330         status        smallint unsigned,
331         bytes_sent    smallint unsigned,
332         referer       varchar(255), 
333         agent         varchar(255),
334         request_duration float
335 )");
336         $dbh->genericSqlQuery("CREATE INDEX log_time ON $log_tbl (time_stamp)");
337         $dbh->genericSqlQuery("CREATE INDEX log_host ON $log_tbl (remote_host)");
338         echo "  ",_("CREATED");
339         break;
340     }
341     echo "<br />\n";
342 }
343
344 /**
345  * update from ~1.3.4 to current.
346  * only session, user, pref and member
347  * jeffs-hacks database api (around 1.3.2) later:
348  *   people should export/import their pages if using that old versions.
349  */
350 function CheckDatabaseUpdate(&$request) {
351     global $DBParams, $DBAuthParams;
352     if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
353     echo "<h3>",_("check for necessary database updates"),"</h3>\n";
354
355     _upgrade_db_init($dbh);
356
357     $tables = $dbh->_backend->listOfTables();
358     $backend_type = $dbh->_backend->backendType();
359     $prefix = isset($DBParams['prefix']) ? $DBParams['prefix'] : '';
360     foreach (explode(':','session:user:pref:member') as $table) {
361         echo sprintf(_("check for table %s"), $table)," ...";
362         if (!in_array($prefix.$table, $tables)) {
363             installTable($dbh, $table, $backend_type);
364         } else {
365             echo _("OK")," <br />\n";
366         }
367     }
368     if (ACCESS_LOG_SQL) {
369         $table = "accesslog";
370         echo sprintf(_("check for table %s"), $table)," ...";
371         if (!in_array($prefix.$table, $tables)) {
372             installTable($dbh, $table, $backend_type);
373         } else {
374             echo _("OK")," <br />\n";
375         }
376     }
377     $backend = &$dbh->_backend->_dbh;
378
379     // 1.3.8 added session.sess_ip
380     if (phpwiki_version() >= 1030.08 and USE_DB_SESSION and isset($request->_dbsession)) {
381         echo _("check for new session.sess_ip column")," ... ";
382         $database = $dbh->_backend->database();
383         assert(!empty($DBParams['db_session_table']));
384         $session_tbl = $prefix . $DBParams['db_session_table'];
385         $sess_fields = $dbh->_backend->listOfFields($database, $session_tbl);
386         if (!strstr(strtolower(join(':', $sess_fields)),"sess_ip")) {
387             // TODO: postgres test (should be able to add columns at the end, but not in between)
388             echo "<b>",_("ADDING"),"</b>"," ... ";              
389             $dbh->genericSqlQuery("ALTER TABLE $session_tbl ADD sess_ip CHAR(15) NOT NULL");
390             $dbh->genericSqlQuery("CREATE INDEX sess_date ON $session_tbl (sess_date)");
391         } else {
392             echo _("OK");
393         }
394         echo "<br />\n";
395     }
396
397     // 1.3.10 mysql requires page.id auto_increment
398     // mysql, mysqli or mysqlt
399     if (phpwiki_version() >= 1030.099 and substr($backend_type,0,5) == 'mysql') {
400         echo _("check for page.id auto_increment flag")," ...";
401         extract($dbh->_backend->_table_names);
402         assert(!empty($page_tbl));
403         $database = $dbh->_backend->database();
404         $fields = mysql_list_fields($database, $page_tbl, $dbh->_backend->connection());
405         $columns = mysql_num_fields($fields); 
406         for ($i = 0; $i < $columns; $i++) {
407             if (mysql_field_name($fields, $i) == 'id') {
408                 $flags = mysql_field_flags($fields, $i);
409                 //DONE: something was wrong with ADODB here.
410                 if (!strstr(strtolower($flags), "auto_increment")) {
411                     echo "<b>",_("ADDING"),"</b>"," ... ";
412                     // MODIFY col_def valid since mysql 3.22.16,
413                     // older mysql's need CHANGE old_col col_def
414                     $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE id id INT NOT NULL AUTO_INCREMENT");
415                     $fields = mysql_list_fields($database, $page_tbl);
416                     if (!strstr(strtolower(mysql_field_flags($fields, $i)), "auto_increment"))
417                         echo " <b><font color=\"red\">", _("FAILED"), "</font></b><br />\n";
418                     else     
419                         echo _("OK"), "<br />\n";
420                 } else {
421                     echo _("OK"), "<br />\n";
422                 }
423                 break;
424             }
425         }
426         mysql_free_result($fields);
427     }
428
429     // check for mysql 4.1.x/5.0.0a binary search problem.
430     //   http://bugs.mysql.com/bug.php?id=4398
431     // "select * from page where LOWER(pagename) like '%search%'" does not apply LOWER!
432     // confirmed for 4.1.0alpha,4.1.3-beta,5.0.0a; not yet tested for 4.1.2alpha,
433     // TODO: there's another known workaround, not yet applied. On windows only.
434     if (isWindows() and substr($backend_type,0,5) == 'mysql') {
435         echo _("check for mysql 4.1.x/5.0.0 binary search on windows problem")," ...";
436         $result = mysql_query("SELECT VERSION()", $dbh->_backend->connection());
437         $row = mysql_fetch_row($result);
438         $mysql_version = $row[0];
439         $arr = explode('.', $mysql_version);
440         $version = (string)(($arr[0] * 100) + $arr[1]) . "." . (integer)$arr[2];
441         if ($version >= 401.0) {
442             $dbh->genericSqlQuery("ALTER TABLE $page_tbl CHANGE pagename pagename VARCHAR(100) NOT NULL");
443             echo sprintf(_("version <em>%s</em> <b>FIXED</b>"), $mysql_version),"<br />\n";     
444         } else {
445             echo sprintf(_("version <em>%s</em> not affected"), $mysql_version),"<br />\n";
446         }
447     }
448
449     _upgrade_cached_html($dbh);
450
451     return;
452 }
453
454 function _upgrade_db_init (&$dbh) {
455     global $request, $DBParams, $DBAuthParams;
456     if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
457     if (defined('DBADMIN_USER') and DBADMIN_USER) {
458         // if need to connect as the root user, for alter permissions
459         $AdminParams = $DBParams;
460         if ($DBParams['dbtype'] == 'SQL')
461             $dsn = DB::parseDSN($AdminParams['dsn']);
462         else
463             $dsn = parseDSN($AdminParams['dsn']);
464         $AdminParams['dsn'] = sprintf("%s://%s:%s@%s/%s",
465                                       $dsn['phptype'],
466                                       DBADMIN_USER,
467                                       DBADMIN_PASSWD,
468                                       $dsn['hostspec'],
469                                       $dsn['database']);
470         $dbh = WikiDB::open($AdminParams);
471     } else {
472         $dbh = &$request->_dbi;
473     }
474 }
475
476 /**
477  * if page.cached_html does not exists:
478  *   put _cached_html from pagedata into a new seperate blob, not huge serialized string.
479  *
480  * it is only rarelely needed: for current page only, if-not-modified
481  * but was extracetd for every simple page iteration.
482  */
483 function _upgrade_cached_html (&$dbh) {
484     global $DBParams;
485     if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
486     if (phpwiki_version() >= 1030.10) {
487         echo _("check for extra page.cached_html column")," ... ";
488         $database = $dbh->_backend->database();
489         extract($dbh->_backend->_table_names);
490         $fields = $dbh->_backend->listOfFields($database, $page_tbl);
491         if (!strstr(strtolower(join(':', $fields)), "cached_html")) {
492             echo "<b>",_("ADDING"),"</b>"," ... ";
493             $backend_type = $dbh->_backend->backendType();
494             if (substr($backend_type,0,5) == 'mysql')
495                 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html MEDIUMBLOB");
496             else
497                 $dbh->genericSqlQuery("ALTER TABLE $page_tbl ADD cached_html BLOB");
498             echo "<b>",_("CONVERTING"),"</b>"," ... ";
499             _convert_cached_html($dbh);
500             echo _("OK"), "<br />\n";
501         } else {
502             echo _("OK"), "<br />\n";
503         }
504     }
505 }
506
507 /** 
508  * move _cached_html for all pages from pagedata into a new seperate blob.
509  * decoupled from action=upgrade, so that it can be used by a WikiAdminUtils button also.
510  */
511 function _convert_cached_html (&$dbh) {
512     global $DBParams;
513     if (!in_array($DBParams['dbtype'], array('SQL','ADODB'))) return;
514
515     $pages = $dbh->getAllPages();
516     $cache =& $dbh->_cache;
517     $count = 0;
518     extract($dbh->_backend->_table_names);
519     while ($page = $pages->next()) {
520         $pagename = $page->getName();
521         $data = $dbh->_backend->get_pagedata($pagename);
522         if (!empty($data['_cached_html'])) {
523             $cached_html = $data['_cached_html'];
524             $data['_cached_html'] = '';
525             $cache->update_pagedata($pagename, $data);
526             // store as blob, not serialized
527             $dbh->genericSqlQuery("UPDATE $page_tbl SET cached_html=? WHERE pagename=?",
528                                   array($cached_html, $pagename));
529             $count++;
530         }
531     }
532     return $count;
533 }
534
535 function fixConfigIni($match, $new) {
536     $file = FindFile("config/config.ini");
537     $found = false;
538     if (is_writable($file)) {
539         $in = fopen($file,"rb");
540         $out = fopen($tmp = tempnam(FindFile("uploads"),"cfg"),"wb");
541         if (isWindows())
542             $tmp = str_replace("/","\\",$tmp);
543         while ($s = fgets($in)) {
544             if (preg_match($match, $s)) {
545                 $s = $new . (isWindows() ? "\r\n" : "\n");
546                 $found = true;
547             }
548             fputs($out, $s);
549         }
550         fclose($in);
551         fclose($out);
552         if (!$found) {
553             echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
554                 sprintf(_("%s not found"), $match);
555             unlink($out);
556         } else {
557             @unlink("$file.bak");
558             @rename($file,"$file.bak");
559             if (rename($tmp, $file))
560                 echo " <b>",_("FIXED"),"</b>";
561             else {
562                 echo " <b>",_("FAILED"),"</b>: ";
563                 sprintf(_("couldn't move %s to %s"), $tmp, $file);
564                 return false;
565             }
566         }
567         return $found;
568     } else {
569         echo " <b><font color=\"red\">",_("FAILED"),"</font></b>: ",
570             sprintf(_("%s is not writable"), $file);
571         return false;
572     }
573 }
574
575 function CheckConfigUpdate(&$request) {
576     echo "<h3>",_("check for necessary config updates"),"</h3>\n";
577     echo _("check for old CACHE_CONTROL = NONE")," ... ";
578     if (defined('CACHE_CONTROL') and CACHE_CONTROL == '') {
579         echo "<br />&nbsp;&nbsp;",_("CACHE_CONTROL is set to 'NONE', and must be changed to 'NO_CACHE'")," ...";
580         fixConfigIni("/^\s*CACHE_CONTROL\s*=\s*NONE/","CACHE_CONTROL = NO_CACHE");
581     } else {
582         echo _("OK");
583     }
584     echo "<br />\n";
585     echo _("check for GROUP_METHOD = NONE")," ... ";
586     if (defined('GROUP_METHOD') and GROUP_METHOD == '') {
587         echo "<br />&nbsp;&nbsp;",_("GROUP_METHOD is set to NONE, and must be changed to \"NONE\"")," ...";
588         fixConfigIni("/^\s*GROUP_METHOD\s*=\s*NONE/","GROUP_METHOD = \"NONE\"");
589     } else {
590         echo _("OK");
591     }
592     echo "<br />\n";
593 }
594
595 /**
596  * TODO:
597  *
598  * Upgrade: Base class for multipage worksteps
599  * identify, validate, display options, next step
600  */
601 class Upgrade {
602 }
603
604 class Upgrade_CheckPgsrc extends Upgrade {
605 }
606
607 class Upgrade_CheckDatabaseUpdate extends Upgrade {
608 }
609
610 // TODO: At which step are we? 
611 // validate and do it again or go on with next step.
612
613 /** entry function from lib/main.php
614  */
615 function DoUpgrade($request) {
616
617     if (!$request->_user->isAdmin()) {
618         $request->_notAuthorized(WIKIAUTH_ADMIN);
619         $request->finish(
620                          HTML::div(array('class' => 'disabled-plugin'),
621                                    fmt("Upgrade disabled: user != isAdmin")));
622         return;
623     }
624
625     StartLoadDump($request, _("Upgrading this PhpWiki"));
626     //CheckOldIndexUpdate($request); // to upgrade from < 1.3.10
627     CheckActionPageUpdate($request);
628     CheckDatabaseUpdate($request);
629     CheckPgsrcUpdate($request);
630     //CheckThemeUpdate($request);
631     CheckConfigUpdate($request);
632     EndLoadDump($request);
633 }
634
635
636 /**
637  $Log: not supported by cvs2svn $
638  Revision 1.32  2004/12/10 22:15:00  rurban
639  fix $page->get('_cached_html)
640  refactor upgrade db helper _convert_cached_html() to be able to call them from WikiAdminUtils also.
641  support 2nd genericSqlQuery param (bind huge arg)
642
643  Revision 1.31  2004/12/10 02:45:26  rurban
644  SQL optimization:
645    put _cached_html from pagedata into a new seperate blob, not huge serialized string.
646    it is only rarelely needed: for current page only, if-not-modified
647    but was extracted for every simple page iteration.
648
649  Revision 1.30  2004/11/29 17:58:57  rurban
650  just aesthetics
651
652  Revision 1.29  2004/11/29 16:08:31  rurban
653  added missing nl
654
655  Revision 1.28  2004/11/16 16:25:14  rurban
656  fix accesslog tablename, print CREATED only if really done
657
658  Revision 1.27  2004/11/07 16:02:52  rurban
659  new sql access log (for spam prevention), and restructured access log class
660  dbh->quote (generic)
661  pear_db: mysql specific parts seperated (using replace)
662
663  Revision 1.26  2004/10/14 19:19:34  rurban
664  loadsave: check if the dumped file will be accessible from outside.
665  and some other minor fixes. (cvsclient native not yet ready)
666
667  Revision 1.25  2004/09/06 08:28:00  rurban
668  rename genericQuery to genericSqlQuery
669
670  Revision 1.24  2004/07/05 13:56:22  rurban
671  sqlite autoincrement fix
672
673  Revision 1.23  2004/07/04 10:28:06  rurban
674  DBADMIN_USER fix
675
676  Revision 1.22  2004/07/03 17:21:28  rurban
677  updated docs: submitted new mysql bugreport (#1491 did not fix it)
678
679  Revision 1.21  2004/07/03 16:51:05  rurban
680  optional DBADMIN_USER:DBADMIN_PASSWD for action=upgrade (if no ALTER permission)
681  added atomic mysql REPLACE for PearDB as in ADODB
682  fixed _lock_tables typo links => link
683  fixes unserialize ADODB bug in line 180
684
685  Revision 1.20  2004/07/03 14:48:18  rurban
686  Tested new mysql 4.1.3-beta: binary search bug as fixed.
687  => fixed action=upgrade,
688  => version check in PearDB also (as in ADODB)
689
690  Revision 1.19  2004/06/19 12:19:09  rurban
691  slightly improved docs
692
693  Revision 1.18  2004/06/19 11:47:17  rurban
694  added CheckConfigUpdate: CACHE_CONTROL = NONE => NO_CACHE
695
696  Revision 1.17  2004/06/17 11:31:50  rurban
697  check necessary localized actionpages
698
699  Revision 1.16  2004/06/16 10:38:58  rurban
700  Disallow refernces in calls if the declaration is a reference
701  ("allow_call_time_pass_reference clean").
702    PhpWiki is now allow_call_time_pass_reference = Off clean,
703    but several external libraries may not.
704    In detail these libs look to be affected (not tested):
705    * Pear_DB odbc
706    * adodb oracle
707
708  Revision 1.15  2004/06/07 19:50:40  rurban
709  add owner field to mimified dump
710
711  Revision 1.14  2004/06/07 18:38:18  rurban
712  added mysql 4.1.x search fix
713
714  Revision 1.13  2004/06/04 20:32:53  rurban
715  Several locale related improvements suggested by Pierrick Meignen
716  LDAP fix by John Cole
717  reanable admin check without ENABLE_PAGEPERM in the admin plugins
718
719  Revision 1.12  2004/05/18 13:59:15  rurban
720  rename simpleQuery to genericSqlQuery
721
722  Revision 1.11  2004/05/15 13:06:17  rurban
723  skip the HomePage, at first upgrade the ActionPages, then the database, then the rest
724
725  Revision 1.10  2004/05/15 01:19:41  rurban
726  upgrade prefix fix by Kai Krakow
727
728  Revision 1.9  2004/05/14 11:33:03  rurban
729  version updated to 1.3.11pre
730  upgrade stability fix
731
732  Revision 1.8  2004/05/12 10:49:55  rurban
733  require_once fix for those libs which are loaded before FileFinder and
734    its automatic include_path fix, and where require_once doesn't grok
735    dirname(__FILE__) != './lib'
736  upgrade fix with PearDB
737  navbar.tmpl: remove spaces for IE &nbsp; button alignment
738
739  Revision 1.7  2004/05/06 17:30:38  rurban
740  CategoryGroup: oops, dos2unix eol
741  improved phpwiki_version:
742    pre -= .0001 (1.3.10pre: 1030.099)
743    -p1 += .001 (1.3.9-p1: 1030.091)
744  improved InstallTable for mysql and generic SQL versions and all newer tables so far.
745  abstracted more ADODB/PearDB methods for action=upgrade stuff:
746    backend->backendType(), backend->database(),
747    backend->listOfFields(),
748    backend->listOfTables(),
749
750  Revision 1.6  2004/05/03 15:05:36  rurban
751  + table messages
752
753  Revision 1.4  2004/05/02 21:26:38  rurban
754  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
755    because they will not survive db sessions, if too large.
756  extended action=upgrade
757  some WikiTranslation button work
758  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
759  some temp. session debug statements
760
761  Revision 1.3  2004/04/29 22:33:30  rurban
762  fixed sf.net bug #943366 (Kai Krakow)
763    couldn't load localized url-undecoded pagenames
764
765  Revision 1.2  2004/03/12 15:48:07  rurban
766  fixed explodePageList: wrong sortby argument order in UnfoldSubpages
767  simplified lib/stdlib.php:explodePageList
768
769  */
770
771 // For emacs users
772 // Local Variables:
773 // mode: php
774 // tab-width: 8
775 // c-basic-offset: 4
776 // c-hanging-comment-ender-p: nil
777 // indent-tabs-mode: nil
778 // End:
779 ?>