Fixed bug #12017: Wrong Inclusion in tceforms and tceforms_fe
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_matchcondition.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2009 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 * 80: class t3lib_matchCondition
41 * 87: function __construct()
42 * 105: function t3lib_matchCondition()
43 * 115: function match($condition_line)
44 * 160: function evalConditionStr($string)
45 * 381: function testNumber($test,$value)
46 * 405: function matchWild($haystack,$needle)
47 * 429: function whichDevice($useragent)
48 * 498: function browserInfo($useragent)
49 * 611: function browserInfo_version($tmp)
50 * 624: function getGlobal($var, $source=NULL)
51 * 658: function getGP_ENV_TSFE($var)
52 *
53 * TOTAL FUNCTIONS: 11
54 * (This index is automatically created/updated by the extension "extdeveval")
55 *
56 */
57
58
59
60
61
62
63
64
65
66
67
68
69 /**
70 * Matching TypoScript conditions
71 *
72 * Used with the TypoScript parser.
73 * Matches browserinfo, IPnumbers for use with templates
74 *
75 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
76 * @package TYPO3
77 * @subpackage t3lib
78 * @see t3lib_TStemplate::matching(), t3lib_TStemplate::generateConfig()
79 */
80 class t3lib_matchCondition {
81 var $matchAlternative=array(); // If this array has elements, the matching returns true if a whole "matchline" is found in the array!
82 var $matchAll=0; // If set all is matched!
83
84 var $altRootLine=array();
85 var $hookObjectsArr = array();
86
87 /**
88 * Constructor for this class
89 *
90 * @return void
91 */
92 function __construct() {
93 global $TYPO3_CONF_VARS;
94
95 // Usage (ext_localconf.php):
96 // $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'][] =
97 // 'EXT:my_ext/class.browserinfo.php:MyBrowserInfoClass';
98 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'])) {
99 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'] as $classRef) {
100 $this->hookObjectsArr[] = t3lib_div::getUserObj($classRef, '');
101 }
102 }
103 }
104
105 /**
106 * Constructor for this class
107 *
108 * @return void
109 */
110 function t3lib_matchCondition() {
111 $this->__construct();
112 }
113
114 /**
115 * Matching TS condition
116 *
117 * @param string Line to match
118 * @return boolean True if matched
119 */
120 function match($condition_line) {
121 if ($this->matchAll) {
122 return true;
123 }
124 if (count($this->matchAlternative)) {
125 return in_array($condition_line, $this->matchAlternative);
126 }
127
128 // Getting the value from inside of the wrapping square brackets of the condition line:
129 $insideSqrBrackets = substr(trim($condition_line), 1, strlen($condition_line) - 2);
130 $insideSqrBrackets = preg_replace('/\]\s*OR\s*\[/i', ']||[', $insideSqrBrackets);
131 $insideSqrBrackets = preg_replace('/\]\s*AND\s*\[/i', ']&&[', $insideSqrBrackets);
132
133 // The "weak" operator "||" (OR) takes precedence: backwards compatible, [XYZ][ZYX] does still work as OR
134 $orParts = preg_split('/\]\s*(\|\|){0,1}\s*\[/',$insideSqrBrackets);
135
136 foreach ($orParts as $partString) {
137 $matches = false;
138
139 // Splits by the "&&" (AND) operator:
140 $andParts = preg_split('/\]\s*&&\s*\[/',$partString);
141 foreach ($andParts as $condStr) {
142 $matches = $this->evalConditionStr($condStr);
143 if ($matches===false) {
144 break; // only true AND true = true, so we have to break here
145 }
146 }
147
148 if ($matches===true) {
149 break; // true OR false = true, so we break if we have a positive result
150 }
151 }
152
153 return $matches;
154 }
155
156
157 /**
158 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
159 *
160 * @param string The condition to match against its criterias.
161 * @return boolean Returns true or false based on the evaluation.
162 * @see t3lib_tsparser::parse()
163 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=292&cHash=c6c7d43d2f
164 */
165 function evalConditionStr($string) {
166 if (!is_array($this->altRootLine)) {
167 $this->altRootLine = array();
168 }
169 list($key, $value) = explode('=', $string, 2);
170 $key = trim($key);
171 $value = trim($value);
172 if (t3lib_div::inList('browser,version,system,useragent', strtolower($key))) {
173 $browserInfo = $this->browserInfo(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
174 }
175 switch ($key) {
176 case 'browser':
177 $values = t3lib_div::trimExplode(',', $value, true);
178 foreach ($values as $test) {
179 if (strpos($browserInfo['browser'] . $browserInfo['version'], $test) !== false) {
180 return true;
181 }
182 }
183 break;
184 case 'version':
185 $values = t3lib_div::trimExplode(',', $value, true);
186 foreach ($values as $test) {
187 if (strcspn($test, '=<>') == 0) {
188 switch (substr($test, 0, 1)) {
189 case '=':
190 if (doubleval(substr($test, 1)) == $browserInfo['version']) {
191 return true;
192 }
193 break;
194 case '<':
195 if (doubleval(substr($test, 1)) > $browserInfo['version']) {
196 return true;
197 }
198 break;
199 case '>':
200 if (doubleval(substr($test, 1)) < $browserInfo['version']) {
201 return true;
202 }
203 break;
204 }
205 } else {
206 if (strpos(' ' . $browserInfo['version'], $test) == 1) {
207 return true;
208 }
209 }
210 }
211 break;
212 case 'system':
213 $values = t3lib_div::trimExplode(',', $value, true);
214 foreach ($values as $test) {
215 if (strpos(' ' . $browserInfo['system'], $test) == 1) {
216 return true;
217 }
218 }
219 break;
220 case 'device':
221 if (!isset($this->deviceInfo)) {
222 $this->deviceInfo = $this->whichDevice(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
223 }
224 $values = t3lib_div::trimExplode(',', $value, true);
225 foreach ($values as $test) {
226 if ($this->deviceInfo == $test) {
227 return true;
228 }
229 }
230 break;
231 case 'useragent':
232 $test = trim($value);
233 if (strlen($test)) {
234 return $this->matchWild($browserInfo['useragent'], $test);
235 }
236 break;
237 case 'language':
238 $values = t3lib_div::trimExplode(',', $value, true);
239 foreach ($values as $test) {
240 if (preg_match('/^\*.+\*$/', $test)) {
241 $allLanguages = preg_split('/[,;]/', t3lib_div::getIndpEnv('HTTP_ACCEPT_LANGUAGE'));
242 if (in_array(substr($test, 1, -1), $allLanguages)) {
243 return true;
244 }
245 } else if (t3lib_div::getIndpEnv('HTTP_ACCEPT_LANGUAGE') == $test) {
246 return true;
247 }
248 }
249 break;
250 case 'IP':
251 if (t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $value)) {
252 return true;
253 }
254 break;
255 case 'hostname':
256 if (t3lib_div::cmpFQDN(t3lib_div::getIndpEnv('REMOTE_ADDR'), $value)) {
257 return true;
258 }
259 break;
260 // hour, minute, dayofweek, dayofmonth, month, year, julianday
261 case 'hour':
262 case 'minute':
263 case 'month':
264 case 'year':
265 case 'dayofweek':
266 case 'dayofmonth':
267 case 'dayofyear':
268 $theEvalTime = $GLOBALS['SIM_EXEC_TIME']; // In order to simulate time properly in templates.
269 switch($key) {
270 case 'hour': $theTestValue = date('H', $theEvalTime); break;
271 case 'minute': $theTestValue = date('i', $theEvalTime); break;
272 case 'month': $theTestValue = date('m', $theEvalTime); break;
273 case 'year': $theTestValue = date('Y', $theEvalTime); break;
274 case 'dayofweek': $theTestValue = date('w', $theEvalTime); break;
275 case 'dayofmonth': $theTestValue = date('d', $theEvalTime); break;
276 case 'dayofyear': $theTestValue = date('z', $theEvalTime); break;
277 }
278 $theTestValue = intval($theTestValue);
279 // comp
280 $values = t3lib_div::trimExplode(',', $value, true);
281 foreach ($values as $test) {
282 if (t3lib_div::testInt($test)) {
283 $test = '=' . $test;
284 }
285 if ($this->testNumber($test, $theTestValue)) {
286 return true;
287 }
288 }
289 break;
290 case 'usergroup':
291 if ($GLOBALS['TSFE']->gr_list != '0,-1') { // '0,-1' is the default usergroups when not logged in!
292 $values = t3lib_div::trimExplode(',', $value, true);
293 foreach ($values as $test) {
294 if ($test == '*' || t3lib_div::inList($GLOBALS['TSFE']->gr_list, $test)) {
295 return true;
296 }
297 }
298 }
299 break;
300 case 'loginUser':
301 if ($GLOBALS['TSFE']->loginUser) {
302 $values = t3lib_div::trimExplode(',', $value, true);
303 foreach ($values as $test) {
304 if ($test == '*' || !strcmp($GLOBALS['TSFE']->fe_user->user['uid'], $test)) {
305 return true;
306 }
307 }
308 }
309 break;
310 case 'globalVar':
311 $values = t3lib_div::trimExplode(',', $value, true);
312 foreach ($values as $test) {
313 $point = strcspn($test, '!=<>');
314 $theVarName = substr($test, 0, $point);
315 $nv = $this->getGP_ENV_TSFE(trim($theVarName));
316 $testValue = substr($test, $point);
317
318 if ($this->testNumber($testValue, $nv)) {
319 return true;
320 }
321 }
322 break;
323 case 'globalString':
324 $values = t3lib_div::trimExplode(',', $value, true);
325 foreach ($values as $test) {
326 $point = strcspn($test, '=');
327 $theVarName = substr($test, 0, $point);
328 $nv = $this->getGP_ENV_TSFE(trim($theVarName));
329 $testValue = substr($test, $point+1);
330
331 if ($this->matchWild($nv, trim($testValue))) {
332 return true;
333 }
334 }
335 break;
336 case 'treeLevel':
337 $values = t3lib_div::trimExplode(',', $value, true);
338 $theRootLine = is_array($GLOBALS['TSFE']->tmpl->rootLine) ? $GLOBALS['TSFE']->tmpl->rootLine : $this->altRootLine;
339 $treeLevel = count($theRootLine)-1;
340 foreach ($values as $test) {
341 if ($test == $treeLevel) {
342 return true;
343 }
344 }
345 break;
346 case 'PIDupinRootline':
347 case 'PIDinRootline':
348 $values = t3lib_div::trimExplode(',', $value, true);
349 if (($key=='PIDinRootline') || (!in_array($GLOBALS['TSFE']->id, $values))) {
350 $theRootLine = is_array($GLOBALS['TSFE']->tmpl->rootLine) ? $GLOBALS['TSFE']->tmpl->rootLine : $this->altRootLine;
351 foreach ($values as $test) {
352 foreach ($theRootLine as $rl_dat) {
353 if ($rl_dat['uid'] == $test) {
354 return true;
355 }
356 }
357 }
358 }
359 break;
360 case 'compatVersion':
361 return t3lib_div::compat_version($value);
362 break;
363 case 'userFunc':
364 $values = preg_split('/\(|\)/', $value);
365 $funcName = trim($values[0]);
366 $funcValue = t3lib_div::trimExplode(',', $values[1]);
367 $pre = $GLOBALS['TSFE']->TYPO3_CONF_VARS['FE']['userFuncClassPrefix'];
368 if ($pre &&
369 !t3lib_div::isFirstPartOfStr(trim($funcName),$pre) &&
370 !t3lib_div::isFirstPartOfStr(trim($funcName),'tx_')
371 ) {
372 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('Match condition: Function "'.$funcName.'" was not prepended with "'.$pre.'"',3);
373 return false;
374 }
375 if (function_exists($funcName) && call_user_func($funcName, $funcValue[0])) {
376 return true;
377 }
378 break;
379 }
380
381
382 return false;
383 }
384
385 /**
386 * Evaluates a $leftValue based on an operator: "<", ">", "<=", ">=", "!=" or "="
387 *
388 * @param string $test: The value to compare with on the form [operator][number]. Eg. "< 123"
389 * @param integer $leftValue: The value on the left side
390 * @return boolean If $value is "50" and $test is "< 123" then it will return true.
391 */
392 function testNumber($test, $leftValue) {
393 if (preg_match('/^(!?=+|<=?|>=?)\s*([^\s]*)\s*$/', $test, $matches)) {
394 $operator = $matches[1];
395 $rightValue = $matches[2];
396
397 switch ($operator) {
398 case '>=':
399 return ($leftValue >= doubleval($rightValue));
400 break;
401 case '<=':
402 return ($leftValue <= doubleval($rightValue));
403 break;
404 case '!=':
405 return ($leftValue != doubleval($rightValue));
406 break;
407 case '<':
408 return ($leftValue < doubleval($rightValue));
409 break;
410 case '>':
411 return ($leftValue > doubleval($rightValue));
412 break;
413 default:
414 // nothing valid found except '=', use '='
415 return ($leftValue == trim($rightValue));
416 break;
417 }
418 }
419
420 return false;
421 }
422
423 /**
424 * Matching two strings against each other, supporting a "*" wildcard or (if wrapped in "/") PCRE regular expressions
425 *
426 * @param string The string in which to find $needle.
427 * @param string The string to find in $haystack
428 * @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 "Net*ape" then it returns true.
429 */
430 function matchWild($haystack, $needle) {
431 $result = false;
432
433 if ($needle) {
434 if (preg_match('/^\/.+\/$/', $needle)) {
435 // Regular expression, only "//" is allowed as delimiter
436 $regex = $needle;
437 } else {
438 $needle = str_replace(array('*', '?'), array('###MANY###', '###ONE###'), $needle);
439 $regex = '/^' . preg_quote($needle, '/') . '$/';
440 // Replace the marker with .* to match anything (wildcard)
441 $regex = str_replace(array('###MANY###', '###ONE###'), array('.*' , '.'), $regex);
442 }
443
444 $result = (boolean)preg_match($regex, (string)$haystack);
445 }
446
447 return $result;
448 }
449
450 /**
451 * Returns a code for a browsing device based on the input useragent string
452 *
453 * @param string User agent string from browser, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
454 * @return string A code. See link.
455 * @access private
456 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=296&cHash=a8ae66c7d6
457 */
458 function whichDevice($useragent) {
459 foreach($this->hookObjectsArr as $hookObj) {
460 if (method_exists($hookObj, 'whichDevice')) {
461 $result = $hookObj->whichDevice($useragent);
462 if (strlen($result)) {
463 return $result;
464 }
465 }
466 }
467
468 // deprecated, see above
469 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['devices_class'])) {
470 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['devices_class'] as $_classRef) {
471 $_procObj = t3lib_div::getUserObj($_classRef);
472 return $_procObj->whichDevice_ext($useragent);
473 }
474 }
475 //
476
477 $agent=strtolower(trim($useragent));
478 // pda
479 if( strstr($agent, 'avantgo')) {
480 return 'pda';
481 }
482
483 // wap
484 $browser=substr($agent,0,4);
485 $wapviwer=substr(stristr($agent,'wap'),0,3);
486 if( $wapviwer=='wap' ||
487 $browser=='noki' ||
488 $browser== 'eric' ||
489 $browser== 'r380' ||
490 $browser== 'up.b' ||
491 $browser== 'winw' ||
492 $browser== 'wapa') {
493 return 'wap';
494 }
495
496 // grabber
497 if( strstr($agent, 'g.r.a.b.') ||
498 strstr($agent, 'utilmind httpget') ||
499 strstr($agent, 'webcapture') ||
500 strstr($agent, 'teleport') ||
501 strstr($agent, 'webcopier')) {
502 return 'grabber';
503 }
504
505 // robots
506 if( strstr($agent, 'crawler') ||
507 strstr($agent, 'spider') ||
508 strstr($agent, 'googlebot') ||
509 strstr($agent, 'searchbot') ||
510 strstr($agent, 'infoseek') ||
511 strstr($agent, 'altavista') ||
512 strstr($agent, 'diibot')) {
513 return 'robot';
514 }
515
516 }
517
518 /**
519 * Generates an array with abstracted browser information
520 * This method is used in the function match() in this class
521 *
522 * @param string The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
523 * @return array Contains keys "browser", "version", "system"
524 * @access private
525 * @see match()
526 */
527 function browserInfo($useragent) {
528 foreach($this->hookObjectsArr as $hookObj) {
529 if (method_exists($hookObj, 'browserInfo')) {
530 $result = $hookObj->browserInfo($useragent);
531 if (strlen($result)) {
532 return $result;
533 }
534 }
535 }
536
537 $browserInfo = t3lib_utility_Client::getBrowserInfo($useragent);
538
539 return $browserInfo;
540 }
541
542 /**
543 * 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.
544 *
545 * @param string A string with version number, eg. "/7.32 blablabla"
546 * @return double Returns double value, eg. "7.32"
547 * @deprecated since TYPO3 4.3 - use t3lib_utility_Client::getVersion() instead
548 */
549 function browserInfo_version($tmp) {
550 t3lib_div::logDeprecatedFunction();
551 return t3lib_utility_Client::getVersion($tmp);
552 }
553
554 /**
555 * Return global variable where the input string $var defines array keys separated by "|"
556 * Example: $var = "HTTP_SERVER_VARS | something" will return the value $GLOBALS['HTTP_SERVER_VARS']['something'] value
557 *
558 * @param string Global var key, eg. "HTTP_GET_VAR" or "HTTP_GET_VARS|id" to get the GET parameter "id" back.
559 * @param array Alternative array than $GLOBAL to get variables from.
560 * @return mixed Whatever value. If none, then blank string.
561 * @access private
562 */
563 function getGlobal($var, $source=NULL) {
564 $vars = explode('|',$var);
565 $c = count($vars);
566 $k = trim($vars[0]);
567 $theVar = isset($source) ? $source[$k] : $GLOBALS[$k];
568
569 for ($a=1;$a<$c;$a++) {
570 if (!isset($theVar)) { break; }
571
572 $key = trim($vars[$a]);
573 if (is_object($theVar)) {
574 $theVar = $theVar->$key;
575 } elseif (is_array($theVar)) {
576 $theVar = $theVar[$key];
577 } else {
578 return '';
579 }
580 }
581
582 if (!is_array($theVar) && !is_object($theVar)) {
583 return $theVar;
584 } else {
585 return '';
586 }
587 }
588
589 /**
590 * Returns GP / ENV / TSFE vars
591 *
592 * @param string Identifier
593 * @return mixed The value of the variable pointed to.
594 * @access private
595 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=311&cHash=487cbd5cdf
596 */
597 function getGP_ENV_TSFE($var) {
598 $vars = explode(':',$var,2);
599 if (count($vars)==1) {
600 $val = $this->getGlobal($var);
601 } else {
602 $splitAgain=explode('|',$vars[1],2);
603 $k=trim($splitAgain[0]);
604 if ($k) {
605 switch((string)trim($vars[0])) {
606 case 'GP':
607 $val = t3lib_div::_GP($k);
608 break;
609 case 'TSFE':
610 $val = $this->getGlobal('TSFE|'.$vars[1]);
611 $splitAgain=0; // getGlobal resolves all parts of the key, so no further splitting is needed
612 break;
613 case 'ENV':
614 $val = getenv($k);
615 break;
616 case 'IENV':
617 $val = t3lib_div::getIndpEnv($k);
618 break;
619 case 'LIT':
620 { return trim($vars[1]); } // return litteral value...
621 break;
622 }
623 // If array:
624 if (count($splitAgain)>1) {
625 if (is_array($val) && trim($splitAgain[1])) {
626 $val=$this->getGlobal($splitAgain[1],$val);
627 } else {
628 $val='';
629 }
630 }
631 }
632 }
633 return $val;
634 }
635 }
636
637
638 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_matchcondition.php']) {
639 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_matchcondition.php']);
640 }
641
642 ?>