Updated for better reporting when loading from remote url fails. Now displays error...
[moodle.git] / rss / templib.php
1 <?php
3 global $CFG;
5 //initialize config vars for rss_client block if missing
6 if (empty($CFG->block_rss_client_submitters) ) {
7     $CFG->block_rss_client_submitters = 2; //default to admin only
8 }
9 if (empty($CFG->block_rss_client_num_entries) ) {
10     $CFG->block_rss_client_num_entries = 5; //default to 5 entries per block
11 }
12 if (empty($CFG->block_rss_timeout) ) {
13     $CFG->block_rss_timeout = 30;
14 }
16 /**
17  *   Determines whether or not to get a news feed remotely or from cache and reads it into a string
18  * @param int rssid - id of feed in blog_rss table
19  * @param string url - url of remote feed
20  * @param string type - either 'A' or 'R' where A is an atom feed and R is either rss or rdf
21  * @return Atom|MagpieRSS|null This function returns an Atom object in the case of an Atom feed, a MagpieRSS object in the case of an RDF/RSS feed or null if there was an error loading the remote feed.
22  * NOTE that this function requires allow_url_fopen be On in your php.ini file 
23  * (it may be off for security by your web host)
24  */
25 function rss_get_feed($rssid, $url, $type) {
26     
27     global $CFG;
28     $writetofile = false;
29     $urlfailurestring = 'Failed to open remote feed at: ' . $url .'<br /> allow_url_fopen needs to be On in the php.ini file for this file wrapper call to work. Please refer to <a href="http://us2.php.net/filesystem">http://us2.php.net/filesystem</a>';
30     $filefailurestring = 'Could not open the file located at: ';
31     $secs = $CFG->block_rss_timeout * 60;
33     // If moodle dataroot cache folder is missing create it
34     if (!file_exists($CFG->dataroot .'/cache/')) {
35         mkdir($CFG->dataroot .'/cache');
36     }
37     // If moodle dataroot cache/rsscache folder is missing create it
38     if (!file_exists($CFG->dataroot .'/cache/rsscache/')) {
39         mkdir($CFG->dataroot .'/cache/rsscache');
40     }
42     $file = $CFG->dataroot .'/cache/rsscache/'. $rssid .'.xml';
43 //    echo "file = ". $file; //debug
44     
45     //if feed in cache
46     if (file_exists($file)) {
47         //check age of cache file
48     //      echo "file exists $file"; //debug
49         if ($CFG->debug){
50             $data = stat($file);
51         } else {
52             $data = @stat($file);
53         }
54         $now = time();
55         if (($now - $data[10]) > $secs) {
56             // The cached file has expired. Attempt to read fresh from source
57             $xml = load_feed_from_url($url);
58             if ($xml) {
59                 //success
60                 $writetofile = true;
61             } else {
62                 // Failed to load remote feed. Since the file exists attempt to read from cache
63                 if ($CFG->debug) {
64                     print $urlfailurestring;
65                 }
66                 $xml = load_feed_from_file($file);
67                 if (!$xml) {
68                     // Failed to load from cache as well!
69                     if ($CFG->debug) {
70                         print $filefailurestring . $file;
71                         return;
72                     }
73                 }
74             }
75         } else {
76             // Cached file has not expired. Attempt to read from cached file.
77             $xml = load_feed_from_file($file);
78             if (!$xml) {
79                 // Failed to load from cache, attempt to read from source
80                 if ($CFG->debug) {
81                     print $filefailurestring . $file;
82                 }
83                 $xml = load_feed_from_url($url);
84                 if ($xml) {
85                     // success
86                     $writetofile = true;
87                 } else {
88                     // Failed to read from source as well!
89                     if ($CFG->debug) {
90                         print $urlfailurestring;
91                     }
92                     return;
93                 }
94             }
95         }
96     } else { 
97         // No cached fil at all, read from source
98         $xml = load_feed_from_url($url);
99         if ($xml) {
100             //success
101             $writetofile = true;
102         } else {
103             // Failed to read from source url!
104             if ($CFG->debug) {
105                 print $urlfailurestring;
106             }
107             return;
108         }
109     }
110     
111     //print_object($xml); //debug
112     if ($CFG->debug){
113         $xmlstr = implode(' ', $xml);
114     } else {
115         $xmlstr = @implode(' ', $xml);
116     }
117     
118     if ( $writetofile && !empty($xmlstr) ) { //write file to cache
119         // jlb: adding file:/ to the start of the file name fixed
120         // some caching problems that I was experiencing.
121         //$file="file:/" + $file;
122         file_put_contents($file, $xmlstr);
123     }
124     
125     if ($type == 'A') {
126         //note: Atom is being modified by a working group
127         //http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html
128         include_once($CFG->dirroot .'/rss/class.Atom.php');
129         $atom = new Atom($xmlstr);
130         $atom->channel = $atom->feed;
131         $atom->items = $atom->entries;
132         $atom->channel['description'] = $atom->channel['tagline'];
133         for($i=0;$i<count($atom->items);$i++) {
134             $atom->items[$i]['description'] = $atom->items[$i]['content'];
135         }
136         return $atom;
137     } else {
138         include_once($CFG->dirroot .'/rss/class.RSS.php');
139         $rss = new MagpieRSS($xmlstr);
140         return $rss;
141     }
144 /**
145  * @param string $file The path to the cached feed to load
146  */
147 function load_feed_from_file($file) {
148     global $CFG;
149 //          echo "read from cache"; //debug
150     //read in from cache
151     if ($CFG->debug){
152         $xml = file($file);
153     } else {
154         $xml = @file($file);
155     }
156     return $xml;
159 /**
160  * @param string $url The url of the remote news feed to load
161  */
162 function load_feed_from_url($url) {
163     global $CFG;
164 //          echo "read from original"; //debug
165     //read from source
166     if ($CFG->debug){
167         $xml = file($url);
168     } else {
169         $xml = @file($url);
170     }
171     return $xml;
174 /**
175  * @param int $rssid .
176  */
177 function rss_display_feeds($rssid='none') {
178     global $db, $USER, $CFG, $THEME;
179     global $blogid; //hackish, but if there is a blogid it would be good to preserve it
181     $closeTable = false;
182     //Daryl Hawes note: convert this sql statement to a moodle function call
183     if ($rssid != 'none'){
184         $sql = 'SELECT * FROM '. $CFG->prefix .'block_rss_client WHERE id='. $rssid;
185     } else {
186         $sql = 'SELECT * FROM '. $CFG->prefix .'block_rss_client';
187     }
188     
189     $res = $db->Execute($sql);
190 //    print_object($res); //debug
191     
192     if ($res->fields){
193         $closeTable = true;
194         ?>
195             <table width="100%">
196             <tr bgcolor="<?php echo $THEME->cellheading;?>" class="forumpostheadertopic">
197                 <td><?php print_string('block_rss_feed', 'block_rss_client'); ?></td>
198                 <td><?php print_string('edit'); ?></td>
199                 <td><?php print_string('delete'); ?></td>
200             </tr>
201         <?
202     }
203     
204     if (isset($res) && $res->fields){
205         while(!$res->EOF) {
206             $editString = '&nbsp;';
207             $deleteString = '&nbsp;';
208             if ($res->fields['userid'] == $USER->id || isadmin()){
209                 $editString = '<a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?act=rss_edit&rssid='. $res->fields['id'] .'&blogid='. $blogid .'">';
210                 $editString .= '<img src="'. $CFG->pixpath .'/t/edit.gif" alt="'. get_string('edit');
211 $editString .= '" title="'. get_string('edit') .'" align="absmiddle" height=\"16\" width=\"16\" border=\"0\" /></a>';
212                 
213                 $deleteString = '<a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?act=delfeed&rssid='. $res->fields['id'];
214                 $deleteString .= '&blogid='. $blogid .'" onClick="return confirm(\''. get_string('block_rss_delete_feed_confirm', 'block_rss_client') .'\');">';
215                 $deleteString .= '<img src="'. $CFG->pixpath .'/t/delete.gif" alt="'. get_string('delete');
216 $deleteString .= '" title="'. get_string('delete') .'" align="absmiddle" border=\"0\" /></a>';
217             }
218             print '<tr bgcolor="'. $THEME->cellcontent .'" class="forumpostmessage"><td><strong><a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?act=view&rssid=';
219             print $res->fields['id'] .'&blogid='. $blogid .'">'. $res->fields['title'] .'</a></strong><br />' ."\n";
220             print $res->fields['description'] .'&nbsp;<br />' ."\n";
221             print $res->fields['url'] .'&nbsp;&nbsp;<a href="'. $res->fields['url'] .'" target=_new><img src="'. $CFG->pixpath .'/blog/xml.gif" border="0" /></a>' ."\n";
222             print '<a href="http://feeds.archive.org/validator/check?url='. $res->fields['url'] .'">(Validate)</a>';
223             print '</td><td align="center">'. $editString .'</td>' ."\n";
224             print '<td align=\"center\">'. $deleteString .'</td>' ."\n";
225             print '</tr>'."\n";
226             $res->MoveNext();
227         }
228     }
229     if ($closeTable){
230         print '</table>'."\n";
231     }
234 /**
235  * @param string $act .
236  * @param string $url .
237  * @param int $rssid .
238  * @param string $rsstype .
239  * @param bool $printnow .
240  */
241 function rss_get_form($act, $url, $rssid, $rsstype, $printnow=true) {
242     global $USER, $CFG, $_SERVER, $blockid, $blockaction;
243     global $blogid; //hackish, but if there is a blogid it would be good to preserve it
245     $returnstring = '<table><tr><td valign=\"top\">'; 
246     if ($act == 'rss_edit') { 
247         $returnstring .= get_string('edit'); 
248     } else { 
249         $returnstring .= get_string('block_rss_add_new', 'block_rss_client');
250     }
251     $returnstring .= '  '. get_string('block_rss_feed', 'block_rss_client');
252     
253     $returnstring .= '</td></tr><tr><td>';
254     
255     $returnstring .= '<form action="'. $_SERVER['PHP_SELF'] .'" method=POST name="block_rss">';
256     $returnstring .= 'URL: <input type="text" size="32" maxlength="128" name="url" value="';
257     if ($act == 'rss_edit') { 
258         $returnstring .= $url; 
259     } 
260     
261     $returnstring .= '" /><br /><select name="rsstype"><option value="R">RSS/RDF</option>
262     <option value="A"';
263     if ($act == 'rss_edit' and $rsstype == 'A') {
264         $returnstring .= ' selected';
265     } 
266     
267     $returnstring .= '>Atom</option></select>';
268     
269     $returnstring .= '<input type="hidden" name="act" value="';
270     if ($act == 'rss_edit') {
271         $returnstring .= 'updfeed';
272     } else {
273         $returnstring .= 'addfeed';
274     } 
275     $returnstring .= '" />';
276     if ($act == 'rss_edit') { 
277         $returnstring .= '<input type="hidden" name="rssid" value="'. $rssid .'" />'. "\n"; 
278     } 
279     $returnstring .= '<input type="hidden" name="blogid" value="'. $blogid .'" />';
280     $returnstring .= '<input type="hidden" name="user" value="'. $USER->id .'" />';
281     $returnstring .= '<input type="submit" value="';
282     if ($act == 'rss_edit') {
283         $returnstring .= get_string('update'); 
284     } else { 
285         $returnstring .= get_string('add'); 
286     }
287     $returnstring .= '" />&nbsp;</form>';
288     
289     $returnstring .= '<ul>' . get_string('block_rss_find_more_feeds', 'block_rss_client');
290 // removed as this is possibly out of place here
291 //    $returnstring .= '<li><a href="http://www.syndic8.com" target="_new">syndic8</a> <li><a href="http://www.newsisfree.com" target="_new">NewsIsFree</A>';
292     $returnstring .= '</ul>';
293     $returnstring .= '</td></tr></table>';
294     
295     if ($printnow){
296         print $returnstring;
297     }
298     return $returnstring;
301 /**
302  * added by Daryl Hawes for rss/atom feeds
303  * found at http://us4.php.net/manual/en/function.fwrite.php
304  * added check for moodle debug option. if off then use '@' to suppress error/warning messages
305  * @param string $filename .
306  * @param string $content .
307  */
308 if (! function_exists('file_put_contents')){
309     function file_put_contents($filename, $content) {
310         global $CFG;
311         $nr_of_bytes = 0;
312         if ($CFG->debug){
313             if (($file = fopen($filename, 'w+')) === false) return false;
314         } else {
315             if (($file = @fopen($filename, 'w+')) === false) return false;
316         }
317         if ($CFG->debug){
318             if ($nr_of_bytes = fwrite($file, $content, strlen($content)) === false) return false;
319         } else {
320             if ($nr_of_bytes = @fwrite($file, $content, strlen($content)) === false) return false;
321         }        
322         fclose($file);
323         return $nr_of_bytes;
324     }
326 ?>