1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Andreas Gohr <andi@splitbrain.org> 5 */ 6// must be run within Dokuwiki 7if(!defined('DOKU_INC')) die(); 8 9if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 10require_once(DOKU_PLUGIN.'syntax.php'); 11require_once(DOKU_INC.'inc/infoutils.php'); 12require_once(DOKU_PLUGIN.'semanticdata/phpSesame/phpSesame.php'); 13 14 15/** 16 * This is the base class for all syntax classes, providing some general stuff 17 */ 18class helper_plugin_semanticdata extends DokuWiki_Plugin { 19 20 21 /** 22 * Connect to the triple store 23 */ 24 function _getTripleStore(){ 25 static $ts = null; 26 if ($ts === null) { 27 $sesame = array('url' => $this->getConf('connect_url'), 'repository' => $this->getConf('connect_repository')); 28 $ts = new phpSesame($sesame['url'], $sesame['repository']); 29 } 30 return $ts; 31 } 32 33 34 /** 35 * Makes sure the given data fits with the given type 36 */ 37 function _cleanData($value, $type){ 38 $value = trim($value); 39 if(!$value) return ''; 40 if (is_array($type)) { 41 if (isset($type['enum']) && 42 !preg_match('/(^|,\s*)' . preg_quote_cb($value) . '($|\s*,)/', $type['enum'])) { 43 return ''; 44 } 45 $type = $type['type']; 46 } 47 switch($type){ 48 case 'dt': 49 if(preg_match('/^(\d\d\d\d)-(\d\d?)-(\d\d?)$/',$value,$m)){ 50 return sprintf('%d-%02d-%02d',$m[1],$m[2],$m[3]); 51 } 52 return ''; 53 case 'url': 54 if(!preg_match('!^[a-z]+://!i',$value)) $value='http://'.$value; 55 return $value; 56 case 'mail': 57 $email = ''; 58 $name = ''; 59 $part = ''; 60 $parts = preg_split('/\s+/',$value); 61 do{ 62 $part = array_shift($parts); 63 if(!$email && mail_isvalid($part)){ 64 $email = strtolower($part); 65 continue; 66 } 67 $name .= $part.' '; 68 }while($part); 69 return trim($email.' '.$name); 70 case 'page': case 'nspage': 71 return cleanID($value); 72 default: 73 return $value; 74 } 75 } 76 77 function _addPrePostFixes($type, $val, $pre='', $post='') { 78 if (is_array($type)) { 79 if (isset($type['prefix'])) $pre = $type['prefix']; 80 if (isset($type['postfix'])) $post = $type['postfix']; 81 } 82 return $pre.$val.$post; 83 } 84 85 /** 86 * Return XHTML formated data, depending on column type 87 */ 88 function _formatData($column, $value, &$R){ 89 global $conf; 90 $vals = explode("\n",$value); 91 $outs = array(); 92 foreach($vals as $val){ 93 $val = trim($val); 94 if($val=='') continue; 95 $type = $column['type']; 96 if (is_array($type)) $type = $type['type']; 97 switch($type){ 98 case 'page': 99 $val = $this->_addPrePostFixes($column['type'], $val, ':'); 100 $outs[] = $R->internallink($val,null,null,true); 101 break; 102 case 'title': 103 list($id,$title) = explode('|',$val,2); 104 $id = $this->_addPrePostFixes($column['type'], $id, ':'); 105 $outs[] = $R->internallink($id,$title,null,true); 106 break; 107 case 'nspage': 108 // no prefix/postfix here 109 $val = ':'.$column['key'].":$val"; 110 111 $outs[] = $R->internallink($val,null,null,true); 112 break; 113 case 'mail': 114 list($id,$title) = explode(' ',$val,2); 115 $id = $this->_addPrePostFixes($column['type'], $id); 116 $id = obfuscate(hsc($id)); 117 if(!$title){ 118 $title = $id; 119 }else{ 120 $title = hsc($title); 121 } 122 if($conf['mailguard'] == 'visible') $id = rawurlencode($id); 123 $outs[] = '<a href="mailto:'.$id.'" class="mail" title="'.$id.'">'.$title.'</a>'; 124 break; 125 case 'url': 126 $val = $this->_addPrePostFixes($column['type'], $val); 127 $outs[] = '<a href="'.hsc($val).'" class="urlextern" title="'.hsc($val).'">'.hsc($val).'</a>'; 128 break; 129 case 'tag': 130 #FIXME handle pre/postfix 131 $outs[] = '<a href="'.wl(str_replace('/',':',cleanID($column['key'])),array('dataflt'=>$column['key'].':'.$val )). 132 '" title="'.sprintf($this->getLang('tagfilter'),hsc($val)). 133 '" class="wikilink1">'.hsc($val).'</a>'; 134 break; 135 case 'wiki': 136 global $ID; 137 $oldid = $ID; 138 list($ID,$data) = explode('|',$val,2); 139 $data = $this->_addPrePostFixes($column['type'], $data); 140 // Trim document_{start,end}, p_{open,close} 141 $ins = array_slice(p_get_instructions($data), 2, -2); 142 $outs[] = p_render('xhtml', $ins, $byref_ignore); 143 $ID = $oldid; 144 break; 145 default: 146 $val = $this->_addPrePostFixes($column['type'], $val); 147 if(substr($type,0,3) == 'img'){ 148 $sz = (int) substr($type,3); 149 if(!$sz) $sz = 40; 150 $title = $column['key'].': '.basename(str_replace(':','/',$val)); 151 $outs[] = '<a href="'.ml($val).'" class="media" rel="lightbox"><img src="'.ml($val,"w=$sz").'" alt="'.hsc($title).'" title="'.hsc($title).'" width="'.$sz.'" /></a>'; 152 }else{ 153 $outs[] = hsc($val); 154 } 155 } 156 } 157 return join(', ',$outs); 158 } 159 160 /** 161 * Split a column name into its parts 162 * 163 * @returns array with key, type, ismulti, title, opt 164 */ 165 function _column($col){ 166 preg_match('/^([^_]*)(?:_(.*))?((?<!s)|s)$/', $col, $matches); 167 $column = array('multi' => ($matches[3] === 's'), 168 'key' => utf8_strtolower($matches[1]), 169 'title' => $matches[1], 170 'type' => utf8_strtolower($matches[2])); 171 172 // fix title for special columns 173 static $specials = array('%title%' => array('page', 'title'), 174 '%pageid%' => array('title', 'page'), 175 '%class%' => array('class')); 176 if (isset($specials[$column['title']])) { 177 $s = $specials[$column['title']]; 178 $column['title'] = $this->getLang($s[0]); 179 if($column['type'] === '' && isset($s[1])) { 180 $column['type'] = $s[1]; 181 } 182 } 183 184 // check if the type is some alias 185 $aliases = $this->_aliases(); 186 if(isset($aliases[$column['type']])){ 187 $column['origtype'] = $column['type']; 188 $column['type'] = $aliases[$column['type']]; 189 } 190 return $column; 191 } 192 193 /** 194 * Load defined type aliases 195 */ 196 function _aliases(){ 197 static $aliases = null; 198 if(!is_null($aliases)) return $aliases; 199 200 //$sqlite = $this->_getDB(); 201 $sqlite = $this->_getTripleStore(); 202 if(!$sqlite) return array(); 203 204 // aliases come later 205 $aliases = array(); 206 207 /* 208 * Aliases are currently not supported 209 */ 210 return $aliases; 211 } 212 213 /** 214 * Parse a filter line into an array 215 * 216 * @return mixed - array on success, false on error 217 */ 218 function _parse_filter($filterline){ 219 if(preg_match('/^(.*?)([=<>!~]{1,2})(.*)$/',$filterline,$matches)){ 220 $column = $this->_column(trim($matches[1])); 221 222 $com = $matches[2]; 223 $aliasses = array('<>' => '!=', '=!' => '!=', '~!' => '!~', 224 '==' => '=', '~=' => '~', '=~' => '~'); 225 226 if (isset($aliasses[$com])) { 227 $com = $aliasses[$com]; 228 } elseif (!preg_match('/(!?[=~])|([<>]=?)/', $com)) { 229 msg('Failed to parse comparison "'.hsc($com).'"',-1); 230 return false; 231 } 232 233 $val = trim($matches[3]); 234 // allow current user name in filter: 235 $val = str_replace('%user%',$_SERVER['REMOTE_USER'],$val); 236 // allow current date in filter: 237 $val = str_replace('%now%', dformat(null, '%Y-%m-%d'),$val); 238 239 if(strpos($com, '~') !== false) { 240 $val = str_replace('*','%',$val); 241 if ($com == '!~'){ 242 $com = 'NOT LIKE'; 243 } else { 244 $com = 'LIKE'; 245 } 246 } else { 247 // Clean if there are no asterisks I could kill 248 $val = $this->_cleanData($val, $column['type']); 249 } 250 251 $val = addslashes($val); 252 253 return array('key' => $column['key'], 254 'value' => $val, 255 'compare' => $com, 256 ); 257 } 258 msg('Failed to parse filter "'.hsc($filterline).'"',-1); 259 return false; 260 } 261 262 /** 263 * Get filters given in the request via GET or POST 264 */ 265 function _get_filters(){ 266 $flt = array(); 267 $filters = array(); 268 269 if(!isset($_REQUEST['dataflt'])){ 270 $flt = array(); 271 }elseif(!is_array($_REQUEST['dataflt'])){ 272 $flt = (array) $_REQUEST['dataflt']; 273 }else{ 274 $flt = $_REQUEST['dataflt']; 275 } 276 277 foreach($flt as $key => $line){ 278 // we also take the column and filtertype in the key: 279 if(!is_numeric($key)) $line = $key.$line; 280 $f = $this->_parse_filter($line); 281 if(is_array($f)){ 282 $f['logic'] = 'AND'; 283 $filters[] = $f; 284 } 285 } 286 287 return $filters; 288 } 289 290 /** 291 * prepare an array to be passed through buildURLparams() 292 */ 293 function _a2ua($name,$array){ 294 $urlarray = array(); 295 foreach((array) $array as $key => $val){ 296 $urlarray[rawurlencode($name).'['.rawurlencode($key).']'] = $val; 297 } 298 return $urlarray; 299 } 300 301} 302