root/trunk/gregarius/schema.php

Revision 1762, 31.9 kB (checked in by cfriesen, 9 months ago)

Refresh interval in the feed properties.

  • Property svn:eol-style set to native
  • Property svn:eolstyle set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 ###############################################################################
3 # Gregarius - A PHP based RSS aggregator.
4 # Copyright (C) 2003 - 2006 Marco Bonetti
5 #
6 ###############################################################################
7 # This program is free software and open source software; you can redistribute
8 # it and/or modify it under the terms of the GNU General Public License as
9 # published by the Free Software Foundation; either version 2 of the License,
10 # or (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15 # more details.
16 #
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit
20 # http://www.gnu.org/licenses/gpl.html
21 #
22 ###############################################################################
23 # E-mail:      mbonetti at gmail dot com
24 # Web page:    http://gregarius.net/
25 #
26 ###############################################################################
27
28 define('DBSTRUCT', dirname(__FILE__) . '/dbstruct.sql');
29
30 require_once('util.php');
31 require_once('cls/l10n.php');
32 /**
33  * Checks the db schema for the for all required tables, adds those which are missing.
34  * Returns the number of added tables;
35  */
36 function checkSchema() {
37     
38     $missing_tables = array();
39     $actual_tables=array();
40     $expected_tables = getExpectedTables();
41     
42     $rs = rss_query( "show tables", true, true );
43     while(list($tbl) = rss_fetch_row($rs)) {
44         $actual_tables[]=$tbl;
45     }
46     
47     foreach ($expected_tables as $base => $tbl) {
48         $exists = array_search($tbl,$actual_tables);
49         if ($exists === FALSE || $exists === NULL) {
50             $missing_tables[]=$base;
51         }
52     }
53     
54     $updated  = 0;
55     if (count($missing_tables) > 0) {
56         $msg = (count($actual_tables)?"Updating":"Creating")
57             .' your database schema! This should be a one-time operation,'
58             .' if you see this message over and over again please import your database schema'
59             .' manually.';
60         rss_error($msg, RSS_ERROR_WARNING);
61
62         foreach($missing_tables as $table) {
63             $updated += call_user_func("_init_$table");
64         }
65         
66         if ($updated == count($missing_tables)) {
67             rss_error(__("Successfully created $updated of $updated database tables!"), RSS_ERROR_NOTICE);
68         } else {
69             rss_error(
70                 (count($missing_tables) - $updated) . " out of "
71             . count($missing_tables) ." tables could not be created!",RSS_ERROR_ERROR);
72         }
73     }
74     
75     if ($updated) {
76         rss_invalidate_cache();
77     }
78     return $updated;
79 }
80
81 function getExpectedTables() {
82 $expected_tables = array (
83         "channels" => trim(getTable("channels")),
84         "config" => trim(getTable("config")),
85         "folders" => trim(getTable("folders")),
86         "item" => trim(getTable("item")),
87         "metatag" => trim(getTable("metatag")),
88         "tag" => trim(getTable("tag")),
89         "rating" => trim(getTable("rating")),
90         "cache" => trim(getTable("cache")),
91         "users" => trim(getTable("users")),       
92         "dashboard" => trim(getTable("dashboard")),
93         "properties" => trim(getTable("properties")),
94
95     );
96     return $expected_tables;
97 }
98 function rss_query_wrapper($query, $dieOnError=true, $preventRecursion=false) {
99     if (defined('DUMP_SCHEMA')) {
100         global $out;
101         $out .= ($query . ";\n");
102     } else {
103         rss_query(trim($query),$dieOnError,$preventRecursion);
104     }
105 }
106
107 /**
108  * this function handles specific schema updates that occurred
109  * during version updates.
110  *
111  * @return the number of updated tables
112  */
113 function checkSchemaColumns($column) {
114     $updated = 0;
115     switch($column) {
116         case 'c.mode':
117         case 'mode':
118             // default feed mode, added in 0.4.1
119             rss_query('alter table ' .getTable('channels') .' add column mode int(16) not null default 1');
120             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
121                 $updated++;
122                 rss_error("updated schema for table " . getTable('channels'), RSS_ERROR_NOTICE);
123             } else {
124                 rss_error("Failed updating schema for table " . getTable('channels')
125                 .": " . rss_sql_error_message(), RSS_ERROR_ERROR
126                 );
127             }
128         break;
129         case 'c.itemsincache':
130         case 'itemsincache':
131             // date feed was last refreshed, added in 0.5.3
132             rss_query('alter table ' .getTable('channels') .' add column itemsincache text null');
133             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
134                 $updated++;
135                 rss_error("updated schema for table " . getTable('channels'), RSS_ERROR_NOTICE);
136             } else {
137                 rss_error("Failed updating schema for table " . getTable('channels')
138                 .": " . rss_sql_error_message(), RSS_ERROR_ERROR
139                 );
140             }
141         break;
142         case 'c.daterefreshed':
143         case 'daterefreshed':
144             // date feed was last refreshed, added in 0.5.3
145             rss_query('alter table ' .getTable('channels') .' add column daterefreshed datetime null default 1');
146             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
147                 $updated++;
148                 rss_error("updated schema for table " . getTable('channels'), RSS_ERROR_NOTICE);
149             } else {
150                 rss_error("Failed updating schema for table " . getTable('channels')
151                 .": " . rss_sql_error_message(), RSS_ERROR_ERROR
152                 );
153             }
154         // break; - fallthrough allowed on purpose because these are added at the same time
155         case 'c.etag':
156         case 'etag':
157             // etag of the feed, (from HTTP header) added in 0.5.3
158             rss_query('alter table ' .getTable('channels') .' add column etag varchar(255) default null');
159             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
160                 $updated++;
161                 rss_error("updated schema for table " . getTable('channels'), RSS_ERROR_NOTICE);
162             } else {
163                 rss_error("Failed updating schema for table " . getTable('channels')
164                 .": " . rss_sql_error_message(), RSS_ERROR_ERROR
165                 );
166             }
167         // break; - fallthrough allowed on purpose because these are added at the same time
168         case 'c.lastmodified':
169         case 'lastmodified':
170             // last modified code returned by the feed (from HTTP header), added in 0.5.3
171             rss_query('alter table ' .getTable('channels') .' add column lastmodified varchar(255) default null');
172             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
173                 $updated++;
174                 rss_error("updated schema for table " . getTable('channels'), RSS_ERROR_NOTICE);
175             } else {
176                 rss_error("Failed updating schema for table " . getTable('channels')
177                 .": " . rss_sql_error_message(), RSS_ERROR_ERROR
178                 );
179             }
180         break;
181         case 'i.author':
182         case 'author':
183             // item's author
184             rss_query('alter table ' . getTable('item') . ' add column author varchar(255) null');
185             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
186                 $updated++;
187                 rss_error('updated schema for table ' . getTable('item'), RSS_ERROR_NOTICE);
188             } else {
189                 rss_error('Failed updating schema for table ' . getTable('item') . ': '
190                     . rss_sql_error_message(), RSS_ERROR_ERROR);
191             }
192         break;
193         
194         case 'm.tdate':
195         case 'tdate':
196             // tag date
197             rss_query('alter table ' . getTable('metatag') . ' add column tdate datetime null');
198             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
199                 rss_query('update ' . getTable('metatag') . ' set tdate=now()');
200                 $updated++;
201                 rss_error('updated schema for table ' . getTable('metatag'), RSS_ERROR_NOTICE);
202             } else {
203                 rss_error('Failed updating schema for table ' . getTable('metatag') . ': '
204                     . rss_sql_error_message(), RSS_ERROR_ERROR);
205             }
206         break;
207         case 'i.enclosure':
208         case 'enclosure':
209             // enclosure for an item
210             rss_query('alter table ' . getTable('item') . ' add column enclosure varchar(255) null');
211             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
212                 $updated++;
213                 rss_error('updated schema for table ' . getTable('item'), RSS_ERROR_NOTICE);
214             } else {
215                 rss_error('Failed updating schema for table ' . getTable('item') . ': '
216                     . rss_sql_error_message(), RSS_ERROR_ERROR);
217             }
218         break;
219         
220         case 'userips':
221         case 'i.userips':
222         // users.userips: list of valid IP subnets the user has logged in from
223         rss_query('alter table ' . getTable('users') . ' add column userips text default \'\'');
224             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
225                 $updated++;
226                 rss_error('updated schema for table ' . getTable('users'), RSS_ERROR_NOTICE);
227             } else {
228                 rss_error('Failed updating schema for table ' . getTable('users') . ': '
229                     . rss_sql_error_message(), RSS_ERROR_ERROR);
230             }
231         break;
232         
233         
234         case 'i.md5sum':
235         case 'md5sum':
236             // md5check on an item - added in 0.5.3
237             rss_query('alter table ' . getTable('item') . ' add column md5sum varchar(32) null');
238             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
239                 $updated++;
240                 rss_error('updated schema for table ' . getTable('item'), RSS_ERROR_NOTICE);
241             } else {
242                 rss_error('Failed updating schema for table ' . getTable('item') . ': '
243                     . rss_sql_error_message(), RSS_ERROR_ERROR);
244             }
245         // break; - fallthrough allowed on purpose because these are added at the same time
246         case 'i.guid':
247         case 'guid':
248             // guid of an item - added in 0.5.3
249             rss_query('alter table ' . getTable('item') . ' add column guid text null');
250             rss_query('alter table ' . getTable('item') . ' add index `guid` (`guid`(10))');
251             if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
252                 $updated++;
253                 rss_error('updated schema for table ' . getTable('item'), RSS_ERROR_NOTICE);
254             } else {
255                 rss_error('Failed updating schema for table ' . getTable('item') . ': '
256                     . rss_sql_error_message(), RSS_ERROR_ERROR);
257             }
258         
259         break;
260     }
261     return $updated;
262 }
263
264 ///////////////////////////////////////////////////////////////////////////////
265 ///////////////////////////////////////////////////////////////////////////////
266
267 function _init_channels() {
268     $table = getTable('channels');
269     rss_query_wrapper ('DROP TABLE IF EXISTS ' . $table, true, true);
270     $sql_create = str_replace('__table__',$table, <<< _SQL_
271         CREATE TABLE __table__ (
272             id bigint(11) NOT NULL auto_increment,
273               title varchar(255) NOT NULL default '',
274               url varchar(255) NOT NULL default '',
275               siteurl varchar(255) default NULL,
276               parent tinyint(4) default '0',
277               descr varchar(255) default NULL,
278               dateadded datetime default NULL,
279             daterefreshed datetime default NULL,
280             refreshinterval int(16) NOT NULL default '60',
281             itemsincache text default NULL,
282             etag varchar(255) default NULL,
283             lastmodified varchar(255) default NULL,
284               icon varchar(255) default NULL,
285               position int(11) NOT NULL default '0',
286             mode int(16) NOT NULL default '1',
287               PRIMARY KEY  (id),
288             KEY url (url)
289         ) TYPE=MyISAM;   
290 _SQL_
291 );
292
293     rss_query_wrapper($sql_create, false, true);
294     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
295         rss_error('The ' . $table . 'table doesn\'t exist and I couldn\'t create it! Please create it manually.', RSS_ERROR_ERROR);
296         return 0;
297     } else {
298         return 1;
299     }
300 }
301 ///////////////////////////////////////////////////////////////////////////////
302
303 function _init_dashboard() {
304     $table = getTable('dashboard');
305     rss_query_wrapper ('DROP TABLE IF EXISTS ' . $table, true, true);
306     $sql_create = str_replace('__table__',$table, <<< _SQL_
307         CREATE TABLE __table__ (
308             id bigint(11) NOT NULL auto_increment,
309               title text NOT NULL default '',
310               url text NOT NULL default '',
311               position tinyint(1) NOT NULL default 0,
312               obj text not NULL default '',
313               daterefreshed datetime default NULL,
314               itemcount tinyint(1) NOT NULL default 3,
315               PRIMARY KEY  (id)
316         ) TYPE=MyISAM;   
317 _SQL_
318 );
319
320     rss_query_wrapper($sql_create, false, true);
321     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
322         rss_error('The ' . $table . 'table doesn\'t exist and I couldn\'t create it! Please create it manually.', RSS_ERROR_ERROR);
323         return 0;
324     }
325     
326     
327     $baseData = array(
328         array ('Latest Gregarius News','http://devlog.gregarius.net/feed/?db=',0, 3),
329         array ('Latest Plugins','http://plugins.gregarius.net/rss.php?db=',1, 5),
330         array ('Latest Themes','http://themes.gregarius.net/rss.php?db=',1, 5),
331         array ('Latest Forum posts','http://forums.gregarius.net/feeds/?Type=rss2&db=',1, 5),
332 //        array ('Technorati','http://www.technorati.com/watchlists/rss.html?wid=59610&db=',1, 5)
333     );
334
335     foreach ($baseData as $feed) {
336         list($title,$url,$pos, $cnt) = $feed;
337         rss_query_wrapper (
338             "INSERT INTO $table (title, url, position, obj, daterefreshed, itemcount) VALUES "
339             ." ('$title', '$url', '$pos', '', null, $cnt)"    , false, true);   
340         if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
341             rss_error('The '  . $table ' table was created successfully, but I couldn\'t insert the default values. Please do so manually!', RSS_ERROR_ERROR);
342             return 0;
343         }   
344     }
345     
346     return 1;
347     
348     
349 }
350
351
352 ///////////////////////////////////////////////////////////////////////////////
353
354 function _init_folders() {
355     $table = getTable('folders');
356     rss_query_wrapper ('DROP TABLE IF EXISTS ' . $table, true, true);
357     $sql_create = str_replace('__table__',$table, <<< _SQL_
358         CREATE TABLE __table__ (
359           id tinyint(11) NOT NULL auto_increment,
360           name varchar(127) NOT NULL default '',
361           position int(11) NOT NULL default '0',   
362           PRIMARY KEY  (id),
363           UNIQUE KEY name (name)
364         ) TYPE=MyISAM;   
365 _SQL_
366 );
367
368     rss_query_wrapper($sql_create, false, true);
369     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
370         rss_error('The ' . $table . 'table doesn\'t exist and I couldn\'t create it! Please create it manually.', RSS_ERROR_ERROR);
371         return 0;
372     }
373     
374     
375     rss_query_wrapper ("INSERT INTO $table (id,name) VALUES (0,'')", false, true);
376     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
377         rss_error('The '  . $table ' table was created successfully, but I couldn\'t insert the default values. Please do so manually!', RSS_ERROR_ERROR);
378         return 0;
379     }
380     rss_query_wrapper ("update $table set id=0 where id=1", false, true);
381     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
382         rss_error('The '  . $table ' table was created successfully, but I couldn\'t insert the default values. Please do so manually!', RSS_ERROR_ERROR);
383         return 0;
384     }
385
386     return 1;
387 }
388
389 ///////////////////////////////////////////////////////////////////////////////
390
391 /** Config table */
392 function _init_config() {
393     $cfg_table = getTable('config');
394     
395     rss_query_wrapper ('DROP TABLE IF EXISTS ' . $cfg_table, true, true);
396     
397     $sql_create = str_replace('__config__',$cfg_table, <<< _SQL_
398         CREATE TABLE __config__ (
399                  key_ varchar(127) NOT NULL default '',
400                  value_ text NOT NULL,
401                  default_ text NOT NULL,
402                  type_ enum('string','num','boolean','array','enum') NOT NULL default 'string',
403                  desc_ text,
404                  export_ varchar(127) default NULL,
405                  PRIMARY KEY  (key_)
406                  ) TYPE=MyISAM;
407 _SQL_
408 );
409
410     rss_query_wrapper($sql_create, false, true);
411     if (!rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
412         rss_error('The ' .getTable('config') . 'table doesn\'t exist and I couldn\'t create it! Please create it manually.', RSS_ERROR_ERROR);
413         return 0;
414     }
415
416     
417     return (setDefaults(null)?1:0);
418 }
419
420
421 function setDefaults($key) {
422       rss_error('inserting some default config values...', RSS_ERROR_NOTICE);
423     $defaults = array (
424         "rss.output.encoding"        =>        array("UTF-8","UTF-8","string","Output encoding for the PHP XML parser.","MAGPIE_OUTPUT_ENCODING"),
425         "rss.output.itemsinchannelview"=>array("10","10","num","Number of read items shown on for a single channel.",NULL),
426         "rss.output.showfavicons"    =>        array("true","true","boolean","Display the favicon for the channels that have one. Due to a IE bug, some icons do not render correctly. You can either change the URL to the icon in the admin screen, or turn the display of favicons off globally here.",NULL),
427         "rss.output.usemodrewrite"    =>        array("true","true","boolean","Make use of apache's mod_rewrite module to return sexy urls. Turn this off if your host doesn't allow you to change this apache setting.",NULL),
428         "rss.config.dateformat"        =>        array("F jS, Y, g:ia T","F jS, Y, g:ia T","string","Format to use when displaying dates. See here for help on the format: http://php.net/date Note that direct access to a given feed's month and day archives more or less depends on the fact that this date format contains the  \"F\" (Month) and \"jS\" (day) elements in this form. So feel free to change the order of the elements, but better leave those two tokens in :)",NULL),
429         "rss.meta.debug"            =>        array("false","false","boolean"," When in debug mode some extra debug info is shown and the error reporting is a bit more verbose.",NULL),
430         "rss.output.compression"    =>        array("true","true","boolean","This variable turns output compression on and off. Output compression is handled by most browsers.",NULL),
431         "rss.output.channelcollapse"=>    array("true","true","boolean","Allow collapsing of channels on the main page. ",NULL),
432         "rss.output.channelcollapsedefault"=>    array("false","false","boolean","Collapse the channels on the main page by default",NULL),
433         "rss.output.usepermalinks"    =>        array("true","true","boolean","Display a permalink icon and allow linking a given item directly.",NULL),
434         "rss.config.markreadonupdate"=>    array("false","false","boolean","Mark all old unread feeds as read when updating if new unread feeds are found.",NULL),
435         "rss.output.lang"            =>        array("en_US,zh_CN,de,da,es,fr,he,it,ja,pt_BR,pt,ru,sv,0","en_US,zh_CN,de,da,es,fr,he,it,ja,pt_BR,pt,ru,sv,0","enum","Language pack to use.",NULL),
436         "rss.output.lang.force"        =>        array("false","false",'boolean',"When false, Gregarius will negotiate the display language with the browser and will fall back to the language defined in rss.output.lang if the negotiation fails. When true, Gregarius won't negotiate and will always use the language defined in rss.output.lang.",NULL),
437         "rss.config.absoluteordering"=>    array("true","true","boolean","Allow feeds and folders to be ordered by their order in the admin section. If this option is set to false, channels and folders will be organized alphabetically by their titles.",NULL),
438         "rss.config.robotsmeta"        =>        array("noindex,follow","noindex,follow","string","How should spiders crawl us? (see http://www.robotstxt.org/wc/meta-user.html for more info).",NULL),
439         "rss.config.serverpush"        =>        array("true","true","boolean","Use the server push method when updating your feeds in the browser. The browsers that support this (Mozilla and Opera) will be autodetected. Turn this option off if you do not use one of these browsers or if you would like to use the Ajax update method",NULL),
440         "rss.config.refreshafter"    =>        array("45","45","num","If this option is set the feeds will be updated after keeping the browser open for x minutes. Please respect the feed providers by not setting this value to anything lower than thirty minutes. Set this variable to 0 turn this option off.",NULL),
441         "rss.input.allowed"            =>        array('a:21:{s:1:"a";a:2:{s:4:"href";i:1;s:5:"title";i:1;}s:1:"b";a:0:{}s:10:"blockquote";a:0:{}s:2:"br";a:0:{}s:4:"code";a:0:{}s:3:"del";a:0:{}s:2:"em";a:0:{}s:1:"i";a:0:{}s:3:"img";a:2:{s:3:"src";i:1;s:3:"alt";i:1;}s:3:"ins";a:0:{}s:2:"li";a:0:{}s:2:"ol";a:0:{}s:1:"p";a:0:{}s:3:"pre";a:0:{}s:3:"sup";a:0:{}s:5:"table";a:0:{}s:2:"td";a:0:{}s:2:"th";a:0:{}s:2:"tr";a:0:{}s:2:"tt";a:0:{}s:2:"ul";a:0:{}}','a:21:{s:1:"a";a:2:{s:4:"href";i:1;s:5:"title";i:1;}s:1:"b";a:0:{}s:10:"blockquote";a:0:{}s:2:"br";a:0:{}s:4:"code";a:0:{}s:3:"del";a:0:{}s:2:"em";a:0:{}s:1:"i";a:0:{}s:3:"img";a:2:{s:3:"src";i:1;s:3:"alt";i:1;}s:3:"ins";a:0:{}s:2:"li";a:0:{}s:2:"ol";a:0:{}s:1:"p";a:0:{}s:3:"pre";a:0:{}s:3:"sup";a:0:{}s:5:"table";a:0:{}s:2:"td";a:0:{}s:2:"th";a:0:{}s:2:"tr";a:0:{}s:2:"tt";a:0:{}s:2:"ul";a:0:{}}',"array","This variable controls input filtering. HTML tags and their attributes, which are not in this list, get filtered out when new RSS items are imported.",NULL),
442         "rss.output.showfeedmeta"    =>        array('false','false','boolean','Display meta-information (like a web- and rss/rdf/xml url) about each feed in the feed side-column.',NULL),
443         //"rss.input.tags.delicious"    =>        array('false','false','boolean','Look up tag suggestions on del.icio.us when editing item tags.',NULL),
444         "rss.output.frontpage.numitems"    =>        array("100","100","num","Maximum number of items displayed on the main page. Set this variable to 0 to show no items on the main page.",NULL),
445         "rss.output.frontpage.mixeditems"    => array('true','true','boolean','Show read items along with unread items on the front page?',NULL),
446         "rss.output.frontpage.numreaditems"    => array(-1,-1,'num','If there are no unread items then how many items to show on the frontpage. Set this to -1 if you want it to be the same as rss.output.numitemsonmainpage',NULL),
447         "rss.output.theme"            =>        array('default','default','string','The theme to use. Download more themes from the <a href="http://themes.gregarius.net/">Gregarius Themes Repository</a>.',NULL),
448         "rss.output.cachecontrol"    =>        array('false','false','boolean','If true, Gregarius will negotiate with the browser and check whether it should get a fresh document or not.',NULL),
449         "rss.config.plugins"        =>        array('a:2:{i:0;s:13:"urlfilter.php";i:1;s:18:"roundedcorners.php";}','a:2:{i:0;s:13:"urlfilter.php";i:1;s:18:"roundedcorners.php";}','array','Plugins are third-party scripts that offer extended functionalities. More plugins can be found at the <a href="http://plugins.gregarius.net/">Plugin Repository</a>.' , NULL),
450         "rss.input.allowupdates"    =>        array('true','true'