Initial revision
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_matchcondition.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 Kasper Skårhøj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class for Matching TypoScript conditions
29 *
30 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
31 *
32 * @author Kasper Skårhøj <kasper@typo3.com>
33 * @package TYPO3
34 * @subpackage t3lib
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 75: class t3lib_matchCondition
42 * 89: function match($string)
43 * 300: function testNumber($test,$value)
44 * 322: function matchWild($haystack,$needle)
45 * 352: function whichDevice($useragent)
46 * 402: function browserInfo($useragent)
47 * 501: function getGlobal($var,$inArr='')
48 * 526: function getGP_ENV_TSFE($var)
49 *
50 * TOTAL FUNCTIONS: 7
51 * (This index is automatically created/updated by the extension "extdeveval")
52 *
53 */
54
55
56
57
58
59
60
61
62
63
64
65
66 /**
67 * Matching TypoScript conditions
68 *
69 * Used with the TypoScript parser.
70 * Matches browserinfo, IPnumbers for use with templates
71 *
72 * @author Kasper Skårhøj <kasper@typo3.com>
73 * @see t3lib_TStemplate::matching(), t3lib_TStemplate::generateConfig()
74 */
75 class t3lib_matchCondition {
76 var $matchAlternative=array(); // If this array has elements, the matching returns true if a whole "matchline" is found in the array!
77 var $matchAll=0; // If set all is matched!
78
79 var $altRootLine=array();
80
81 /**
82 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
83 *
84 * @param string The condition to match against its criterias.
85 * @return boolean Returns true or false based on the evaluation.
86 * @see t3lib_tsparser::parse()
87 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=292&cHash=c6c7d43d2f
88 */
89 function match($string) {
90 if ($this->matchAll) return true;
91 if (count($this->matchAlternative)) {
92 return in_array($string,$this->matchAlternative);
93 }
94
95 if (!$this->browserInfoArray) {
96 $this->browserInfoArray = $this->browserInfo(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
97 }
98 $browserInfo = $this->browserInfoArray;
99 $string = trim($string);
100 $string = substr($string,1,strlen($string)-2);
101 $parts = explode('][',$string);
102 reset($parts);
103 while(list(,$val)=each($parts)) {
104 $pcs = explode('=',$val,2);
105 $switchKey = trim($pcs[0]);
106 switch($switchKey) {
107 case 'browser':
108 $values = explode(',',$pcs[1]);
109 while(list(,$test)=each($values)) {
110 if (strstr($browserInfo['browser'].$browserInfo['version'],trim($test))) {
111 return true;
112 }
113 }
114 break;
115 case 'version':
116 $values = explode(',',$pcs[1]);
117 while(list(,$test)=each($values)) {
118 $test = trim($test);
119 if ($test) {
120 if (strcspn($test,'=<>')==0) {
121 switch(substr($test,0,1)) {
122 case '=':
123 if (doubleval(substr($test,1))==$browserInfo['version']) return true;
124 break;
125 case '<':
126 if (doubleval(substr($test,1))>$browserInfo['version']) return true;
127 break;
128 case '>':
129 if (doubleval(substr($test,1))<$browserInfo['version']) return true;
130 break;
131 }
132 } else {
133 if (strpos(' '.$browserInfo['version'],$test)==1) {return true;}
134 }
135 }
136 }
137 break;
138 case 'system':
139 $values = explode(',',$pcs[1]);
140 while(list(,$test)=each($values)) {
141 $test = trim($test);
142 if ($test) {
143 if (strpos(' '.$browserInfo['system'],$test)==1) {return true;}
144 }
145 }
146 break;
147 case 'device':
148 $values = explode(',',$pcs[1]);
149 if (!isset($this->deviceInfo)) {
150 $this->deviceInfo = $this->whichDevice(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
151 }
152 while(list(,$test)=each($values)) {
153 $test = trim($test);
154 if ($test) {
155 if ($this->deviceInfo==$test) {return true;}
156 }
157 }
158 break;
159 case 'useragent':
160 $test = trim($pcs[1]);
161 if ($test) {
162 return $this->matchWild($browserInfo['useragent'],$test);
163 }
164 break;
165 case 'language':
166 $values = explode(',',$pcs[1]);
167 while(list(,$test)=each($values)) {
168 $test = trim($test);
169 if ($test) {
170 if (t3lib_div::getIndpEnv('HTTP_ACCEPT_LANGUAGE') == $test) {return true;}
171 }
172 }
173 break;
174 case 'IP':
175 if (t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $pcs[1])) {return true;}
176 break;
177 // hour, minute, dayofweek, dayofmonth, month
178 case 'hour':
179 case 'minute':
180 case 'dayofweek':
181 case 'dayofmonth':
182 case 'month':
183 $theEvalTime = $GLOBALS['SIM_EXEC_TIME']; // In order to simulate time properly in templates.
184 switch($switchKey) {
185 case 'hour': $theTestValue = date('H',$theEvalTime); break;
186 case 'minute': $theTestValue = date('i',$theEvalTime); break;
187 case 'dayofweek': $theTestValue = date('w',$theEvalTime); break;
188 case 'dayofmonth': $theTestValue = date('d',$theEvalTime); break;
189 case 'month': $theTestValue = date('m',$theEvalTime); break;
190 }
191 $theTestValue = intval($theTestValue);
192 // comp
193 $values = explode(',',$pcs[1]);
194 reset($values);
195 while(list(,$test)=each($values)) {
196 $test = trim($test);
197 if (t3lib_div::testInt($test)) {$test='='.$test;}
198 if ($test) {
199 if ($this->testNumber($test,$theTestValue)) {return true;}
200 }
201 }
202 break;
203 case 'usergroup':
204 if ($GLOBALS['TSFE']->gr_list!='0,-1') { // '0,-1' is the default usergroups when not logged in!
205 $values = explode(',',$pcs[1]);
206 while(list(,$test)=each($values)) {
207 $test = trim($test);
208 if ($test) {
209 if ($test=='*' || t3lib_div::inList($GLOBALS['TSFE']->gr_list,$test)) {return true;}
210 }
211 }
212 }
213 break;
214 case 'loginUser':
215 if ($GLOBALS['TSFE']->loginUser) {
216 $values = explode(',',$pcs[1]);
217 while(list(,$test)=each($values)) {
218 $test = trim($test);
219 if ($test) {
220 if ($test=='*' || !strcmp($GLOBALS['TSFE']->fe_user->user['uid'],$test)) {return true;}
221 }
222 }
223 }
224 break;
225 case 'globalVar':
226 $values = explode(',',$pcs[1]);
227 while(list(,$test)=each($values)) {
228 $test = trim($test);
229 if ($test) {
230 $point = strcspn($test,'=<>');
231 $theVarName = substr($test,0,$point);
232 $nv = $this->getGP_ENV_TSFE(trim($theVarName));
233 if ($this->testNumber(substr($test,$point) ,$nv)) {return true;}
234 }
235 }
236 break;
237 case 'globalString':
238 $values = explode(',',$pcs[1]);
239 while(list(,$test)=each($values)) {
240 $test = trim($test);
241 if ($test) {
242 $point = strcspn($test,'=');
243 $theVarName = substr($test,0,$point);
244 $nv = $this->getGP_ENV_TSFE(trim($theVarName));
245 if ($this->matchWild($nv,trim(substr($test,$point+1)))) {return true;}
246 }
247 }
248 break;
249 case 'treeLevel':
250 $values = explode(',',$pcs[1]);
251 $theRootLine = is_array($GLOBALS['TSFE']->tmpl->rootLine) ? $GLOBALS['TSFE']->tmpl->rootLine : $this->altRootLine;
252 $theRLC = count($theRootLine)-1;
253 while(list(,$test)=each($values)) {
254 $test = trim($test);
255 if ($test==$theRLC) { return true; }
256 }
257 break;
258 case 'PIDupinRootline':
259 case 'PIDinRootline':
260 $values = explode(',',$pcs[1]);
261 if (($switchKey=='PIDinRootline') || (!in_array($GLOBALS['TSFE']->id,$values))) {
262 $theRootLine = is_array($GLOBALS['TSFE']->tmpl->rootLine) ? $GLOBALS['TSFE']->tmpl->rootLine : $this->altRootLine;
263 reset($values);
264 while(list(,$test)=each($values)) {
265 $test = trim($test);
266 reset($theRootLine);
267 while(list($rl_key,$rl_dat)=each($theRootLine)) {
268 if ($rl_dat['uid']==$test) { return true; }
269 }
270 }
271 }
272 break;
273 case 'userFunc':
274 $values = split('\(|\)',$pcs[1]);
275 $funcName=trim($values[0]);
276 $funcValue = t3lib_div::trimExplode(',',$values[1]);
277 $pre = $GLOBALS['TSFE']->TYPO3_CONF_VARS['FE']['userFuncClassPrefix'];
278 if ($pre &&
279 !t3lib_div::isFirstPartOfStr(trim($funcName),$pre) &&
280 !t3lib_div::isFirstPartOfStr(trim($funcName),'tx_')
281 ) {
282 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('Match condition: Function "'.$funcName.'" was not prepended with "'.$pre.'"',3);
283 return false;
284 }
285 if (function_exists($funcName) && call_user_func($funcName, $funcValue[0])) {
286 return true;
287 }
288 break;
289 }
290 }
291 }
292
293 /**
294 * Will evaluate a $value based on an operator: "<", ">" or "=" (default)
295 *
296 * @param string The value to compare with on the form [operator][number]. Eg. "< 123"
297 * @param integer The number
298 * @return boolean If $value is "50" and $test is "< 123" then it will return true.
299 */
300 function testNumber($test,$value) {
301 $test = trim($test);
302 switch(substr($test,0,1)) {
303 case '<':
304 if (doubleval(substr($test,1))>$value) return true;
305 break;
306 case '>':
307 if (doubleval(substr($test,1))<$value) return true;
308 break;
309 default:
310 if (trim(substr($test,1))==$value) return true;
311 break;
312 }
313 }
314
315 /**
316 * Matching two strings against each other, supporting a "*" wildcard in either end of the $needle
317 *
318 * @param string The string in which to find $needle.
319 * @param string The string to find in $haystack
320 * @return boolean Returns true if $needle matches or is found in (according to wildcards) in $haystack. Eg. if $haystack is "Netscape 6.5" and $needle is "Net*" or "Netscape*" then it returns true.
321 */
322 function matchWild($haystack,$needle) {
323 if ($needle && $haystack) {
324 if (substr($needle,0,1)=='*') {$mode.='before';}
325 if (substr($needle,-1,1)=='*') {$mode.='after';}
326 switch($mode) {
327 case 'before':
328 $matchStr = substr($needle,1);
329 if (substr($haystack,-strlen($matchStr))==$matchStr) return true;
330 break;
331 case 'after':
332 if (strpos(' '.$haystack,substr($needle,0,-1))==1) return true;
333 break;
334 case 'beforeafter':
335 if (strstr($haystack,substr($needle,1,-1))) return true;
336 break;
337 default:
338 if ($needle==$haystack) return true;
339 break;
340 }
341 }
342 }
343
344 /**
345 * Returns a code for a browsing device based on the input useragent string
346 *
347 * @param string User agent string from browser, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
348 * @return string A code. See link.
349 * @access private
350 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=296&cHash=a8ae66c7d6
351 */
352 function whichDevice($useragent) {
353 $agent=strtolower(trim($useragent));
354 // pda
355 if( strstr($agent, 'avantgo')) {
356 return 'pda';
357 }
358
359 // wap
360 $browser=substr($agent,0,4);
361 $wapviwer=substr(stristr($agent,'wap'),0,3);
362 if( $wapviwer=='wap' ||
363 $browser=='noki' ||
364 $browser== 'eric' ||
365 $browser== 'r380' ||
366 $browser== 'up.b' ||
367 $browser== 'winw' ||
368 $browser== 'wapa') {
369 return 'wap';
370 }
371
372 // grabber
373 if( strstr($agent, 'g.r.a.b.') ||
374 strstr($agent, 'utilmind httpget') ||
375 strstr($agent, 'webcapture') ||
376 strstr($agent, 'teleport') ||
377 strstr($agent, 'webcopier')) {
378 return 'grabber';
379 }
380
381 // robots
382 if( strstr($agent, 'crawler') ||
383 strstr($agent, 'spider') ||
384 strstr($agent, 'googlebot') ||
385 strstr($agent, 'searchbot') ||
386 strstr($agent, 'infoseek') ||
387 strstr($agent, 'altavista') ||
388 strstr($agent, 'diibot')) {
389 return 'robot';
390 }
391 }
392
393 /**
394 * Generates an array with abstracted browser information
395 * In the function match() this method is called and the result stored in $this->browserInfoArray
396 *
397 * @param string The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
398 * @return array Contains keys "browser", "version", "system"
399 * @access private
400 * @see match()
401 */
402 function browserInfo($useragent) {
403 $useragent = trim($useragent);
404 $browserInfo=Array();
405 $browserInfo['useragent']=$useragent;
406 if ($useragent) {
407 // browser
408 if (strstr($useragent,'MSIE')) {
409 $browserInfo['browser']='msie';
410 } elseif(strstr($useragent,'Opera')) {
411 $browserInfo['browser']='opera';
412 } elseif(strstr($useragent,'Lynx')) {
413 $browserInfo['browser']='lynx';
414 } elseif(strstr($useragent,'PHP')) {
415 $browserInfo['browser']='php';
416 } elseif(strstr($useragent,'AvantGo')) {
417 $browserInfo['browser']='avantgo';
418 } elseif(strstr($useragent,'WebCapture')) {
419 $browserInfo['browser']='acrobat';
420 } elseif(strstr($useragent,'IBrowse')) {
421 $browserInfo['browser']='ibrowse';
422 } elseif(strstr($useragent,'Teleport')) {
423 $browserInfo['browser']='teleport';
424 } elseif(strstr($useragent,'Mozilla')) {
425 $browserInfo['browser']='netscape';
426 } else {
427 $browserInfo['browser']='unknown';
428 }
429 // version
430 switch($browserInfo['browser']) {
431 case 'netscape':
432 $browserInfo['version'] = doubleval(substr($useragent,8));
433 if (strstr($useragent,'Netscape6')) {$browserInfo['version']=6;}
434 break;
435 case 'msie':
436 $tmp = strstr($useragent,'MSIE');
437 $browserInfo['version'] = doubleval(substr($tmp,4));
438 break;
439 case 'opera':
440 $tmp = strstr($useragent,'Opera');
441 $browserInfo['version'] = doubleval(substr($tmp,5));
442 break;
443 case 'lynx':
444 $tmp = strstr($useragent,'Lynx/');
445 $browserInfo['version'] = doubleval(substr($tmp,5));
446 break;
447 case 'php':
448 $tmp = strstr($useragent,'PHP/');
449 $browserInfo['version'] = doubleval(substr($tmp,4));
450 break;
451 case 'avantgo':
452 $tmp = strstr($useragent,'AvantGo');
453 $browserInfo['version'] = doubleval(substr($tmp,5));
454 break;
455 case 'acrobat':
456 $tmp = strstr($useragent,'WebCapture');
457 $browserInfo['version'] = doubleval(substr($tmp,5));
458 break;
459 case 'ibrowse':
460 $tmp = strstr($useragent,'IBrowse/');
461 $browserInfo['version'] = doubleval(substr($tmp,5));
462 break;
463 }
464 // system
465 $browserInfo['system']='';
466 if (strstr($useragent,'Win')) {
467 // windows
468 if (strstr($useragent,'Win98') || strstr($useragent,'Windows 98')) {
469 $browserInfo['system']='win98';
470 } elseif (strstr($useragent,'Win95') || strstr($useragent,'Windows 95')) {
471 $browserInfo['system']='win95';
472 } elseif (strstr($useragent,'WinNT') || strstr($useragent,'Windows NT')) {
473 $browserInfo['system']='winNT';
474 } elseif (strstr($useragent,'Win16') || strstr($useragent,'Windows 311')) {
475 $browserInfo['system']='win311';
476 }
477 } elseif (strstr($useragent,'Mac')) {
478 $browserInfo['system']='mac';
479 // unixes
480 } elseif (strstr($useragent,'Linux')) {
481 $browserInfo['system']='linux';
482 } elseif (strstr($useragent,'SGI') && strstr($useragent,' IRIX ')) {
483 $browserInfo['system']='unix_sgi';
484 } elseif (strstr($useragent,' SunOS ')) {
485 $browserInfo['system']='unix_sun';
486 } elseif (strstr($useragent,' HP-UX ')) {
487 $browserInfo['system']='unix_hp';
488 }
489 }
490 return $browserInfo;
491 }
492
493 /**
494 * Return global variable where the input string $var defines array keys separated by "|"
495 *
496 * @param string Global var key, eg. "HTTP_GET_VAR" or "HTTP_GET_VARS|id" to get the id GET parameter back.
497 * @param array Alternative array than $GLOBAL to get variables from.
498 * @return mixed Whatever value. If none, then blank string.
499 * @access private
500 */
501 function getGlobal($var,$inArr='') {
502 $vars = explode('|',$var);
503 $c = count($vars);
504 $k = trim($vars[0]);
505 $theVar = is_array($inArr) ? $inArr[$k] : $GLOBALS[$k];
506
507 for ($a=1;$a<$c;$a++) {
508 if (!isset($theVar)) {break;}
509 $theVar = $theVar[trim($vars[$a])];
510 }
511 if (!is_array($theVar)) {
512 return $theVar;
513 } else {
514 return '';
515 }
516 }
517
518 /**
519 * Returns GP / ENV / TSFE vars
520 *
521 * @param string Identifier
522 * @return mixed The value of the variable pointed to.
523 * @access private
524 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=311&cHash=487cbd5cdf
525 */
526 function getGP_ENV_TSFE($var) {
527 $vars = explode(':',$var,2);
528 if (count($vars)==1) {
529 $val = $this->getGlobal($var);
530 } else {
531 $splitAgain=explode('|',$vars[1],2);
532 $k=trim($splitAgain[0]);
533 if ($k) {
534 switch((string)trim($vars[0])) {
535 case 'GP':
536 $val = t3lib_div::GPvar($k);
537 break;
538 case 'TSFE':
539 $val = $GLOBALS['TSFE']->$k;
540 break;
541 case 'ENV':
542 $val = getenv($k);
543 break;
544 case 'IENV':
545 $val = t3lib_div::getIndpEnv($k);
546 break;
547 case 'LIT':
548 return trim($vars[1]); // return litteral value...
549 break;
550 }
551 // If array:
552 if (count($splitAgain)>1) {
553 if (is_array($val) && trim($splitAgain[1])) {
554 $val=$this->getGlobal($splitAgain[1],$val);
555 } else {
556 $val='';
557 }
558 }
559 }
560 }
561 return $val;
562 }
563 }
564
565
566 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_matchcondition.php']) {
567 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_matchcondition.php']);
568 }
569 ?>