1<?php
2/**
3 * @license    GPL 3 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Szymon Olewniczak <(my first name) [at] imz [dot] re>
5 * @author     Cejka Rudolf <cejkar@fit.vutbr.cz>
6 */
7
8// must be run within DokuWiki
9if(!defined('DOKU_INC')) die();
10
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once DOKU_PLUGIN.'syntax.php';
13
14/**
15 * All DokuWiki plugins to extend the parser/rendering mechanism
16 * need to inherit from this class
17 */
18class syntax_plugin_filterrss extends DokuWiki_Syntax_Plugin {
19
20    function getPType(){
21       return 'block';
22    }
23
24    function getType() { return 'substition'; }
25    function getSort() { return 32; }
26
27
28    function connectTo($mode) {
29	$this->Lexer->addSpecialPattern('\[filterrss.*?\]',$mode,'plugin_filterrss');
30    }
31
32    function handle($match, $state, $pos, Doku_Handler $handler) {
33
34	//Remove ] from the end
35	$match = substr($match, 0, -1);
36	//Remove [filterrss
37	$match = substr($match, 10);
38
39	$known_fileds = array('pubDate', 'title', 'description', 'link');
40	$opposite_signs = array('>' => '<', '<' => '>', '>=' => '<=', '<=' => '>=');
41
42	$query = preg_split('/order by/i', $match);
43
44	$args = trim($query[0]);
45
46	if( isset( $query[1] ) )
47	{
48	    $sort = trim($query[1]);
49	    //ASC ist't isteresting
50	    $sort = str_ireplace('asc', '', $sort);
51
52	    $desc = false;
53	    if(stripos($sort, 'desc') !== false)
54	    {
55		$sort = str_ireplace('desc', '', $sort);
56		$desc = true;
57	    }
58
59	    //check if we define limit
60	    //I believe this's enough
61	    $limit = 99999999;
62	    $limit_reg = '/limit\s*([0-9]*)/i';
63	    if(preg_match($limit_reg, $sort, $matches) )
64	    {
65		$limit = (int)$matches[1];
66		$sort = preg_replace($limit_reg, '', $sort);
67	    }
68
69	    $order_by = trim($sort);
70	} else
71	{
72	    //check if we define limit
73	    //I believe this's enough
74	    $limit = 99999999;
75	    $limit_reg = '/limit\s*([0-9]*)\s*$/i';
76	    if(preg_match($limit_reg, $args, $matches) )
77	    {
78		$limit = (int)$matches[1];
79		$query = preg_replace($limit_reg, '', $query);
80	    }
81
82	}
83
84	$exploded = explode(' ', $args);
85	$url = $exploded[0];
86
87	//we have no arguments
88	if(count($exploded) < 3)
89	{
90	    return array('url' => $url, 'conditions' => array(), 'order_by' => $order_by, 'desc' => $desc, 'limit' => $limit);
91	}
92	array_shift($exploded);
93	array_shift($exploded);
94
95
96	$conditions = implode('', $exploded);
97
98	//Remove ] from the end
99	$conditions = substr($conditions, 0, -1);
100
101	$cond_array = explode('&&', $conditions);
102
103	$cond_output = array();
104
105	foreach($cond_array as $cond)
106	{
107	    preg_match('/(.*?)(>|<|=|>=|<=)+(.*)/', $cond, $res);
108	    if(in_array($res[1], $known_fileds))
109	    {
110		$name = $res[1];
111		$value = $res[3];
112		$sign = $res[2];
113	    } elseif(in_array($res[3], $known_fileds))
114	    {
115		$name = $res[3];
116		$value = $res[1];
117		$sign = $opposite_signs[$res[2]];
118	    } else
119	    {
120		continue;
121	    }
122
123	    //remove "" and ''
124	    $value = str_replace(array('"', "'"), '', $value);
125
126	    if(!isset($cond_output[$name]))
127		$cond_output[$name] = array();
128
129		array_push($cond_output[$name], array($sign, $value));
130	}
131	return array('url' => $url, 'conditions' => $cond_output, 'order_by' => $order_by, 'desc' => $desc, 'limit' => $limit);
132    }
133
134    function render($mode, Doku_Renderer $renderer, $data) {
135        if($mode == 'xhtml') {
136
137	    $filterrss =& plugin_load('helper', 'filterrss');
138
139	    $rss = simplexml_load_file($data['url']);
140	    $rss_array = array();
141
142	    if($rss)
143	    {
144		$items = $rss->channel->item;
145		$items_count = 0;
146		foreach($items as $item)
147		{
148		    if( $items_count >= $data['limit'])
149			break;
150		    $items_count++;
151		    $jump_this_entry = false;
152		    foreach($data['conditions'] as $entry => $conditions)
153		    {
154			switch($entry)
155			{
156			    case 'pubDate':
157				foreach($conditions as $comparison)
158				{
159				    $left = strtotime($item->$entry);
160				    $right = strtotime($comparison[1]);
161				    switch($comparison[0])
162				    {
163					case '>':
164					    if(!($left > $right))
165					    {
166						$jump_this_entry = true;
167						break;
168					    }
169					break;
170					case '<':
171					    if(!($left < $right))
172					    {
173						$jump_this_entry = true;
174						break;
175					    }
176					break;
177					case '>=':
178					    if(!($left >= $right))
179					    {
180						$jump_this_entry = true;
181						break;
182					    }
183					break;
184					case '<=':
185					    if(!($left <= $right))
186					    {
187						$jump_this_entry = true;
188						break;
189					    }
190					break;
191					case '=':
192					    if(!($left == $right))
193					    {
194						$jump_this_entry = true;
195						break;
196					    }
197					break;
198				    }
199				}
200			    break;
201			    case 'title':
202			    case 'description':
203			    case 'link':
204				foreach($conditions as $comparison)
205				{
206				    $subject = $item->$entry;
207
208				    //simple regexp option
209				    $pattern ='/'. str_replace('%', '.*', preg_quote($comparison[1])).'/';
210
211				    switch($comparison[0])
212				    {
213					case '=':
214					    if(!preg_match($pattern, $subject))
215					    {
216						$jump_this_entry = true;
217						break;
218					    }
219					break;
220				    }
221				}
222			    break;
223			}
224
225			if($jump_this_entry == true)
226			    break;
227		    }
228		    if($jump_this_entry == false)
229		    {
230			$entry = array();
231			$entry['title'] = $item->title;
232			$entry['link'] = $item->link;
233			$entry['pubDate'] = strtotime($item->pubDate);
234			$entry['description'] = $item->description;
235
236			array_push($rss_array, $entry);
237
238		    }
239		}
240		if(!empty($data['order_by']))
241		{
242		    switch($data['order_by'])
243		    {
244			case 'pubDate':
245			    $rss_array = $filterrss->int_sort($rss_array, $data['order_by']);
246			break;
247			case 'title':
248			case 'description':
249			case 'link':
250			    $rss_array = $filterrss->nat_sort($rss_array, $data['order_by']);
251			break;
252		    }
253		    if($data['desc'])
254		    {
255			$rss_array = array_reverse($rss_array);
256		    }
257		}
258		foreach($rss_array as $entry)
259		{
260		    $renderer->doc .= '<div class="filterrss_plugin">';
261		    $renderer->doc .= '<a href="'.$entry['link'].'">'.$entry['title'].'</a><br>';
262		    $renderer->doc .= '<span>'.date('d.m.Y',$entry['pubDate']).'</span>';
263		    if($this->getConf('bbcode') == true)
264		    {
265			$renderer->doc .= '<p>'.$filterrss->bbcode_parse($entry['description']).'</p>';
266		    } else
267		    {
268			$renderer->doc .= '<p>'.$entry['description'].'</p>';
269		    }
270		    $renderer->doc .= '</div>';
271		}
272	    } else
273	    {
274		$renderer->doc .= 'Cannot load rss feed.';
275	    }
276	    return true;
277        } elseif ($mode == "metadata") {
278	    $renderer->meta['plugin_filterrss']['purge'] = true;
279	}
280        return false;
281    }
282}
283