/** * Unit test the asSplitStringOnExpressions() function to ensure that accurately parses out all expressions * surrounded by curly braces, allowing for strings and escaped curly braces. */ public function oldStringSplitter() { $tests = <<<EOD This string does not contain an expression "This is only a string" "this is a string that contains {something in curly brace}" How about nested curly braces, like {INSERTANS:{SGQ}}? This example has escaped curly braces like \\{this is not an equation\\} Should the parser check for unmatched { opening curly braces? What about for unmatched } closing curly braces? What if there is a { space after the opening brace?} What about a {space before the closing brace }? What about an { expression nested {within a string} that has white space after the opening brace}? This {expression has {a nested curly brace { plus ones with whitespace around them} - they should be properly captured} into an expression with sub-expressions. This {is a string {since it does not close } all of its curly} braces. Can {expressions contain 'single' or "double" quoted strings}? Can an expression contain a perl regular expression like this {'/^\\d{3}-\\d{2}-\\d{4}\$/'}? [img src="images/mine_{Q1}.png"/] [img src="images/mine_" + {Q1} + ".png"/] [img src={implode('','"images/mine_',Q1,'.png"')}/] [img src="images/mine_{if(Q1=="Y",'yes','no')}.png"/] [img src="images/mine_{if(Q1=="Y",'sq with {nested braces}',"dq with {nested braces}")}.png"/] {name}, you said that you are {age} years old, and that you have {numKids} {if((numKids==1),'child','children')} and {numPets} {if((numPets==1),'pet','pets')} running around the house. So, you have {numKids + numPets} wild {if((numKids + numPets ==1),'beast','beasts')} to chase around every day. Since you have more {if((INSERT61764X1X3 > INSERT61764X1X4),'children','pets')} than you do {if((INSERT61764X1X3 > INSERT61764X1X4),'pets','children')}, do you feel that the {if((INSERT61764X1X3 > INSERT61764X1X4),'pets','children')} are at a disadvantage? Here is a String that failed to parse prior to fixing the preg_split() command to avoid recursive search of sub-strings: [{((617167X9X3241 == "Y" or 617167X9X3242 == "Y" or 617167X9X3243 == "Y" or 617167X9X3244 == "Y" or 617167X9X3245 == "Y" or 617167X9X3246 == "Y" or 617167X9X3247 == "Y" or 617167X9X3248 == "Y" or 617167X9X3249 == "Y") and (617167X9X3301 == "Y" or 617167X9X3302 == "Y" or 617167X9X3303 == "Y" or 617167X9X3304 == "Y" or 617167X9X3305 == "Y" or 617167X9X3306 == "Y" or 617167X9X3307 == "Y" or 617167X9X3308 == "Y" or 617167X9X3309 == "Y"))}] Here is the question. EOD; // Here is a String that failed to parse prior to fixing the preg_split() command to avoid recursive search of sub-strings: [{((617167X9X3241 == "Y" or 617167X9X3242 == "Y" or 617167X9X3243 == "Y" or 617167X9X3244 == "Y" or 617167X9X3245 == "Y" or 617167X9X3246 == "Y" or 617167X9X3247 == "Y" or 617167X9X3248 == "Y" or 617167X9X3249 == "Y") and (617167X9X3301 == "Y" or 617167X9X3302 == "Y" or 617167X9X3303 == "Y" or 617167X9X3304 == "Y" or 617167X9X3305 == "Y" or 617167X9X3306 == "Y" or 617167X9X3307 == "Y" or 617167X9X3308 == "Y" or 617167X9X3309 == "Y"))}] Here is the question. $em = new ExpressionManager(); $atests = explode("\n", $tests); array_push($atests, '"hi\\nthere\\nhow\\nare\\nyou?\\n"'); foreach ($atests as $test) { $tokens = $em->asSplitStringOnExpressions($test); print '<b>' . $test . '</b><hr/>'; print '<code>'; print implode("<br/>\n", explode("\n", print_r($tokens, TRUE))); print '</code><hr/>'; } }
/** * Remove any script or dangerous HTML * * @param string $value */ public function xssFilter($value) { $filter = new CHtmlPurifier(); $filter->options = array('AutoFormat.RemoveEmpty' => false, 'Core.NormalizeNewlines' => false, 'CSS.AllowTricky' => true, 'HTML.SafeObject' => true, 'Output.FlashCompat' => true, 'Attr.EnableID' => true, 'Attr.AllowedFrameTargets' => array('_blank', '_self'), 'URI.AllowedSchemes' => array('http' => true, 'https' => true, 'mailto' => true, 'ftp' => true, 'nntp' => true, 'news' => true)); // To allow script BUT purify : HTML.Trusted=true (plugin idea for admin or without XSS filtering ?) /** Start to get complete filtered value with url decode {QCODE} (bug #09300). This allow only question number in url, seems OK with XSS protection **/ $sFiltered = preg_replace('#%7B([a-zA-Z0-9\\.]*)%7D#', '{$1}', $filter->purify($value)); Yii::import('application.helpers.expressions.em_core_helper'); // Already imported in em_manager_helper.php ? $oExpressionManager = new ExpressionManager(); /** We get 2 array : one filtered, other unfiltered **/ $aValues = $oExpressionManager->asSplitStringOnExpressions($value); // Return array of array : 0=>the string,1=>string length,2=>string type (STRING or EXPRESSION) $aFilteredValues = $oExpressionManager->asSplitStringOnExpressions($sFiltered); // Same but for the filtered string $bCountIsOk = count($aValues) == count($aFilteredValues); /** Construction of new string with unfiltered EM and filtered HTML **/ $sNewValue = ""; foreach ($aValues as $key => $aValue) { if ($aValue[2] == "STRING") { $sNewValue .= $bCountIsOk ? $aFilteredValues[$key][0] : $filter->purify($aValue[0]); } else { $sExpression = trim($aValue[0], '{}'); $sNewValue .= "{"; $aParsedExpressions = $oExpressionManager->Tokenize($sExpression, true); foreach ($aParsedExpressions as $aParsedExpression) { if ($aParsedExpression[2] == 'DQ_STRING') { $sNewValue .= "\"" . $filter->purify($aParsedExpression[0]) . "\""; } elseif ($aParsedExpression[2] == 'SQ_STRING') { $sNewValue .= "'" . $filter->purify($aParsedExpression[0]) . "'"; } else { $sNewValue .= $aParsedExpression[0]; } } $sNewValue .= "}"; } } gc_collect_cycles(); // To counter a high memory usage of HTML-Purifier return $sNewValue; }
/** * Remove any script or dangerous HTML * * @param string $value */ public function xssFilter($value) { $filter = new CHtmlPurifier(); $filter->options = array('AutoFormat.RemoveEmpty' => false, 'CSS.AllowTricky' => true, 'HTML.SafeObject' => true, 'Output.FlashCompat' => true, 'Attr.EnableID' => true, 'Attr.AllowedFrameTargets' => array('_blank', '_self'), 'URI.AllowedSchemes' => array('http' => true, 'https' => true, 'mailto' => true, 'ftp' => true, 'nntp' => true, 'news' => true)); // To allow script BUT purify : HTML.Trusted=true (plugin idea for admin or without XSS filtering ?) Yii::import('application.helpers.expressions.em_core_helper'); // Already imported in em_manager_helper.php ? $oExpressionManager = new ExpressionManager(); $aValues = $oExpressionManager->asSplitStringOnExpressions($value); // Return array of array : 0=>the string,1=>string length,2=>string type (STRING or EXPRESSION) $sNewValue = ""; foreach ($aValues as $aValue) { if ($aValue[2] == "STRING") { $sNewValue .= $filter->purify($aValue[0]); } else { $sExpression = trim($aValue[0], '{}'); $sNewValue .= "{"; $aParsedExpressions = $oExpressionManager->Tokenize($sExpression, true); // Return array of array : 0=>the string,1=>string length,2=>string type foreach ($aParsedExpressions as $aParsedExpression) { if ($aParsedExpression[2] == 'DQ_STRING') { $sNewValue .= "\"" . $filter->purify($aParsedExpression[0]) . "\""; } elseif ($aParsedExpression[2] == 'SQ_STRING') { $sNewValue .= "'" . $filter->purify($aParsedExpression[0]) . "'"; } else { $sNewValue .= $aParsedExpression[0]; } } $sNewValue .= "}"; } } return $sNewValue; }