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