source: randomized-blogroll/trunk/random-blogroll-plugin.php @ 274

Revision 274, 10.3 KB checked in by griesselmann, 7 years ago (diff)

Forgot to increment version to 0.2.1

Line 
1<?php
2/*
3Plugin Name: Random Blogroll
4Version: 0.2.1
5Plugin URI: http://www.gerd-riesselmann.net/categories/wordpress-plugins/
6Description: Generates a randomized blogroll out of OPML feed subsriptions.
7Author: Gerd Riesselmann
8Author URI: http://www.gerd-riesselmann.net/
9*/
10
11/*
12Copyright (C) 2005 Gerd Riesselmann
13
14This program is free software; you can redistribute it and/or
15modify it under the terms of the GNU General Public License
16as published by the Free Software Foundation; either version 2
17of the License, or (at your option) any later version.
18
19This program is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22GNU General Public License for more details.
23
24http://www.gnu.org/licenses/gpl.html
25*/
26
27
28/**
29 * global subscription items collection
30 */
31$rbr_items =& new rbr_LinkItems();
32$rbr_formatter =& new rbr_DefaultFormatter();
33
34define("RBR_CHACHE_FILE", "wp-content/rbr-cache/rbr_cache.inc");
35define("RBR_DEBUGLEVEL", 0);
36
37
38/**
39 * Outputs the blogroll list
40 *
41 * @param String The OMPL URI
42 * @param Integer The number of entries to display
43 * @param Integer Frequency of updates in minutes
44 * @param String The tag(s) to place before the generated anchor
45 * @param String The tag(s) to place after the generated anchor
46 */
47function rbr_output($opmlURI, $num = 10, $freq = 60, $tagBefore = "<li>", $tagAfter = "</li>")
48{
49        clearstatcache();
50        // Check if cache is outdated
51        if ( !file_exists(RBR_CHACHE_FILE) || filemtime(RBR_CHACHE_FILE) < time() - $freq * 60)
52        {
53                rbr_rewriteCache($opmlURI, $num, $tagBefore, $tagAfter);
54        }
55       
56        if ( file_exists(RBR_CHACHE_FILE) )
57                include RBR_CHACHE_FILE;
58        else
59        {
60                if (RBR_DEBUGLEVEL >= 1) echo "Writing cache file failed";
61                echo "\n<!-- Randomized Blogroll: No chache file produced -->\n";
62        }
63}
64
65// -----------------------------------------------
66// Data structures
67//
68// Simple item and item collection classes.
69//
70// The collection class rbr_LinkItems can be iterated like this:
71// for ($items->reset(); $item = $items->current(); $items->next())
72//
73// ------------------------------------------------
74
75
76/**
77 * Represents an item in the blogroll
78 */
79class rbr_LinkItem
80{
81        /**
82         * The Title
83         *
84         * @var String
85         */
86        var $name = "";
87
88        /**
89         * The Description
90         *
91         * @var String
92         */
93        var $description = "";
94
95        /**
96         * The URL
97         *
98         * @var String
99         */
100        var $url = "";
101       
102        /**
103         * The feed URL
104         *
105         * @var String
106         */
107        var $feedURL = "";
108
109        /**
110         * Constructor
111         *
112         * @param String Name
113         * @param String Description
114         * @param String URL
115         */
116        function rbr_LinkItem($name, $description, $url, $feedURL = "")
117        {
118                $this->name = $name;
119                $this->description = $description;
120                $this->url = $url;
121                $this->feedURL = $feedURL;
122        }
123
124        /**
125         * Returns HTML code for link anchor
126         *
127         * @return String
128         */
129        function getAnchorHTML()
130        {
131                return "<a href=\"".$this->url."\" title=\"".
132                        htmlspecialchars($this->description, ENT_COMPAT).
133                        "\" rel=\"bookmark\">".$this->name."</a>";
134        }
135}
136
137
138/**
139 * A collection of rbr_LinkItem
140 */
141class rbr_LinkItems
142{
143        /**
144         * The associative array holding the entries
145         *
146         * @var Array
147         */
148        var $items = array();
149       
150        /**
151         * Add an entry
152         *
153         * Checks if the entry already exists and if so, does nothing.
154         *
155         * @param rbr_LinkItem
156         * @return void
157         */
158        function add($item)
159        {
160                $key = $item->name;
161                if ($key == "")
162                {
163                        if (RBR_DEBUGLEVEL >= 1) echo "Empty name in adding item.<br/>";
164                        return;
165                }
166                       
167                if ( array_key_exists($key, $this->items) )
168                {
169                        if (RBR_DEBUGLEVEL >= 1) echo "Key $key used twice in adding item.<br/>";
170                        return;
171                }
172                       
173                $this->items[$key] = &$item;
174        }
175       
176        /**
177         * Returns blogroll item for given key (its title, actually)
178         *
179         * @param String The title of the item
180         * @return rbr_LinkItem
181         */
182        function &get($key)
183        {
184                return $this->items[$key];
185        }
186       
187        /**
188         * Returns the number of items in this collection
189         *
190         * @return Integer
191         */
192        function count()
193        {
194                return count($this->items);
195        }
196       
197        /**
198         * Clears collection
199         */
200        function clear()         
201        {
202                $this->items = array();
203        }
204       
205        /**
206         * Resets internal pointer for interation
207         *
208         * @return void
209         */
210        function reset()
211        {
212                reset ($this->items);
213        }
214       
215        /**
216         * Iterates to next item
217         *
218         * @return void
219         */
220        function next()
221        {
222                next ($this->items);
223        }
224       
225        /**
226         * Returns current item or FALSE, if there is none
227         *
228         * @return rbr_LinkItem FALSE if no current item
229         */
230        function &current()
231        {
232                return  current ($this->items);
233        }
234       
235        /**
236         * Extracts $num random items from items collection
237         *
238         * @param Integer The number of items to extract
239         * @return rbr_LinkItems New collection class
240         */
241         function &extractRandom($num)
242         {
243                $ret =& new rbr_LinkItems();
244               
245                $numEntries = $this->count();
246                if ($numEntries > $num)
247                {
248                        // There is somethin to extract...
249                        if ( version_compare(PHP_VERSION, "4.2", "<") )
250                        {
251                                // Init random numbers
252                                mt_srand((double)microtime()*1000000);
253                        }
254
255                        $arrRandomIndexes = array_rand($this->items, $num);
256                        if (RBR_DEBUGLEVEL >= 3) echo "Writing cache. Count randomEntries: ".count($arrRandomIndexes)."<br/>";
257
258                        foreach($arrRandomIndexes as $key)
259                        {
260                                if (RBR_DEBUGLEVEL >= 3) echo "Random index: ".$key."</br>";
261                                $ret->add( $this->get($key) );
262                        }
263                }
264                else if ($numItems > 0)
265                {
266                        // The number of items in this collection is less or equal then the
267                        // desired number of items. Make a copy of internal array
268                        $ret->items = $this->items;
269                }
270                else
271                {
272                        if (RBR_DEBUGLEVEL >= 1) echo "Extracting from empty collection.<br/>";
273                }
274               
275                return $ret;
276         }
277}
278
279// ------------------------------------------
280// Formatters
281//
282// Formatters are used to customize the blogroll output.
283// Formatters are classes providing one function which returns a string:
284//
285// function format(&$items, $tagBefore, $tagAfter)
286//
287// $items is an instance of rbr_LinkItems, actually a collection of blogroll items
288// $tagBefore are the tags to place before the generated content of each blogroll item
289// $tagAfter are the tags to place after the generated content of each blogroll item
290//
291// If you write your own formatter, you can set it by calling
292// $brb_formatter = new MyCustomFormatter();
293//
294// One formatter is provided by default (rbr_DefaultFormatter). This does a simply output a set
295// of anchors. Take this as a reference implementation
296//
297// -----------------------------------------
298
299/**
300 * Default Formatter.
301 */
302class rbr_DefaultFormatter
303{
304        /**
305         * Formats output
306         *
307         * @param rbr_LinkItems A collection of blogroll items
308         * @param String The tag(s) to place before the generated content of each blogroll item
309         * @param String The tag(s) to place after the generated anchor
310         * @return String
311         */
312        function format(&$items, $tagBefore, $tagAfter)
313        {
314                $ret = "";
315               
316                for ($items->reset(); $item = $items->current(); $items->next())
317                {
318                        $ret .= $tagBefore . $item->getAnchorHTML() . $tagAfter;
319                }
320               
321                return $ret;
322        }
323}
324
325// -----------------------------------------
326// Helper Functions
327// -----------------------------------------
328
329/**
330 * Updates the cache
331 *
332 * @param String The OMPL URI
333 * @param Integer The number of entries to display
334 * @param String The tag(s) to place before the generated anchor
335 * @param String The tag(s) to place after the generated anchor
336 */
337function rbr_rewriteCache($opmlFile, $num, $tagBefore, $tagAfter)
338{
339        global $rbr_items;
340        global $rbr_formatter;
341        rbr_readOPML($opmlFile);
342
343        // Write array to cache
344        if ($handle = fopen(RBR_CHACHE_FILE, 'wb'))
345        {
346                if (RBR_DEBUGLEVEL >= 2) echo "Writing cache. Count rbr_entries: ".$rbr_items->count()."<br/>";         
347               
348                $extractedItems = $rbr_items->extractRandom($num);
349               
350                if ( $extractedItems->count() > 0)
351                {
352                        fwrite($handle, $rbr_formatter->format($extractedItems, $tagBefore, $tagAfter));
353                }
354                else
355                {
356                        fwrite($handle, $tagBefore."No blogroll entries found".$tagAfter);
357                }       
358               
359                fclose($handle);
360        }
361        else
362        {
363                die("Not able to open file ".RBR_CACHE_FILE." for writing");
364        }
365}
366
367
368/**
369 * Processes OPML element. Invoked by XML parser
370 *
371 * @param int Parser ID
372 * @param String Element Name
373 * @param Array Atributes
374 */
375function rbr_opml_startElement($parser, $name, $attribs)
376{
377        if (RBR_DEBUGLEVEL >= 3) print "Processing element: ".$name."<br/>";
378        global $rbr_items;;
379               
380        if ($name == "OUTLINE")
381        {
382                if (isset($attribs["TYPE"]) && $attribs["TYPE"] == "rss")
383                {
384                        if (RBR_DEBUGLEVEL >= 3) print "Detecting outline<br/>";
385                       
386                        $title = "";
387                        $description = "";
388                        $url = "";
389                        $feedURL = "";
390                       
391                        if ( isset($attribs["TITLE"]) )
392                                $title = strip_tags($attribs["TITLE"]);
393                        else if ( isset($attribs["TEXT"]) )
394                                $title = strip_tags($attribs["TEXT"]);
395                                                       
396                        if ( isset($attribs["HTMLURL"]) )
397                                $url = $attribs["HTMLURL"];
398
399                        if (isset($attribs["DESCRIPTION"]))
400                                $description = strip_tags($attribs["DESCRIPTION"]);
401
402                        if (isset($attribs["XMLURL"]))
403                                $feedURL = $attribs["XMLURL"];
404                               
405                        if (strlen($title) > 0 && strlen($url) > 0)
406                        {
407                                if (RBR_DEBUGLEVEL >= 3) echo "Creating entry instance: ".$title."<br/>";
408                                $rbr_items->add( new rbr_LinkItem($title, $description, $url, $feedURL) );
409                        }
410                }
411        }
412}
413
414/**
415 * After processing OPML element. Invoked by XML parser
416 */
417function rbr_opml_endElement($parser, $name)
418{
419        // Does nothing
420}
421
422/**
423 * Reads the OML file by invoking XML parser and fills global class $rbr_entries
424 *
425 * @param the OPML file's URI
426 */
427function rbr_readOPML($file)
428{
429        if (file_exists($file) == false)
430                die($file." not found");
431               
432        $xml_parser = xml_parser_create();
433        xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
434        xml_set_element_handler($xml_parser, "rbr_opml_startElement", "rbr_opml_endElement");
435        if (!($fp = fopen($file, "r"))) {
436           die("could not open XML input");
437        }
438
439        while ($data = fread($fp, 4096)) {
440           if (!xml_parse($xml_parser, $data, feof($fp))) {
441                   die(sprintf("XML error: %s at line %d",
442                                           xml_error_string(xml_get_error_code($xml_parser)),
443                                           xml_get_current_line_number($xml_parser)));
444           }
445        }
446        xml_parser_free($xml_parser);
447}
448
449?>
Note: See TracBrowser for help on using the repository browser.