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