1<?php
2/**
3 * DokuWiki Plugin tagfilter (Helper Component)
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author  lisps
7 */
8
9class helper_plugin_tagfilter extends DokuWiki_Plugin {
10	/**
11	 *
12	 * @var helper_plugin_tag
13	 */
14	protected $Htag;
15	/**
16	* Constructor gets default preferences and language strings
17	*/
18	function __construct() {
19		if (plugin_isdisabled('tag') || (!$this->Htag = plugin_load('helper', 'tag'))) {
20			msg('tag plugin is missing', -1);
21			return false;
22		}
23	}
24
25	function getMethods() {
26		$result = array();
27		$result[] = array(
28	                'name'   => 'getTagsByRegExp',
29	                'desc'   => 'returns tags for given Regular Expression',
30					'params' => array(
31			                    'tags (required)' => 'string',
32			                    'namespace (optional)' => 'string',),
33	                'return' => array('tags' => 'array'),
34		);
35		$result[] = array(
36	                'name'   => 'getTagsByNamespace',
37	                'desc'   => 'returns tags for given namespace',
38					'params' => array(
39			                    'namespace' => 'string',),
40	                'return' => array('tags' => 'array'),
41		);
42		$result[] = array(
43	                'name'   => 'getTagsBySiteID',
44	                'desc'   => 'returns tags for given siteID',
45					'params' => array(
46			                    'siteID' => 'string',),
47	                'return' => array('tags' => 'array'),
48		);
49
50		return $result;
51	}
52	function isNewTagVersion(){
53
54		$Htag  =$this->Htag;
55		if(!$Htag)return false;
56		$info =$Htag->getInfo();
57		return (strtotime($info['date'])>strtotime('2012-08-01'))?true:false;
58	}
59
60	//sucht im Tagindex nach Tags mittels preg Ausdrucken
61	function getTagsByRegExp($tags, $ns = ''){
62
63		$Htag  =$this->Htag;
64		if(!$Htag)return false;
65		$info=$Htag->getInfo();
66		if($this->isNewTagVersion())
67			return $this->getTagsByRegExp_New($tags, $ns,false);
68		$fullTags = array(); //gefundene Tags
69
70		$tags = $Htag->_parseTagList($tags, true);
71		$alltags = $this->getTagsByNamespace($ns,false);
72		foreach($tags  as  $tag){
73			foreach($alltags as $alltag){
74				if($this->preg_matchTag($tag, $alltag)){
75					$fullTags[$alltag] = $this->getTagLabel($alltag);
76				}
77			}
78		}
79		$fullTags = array_unique($fullTags);
80		asort($fullTags);
81
82		return  $fullTags;
83	}
84
85
86	public function preg_matchTag($pregmatch,$tag) {
87		return @preg_match('/^'.$pregmatch.'$/i',$tag);
88	}
89	public function getTagLabel($tag) {
90		$label = strrchr($tag,':');
91		$label = $label !=''?$label:$tag;
92		return mb_convert_case(str_replace('_',' ',trim($label,':')), MB_CASE_TITLE, "UTF-8");
93	}
94
95
96	protected $_tagsByNamespace = array();
97	function getTagsByNamespace($ns = '',$acl_safe = true){
98		if(!isset($this->_tagsByNamespace[$ns])) {
99			$Htag  =$this->Htag;
100			if(!$Htag)return false;
101
102			if($this->isNewTagVersion())
103				return array_keys($this->getTagsByRegExp_New('.*',$ns,$acl_safe));
104
105			$index = array_filter($Htag->topic_idx);
106
107			$tags=array();
108			if($ns === ''){
109				if($acl_safe) {
110					foreach($index as $tag=>$page_r){
111						foreach($page_r as $page) {
112							$perm = auth_quickaclcheck($page);
113							if (!$perm < AUTH_READ){
114								$tags[]=$tag;
115								break;
116							}
117						}
118					}
119				} else {
120					$tags = array_keys($index);
121				}
122			} else {
123				foreach ($index as $tag=>$page_r){
124					if($this->_checkPageArrayInNamespace($page_r,$ns)){
125						$tags[]=$tag;
126					}
127				}
128
129			}
130			$this->_tagsByNamespace[$ns]=array_unique($tags);
131		}
132		return $this->_tagsByNamespace[$ns];
133	}
134
135	function _checkPageArrayInNamespace($page_r,$ns,$acl_safe = true){
136		$Htag  =$this->Htag;
137		if(!$Htag)return false;
138		foreach($page_r as $page){
139			if(noNS($page) ==='_template') return false;
140			if ($ns && (strpos(':'.getNS($page).':', ':'.$ns.':') === 0)){
141				if (!$acl_safe) return true;
142				$perm = auth_quickaclcheck($page);
143				if (!$perm < AUTH_READ) {
144					if(!page_exists($page)) $Htag->_updateTagIndex($page,array());
145					return true;
146				}
147
148			}
149			//if($Htag->_isVisible($page,$ns))
150			//	return true;
151
152		}
153		return false;
154	}
155
156	function canRead($pageid) {
157		$Htag  =$this->Htag;
158		$perm = auth_quickaclcheck($pageid);
159		if (!($perm < AUTH_READ)) {
160			if(!page_exists($pageid) && !$this->isNewTagVersion()) $Htag->_updateTagIndex($pageid,array());
161			return true;
162		}
163		return false;
164	}
165
166	function _checkPageArrayInNamespace_New($page_r,$ns,$acl_safe = true){
167		$Htag  =$this->Htag;
168		if(!$Htag)return false;
169		foreach($page_r as $page){
170			if($Htag->_isVisible($page,$ns)) {
171				if (!$acl_safe) return true;
172				$perm = auth_quickaclcheck($page);
173				if (!$perm < AUTH_READ)
174					return true;
175
176			}
177
178		}
179		return false;
180	}
181
182	/*
183	 * liefert alle Tags f�r eine bestimmte seite Zur�ck
184	 */
185	function getTagsBySiteID($siteID){
186		if($this->isNewTagVersion())
187			return $this->getTagsBySiteId_New($siteID);
188
189		$Htag  =$this->Htag;
190		if(!$Htag)return false;
191
192		$index = array_filter($Htag->topic_idx);
193		/*echo '<pre>';
194		print_r($index);
195		echo '</pre>';*/
196		$tags=array();
197		foreach ($index as $tag=>$page_r){
198			if(in_array($siteID,$page_r)){
199				$tags[]=$tag;
200			}
201		}
202		$tags=array_unique($tags);
203		return $tags;
204	}
205
206	function getTagsBySiteId_New($siteID){
207		$meta = p_get_metadata($siteID,'subject');
208		if($meta === NULL) $meta=array();
209		return $meta;
210	}
211
212	function _tagCompare ($tag1,$tag2){
213		return $tag1==$tag2;
214	}
215	function getTagsByRegExp_New($tag_expr,$ns = '',$acl_safe=true){
216		$tags = $this->getIndex('subject','_w');
217		$tag_label_r = array();
218		foreach($tags  as  $tag){
219			if(@preg_match('/^'.$tag_expr.'$/i',$tag) && $this->_checkTagInNamespace($tag,$ns,$acl_safe)){
220				//$label =stristr($tag,':');
221				$label = strrchr($tag,':');
222				$label = $label !=''?$label:$tag;
223				$tag_label_r[$tag] = ucwords(trim(str_replace('_',' ',trim($label,':'))));
224			}
225		}
226		asort($tag_label_r);
227		return $tag_label_r;
228	}
229	function _checkTagInNamespace($tag,$ns,$acl_safe=true){
230		if($ns == '') return true;
231		$indexer = idx_get_indexer();
232		$pages = $indexer->lookupKey('subject', $tag, array($this, '_tagCompare'));
233		return $this->_checkPageArrayInNamespace_New($pages,$ns,$acl_safe);
234	}
235
236	/*
237	 * from inc/indexer.php
238	 */
239	public function getIndex($idx, $suffix) {
240        global $conf;
241        $fn = $conf['indexdir'].'/'.$idx.$suffix.'.idx';
242        if (!@file_exists($fn)) return array();
243        return file($fn, FILE_IGNORE_NEW_LINES);
244    }
245
246	protected $ps_ns = '';
247	protected $ps_pages_id = array();
248	protected $ps_pages = array();
249
250	function getPagesByTag($tag,$ns=''){
251		$tags = explode(' ',$tag);
252		$this->startPageSearch($ns);
253		foreach($tags as $t){
254			if($t[0] == '+') $this->addAndTag(substr($t,1));
255			elseif($t[0] == '-') $this->addSubTag(substr($t,1));
256			else $this->addOrTag($t);
257		}
258		return $this->getPages();
259	}
260
261	function startPageSearch($ns = '') {
262		$this->ps_ns = $ns;
263		$this->ps_pages_id = array();
264		$this->ps_pages = array();
265	}
266
267	function addAndTag($tag){
268		$tags = $this->getTagsByRegExp($tag,$this->ps_ns);
269		$pages = array();
270		foreach($tags as $t=>$v){
271			$Hpages =$this->Htag->getTopic($this->ps_ns,null,$t);
272			foreach($Hpages as $p){
273				$pages[] = $p['id'];
274				if(!isset($this->ps_pages[$p['id']])) $this->ps_pages[$p['id']] = $p;
275			}
276
277		}
278		$pages = array_unique($pages);
279		$this->ps_pages_id = array_intersect($this->ps_pages_id,$pages);
280	}
281
282	function addSubTag($tag){
283		$tags = $this->getTagsByRegExp($tag,$this->ps_ns);
284		$pages = array();
285		foreach($tags as $t=>$v){
286			$Hpages =$this->Htag->getTopic($this->ps_ns,'',$t);
287			foreach($Hpages as $p){
288				$pages[] = $p['id'];
289			}
290		}
291		$pages = array_unique($pages);
292		$this->ps_pages_id = array_diff($this->ps_pages_id,$pages);
293	}
294	function addOrTag($tag){
295		$tags = $this->getTagsByRegExp($tag,$this->ps_ns);
296		$pages = array();
297		foreach($tags as $t=>$v){
298			$Hpages =$this->Htag->getTopic($this->ps_ns,'',$t);
299			foreach($Hpages as $p){
300				$pages[] = $p['id'];
301				if(!isset($this->ps_pages[$p['id']])) $this->ps_pages[$p['id']] = $p;
302			}
303		}
304		$pages = array_unique($pages);
305		$this->ps_pages_id = array_merge($this->ps_pages_id,$pages);
306		$this->ps_pages_id = array_unique($this->ps_pages_id);
307
308		//print_r($this->ps_pages_id);
309	}
310	function getPages(){
311		$ret = array();
312		foreach ($this->ps_pages_id as $id){
313			$ret[] = $this->ps_pages[$id];
314		}
315		return $ret;
316	}
317
318	function getImageLinkByTag($tag){
319		$id = $this->getConf('nsTagImage').':'.str_replace(array(' ',':'),'_',$tag);
320		$src = $id .'.jpg';
321		if(!@file_exists(mediaFN($src))) {
322			$src = $id .'.png';
323			if(!@file_exists(mediaFN($src))) {
324				$src = $id .'.jpeg';
325				if(!@file_exists(mediaFN($src))) {
326					$src = false;
327				}
328			}
329		}
330		if($src != false) {
331			return ml($src);
332		}
333		return false;
334	}
335
336	function getTagImageColumn($id,$col,$ns){
337		if(!isset($this->_pageTags[$id])) {
338			$this->_pageTags[$id] = $this->getTagsBySiteID($id);
339		}
340		$foundTags = array();
341		foreach($this->_pageTags[$id] as $tag) {
342			if($this->preg_matchTag($col, $tag)) {
343				$foundTags[] = hsc($this->getTagLabel($tag));
344			}
345		}
346		$images = array();
347		foreach($foundTags as $foundTag) {
348			$imageid = $ns.':'.substr($foundTag,strrpos($foundTag,':'));
349
350			$src = $imageid .'.jpg';
351			if(!@file_exists(mediaFN($src))) {
352				$src = $imageid .'.png';
353				if(!@file_exists(mediaFN($src))) {
354					$src = $imageid .'.jpeg';
355					if(!@file_exists(mediaFN($src))) {
356						$src = $imageid .'.gif';
357						if(!@file_exists(mediaFN($src))) {
358							$src = false;
359						}
360					}
361				}
362			}
363			if($src != false) {
364				$images[] = '<img src="'.ml($src).' " class="media" style="height:max-width:200px;"/>';
365			}
366		}
367
368		return implode("<br>",$images);
369
370	}
371
372	/*
373	 * return all pages defined by tag_list_r in a specific namespace
374	 *
375	 * @param ns string the namespace to look in
376	 * @param tag_list_r array an array containing strings with tags seperated by ' '
377	 *
378	 */
379	function getAllPages($ns,$tag_list_r){
380		$pages = array();
381		$pages[''] = '';
382
383		$tag_list = implode(' ',$tag_list_r);
384
385		$page_r = $this->getPagesByTags($ns,$tag_list);
386
387		foreach($page_r as $page){
388			$title = p_get_metadata($page, 'title', METADATA_DONT_RENDER);
389			$title = $title?$title:$page;
390			$pages[$page]=strip_tags($title);  //FIXME hsc() doesent work with chosen
391		}
392
393		asort($pages);
394		return $pages;
395	}
396
397	function getPageTitle($pageid) {
398		$title = p_get_metadata($pageid, 'title', METADATA_DONT_RENDER);
399		$title = $title?$title:$pageid;
400		return strip_tags($title);
401	}
402
403	/*
404	 * gets the pages defined by tag_list
405	 *
406	 * partially copied from tag->helper with less checks (on cache) and no meta lookups
407	 * @param ns string the namespace to look in
408	 * @param tag_list string the tags seperated by ' '
409	 *
410	 * @return array array of page ids
411	 */
412	function getPagesByTags($ns,$tag_list) {
413		$page_names = array();
414		$tags_parsed = $this->Htag->_parseTagList($tag_list, true);
415		$pages_lookup = $this->Htag->_tagIndexLookup($tags_parsed);
416		foreach($pages_lookup as  $page_lookup){
417			// filter by namespace, root namespace is identified with a dot // root namespace is specified, discard all pages who lay outside the root namespace
418			if((($ns == '.') && (getNS($page_lookup) == false)) || ( (strpos(':'.getNS($page_lookup).':', ':'.$ns.':') === 0)) || $ns === '') {
419				$perm = auth_quickaclcheck($page_lookup);
420				if (!($perm < AUTH_READ))
421					$page_names[] = $page_lookup;
422			}
423		}
424		return $page_names;
425	}
426	function getTagCategory($tag){
427		$label = strstr($tag,':',true);
428		$label = $label !=''?$label:$tag;
429		return ucwords(str_replace('_',' ',trim($label,':')));
430	}
431	function th($tag = '') {
432		if(strpos($tag,'*'))
433			return $this->getTagCategory($tag);
434		else
435			return $this->getTagLabel($tag);
436	}
437
438	public $_pageTags = array();
439	function td($id,$col){
440		if(!isset($this->_pageTags[$id])) {
441			$this->_pageTags[$id] = $this->getTagsBySiteID($id);
442		}
443		$foundTags = array();
444		foreach($this->_pageTags[$id] as $tag) {
445			if($this->preg_matchTag($col, $tag)) {
446				$foundTags[] = hsc($this->getTagLabel($tag));
447			}
448		}
449		return implode("<br>",$foundTags);
450	}
451
452
453
454	/**
455	 *
456	 *
457	 * @param string $tags
458	 * @param string $ns
459	 * @return array [tag]=>[]pages
460	 */
461	function getRelationsByTagRegExp($tags, $ns = ''){
462		$relations = array();
463
464		$Htag  =$this->Htag;
465		if(!$Htag)return false;
466
467		$tags = $Htag->_parseTagList($tags, false); //array
468
469		if($this->isNewTagVersion()) {
470		    $indexer = idx_get_indexer();
471		    $indexTags = array_keys($indexer->histogram(1, 0, 3, 'subject'));
472		} else {
473		    $indexTags = array_keys($Htag->topic_idx);
474		}
475
476		$matchedTags = array();
477
478		foreach($indexTags as $tag) {
479			foreach($tags as $tagExpr) {
480				if($this->preg_matchTag($tagExpr, $tag))
481					$matchedTags[] = $tag;
482			}
483		}
484		$matchedTags = array_unique($matchedTags);
485		foreach($matchedTags as $tag) {
486		    if($this->isNewTagVersion()) {
487		        $pages = $Htag->_tagIndexLookup(array($tag));
488		    } else {
489		        $pages = $Htag->topic_idx[$tag];
490		    }
491			$relations[$tag] = array_filter($pages,function($pageid) use ($ns) {
492				if ($ns === '' ||  (strpos(':'.getNS($pageid).':', ':'.$ns.':') === 0)) return true;
493			});
494		}
495
496		$relations = array_filter($relations); //clean empty tags
497		ksort($relations); //sort
498
499		return $relations;
500	}
501}
502
503