Commit 819782e7 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Report.php, Variables.php: Using Variables via store in report. Removed 'form2hash()'

Utils.php: removed sanitize() & randomAlphaNumUnique() - this version is nowhere used.
Support.php, BodytextParser.php: outsourced from bodyTextParser encryptDoubleCurlyBraces().
:
parent 12f419c8
......@@ -96,8 +96,7 @@ class BodytextParser {
// Replace '\{' | '\}' by internal token. All remaining '}' | '{' means: 'nested'
$bodytext = str_replace('\{', '#&[_#', $bodytext);
$bodytext = str_replace('\}', '#&]_#', $bodytext);
$bodytext = str_replace('{{', '#&[[_#', $bodytext);
$bodytext = str_replace('}}', '#&]]_#', $bodytext);
$bodytext = Support::encryptDoubleCurlyBraces($bodytext);
$result = $bodytext;
$posFirstClose = strpos($result, '}');
......@@ -143,9 +142,7 @@ class BodytextParser {
$result = str_replace('#&[_#', '{', $result);
$result = str_replace('#&]_#', '}', $result);
$result = str_replace('#&[[_#', '{{', $result);
$result = str_replace('#&]]_#', '}}', $result);
$result = Support::decryptDoubleCurlyBraces($result);
return $result;
}
......
......@@ -84,7 +84,6 @@ class Evaluate {
$posFirstClose = strpos($result, $this->endDelimiter);
while ($posFirstClose !== false) {
$flagTokenReplaced = true;
$posMatchOpen = strrpos(substr($result, 0, $posFirstClose), $this->startDelimiter);
if ($posMatchOpen === false) {
......@@ -96,32 +95,42 @@ class Evaluate {
$match = substr($result, $posMatchOpen + $this->startDelimiterLength, $posFirstClose - $posMatchOpen - $this->startDelimiterLength);
$evaluated = $this->substitute($match, $foundInStore);
$debugLocal[] = $debugIndent . "#Replace: '$match'";
// If an array is returned, break everything and return this assoc array.
if (is_array($evaluated)) {
$result = $evaluated;
$debugLocal[] = $debugIndent . "#By: 'array(" . count($result) . ")'";
break;
}
if ($foundInStore === '') {
// Encode the non replaceable part as preparation not to process again and to recode at the end.
$evaluated = Support::encryptDoubleCurlyBraces($this->startDelimiter . $match . $this->endDelimiter);
$debugLocal[] = $debugIndent . "#By: <nothing found - not replaced>";
} else {
$flagTokenReplaced = true;
$debugLocal[] = $debugIndent . "#By: '$evaluated'";
// If an array is returned, break everything and return this assoc array.
if (is_array($evaluated)) {
$result = $evaluated;
$debugLocal[] = $debugIndent . "#By: 'array(" . count($result) . ")'";
break;
}
// More to substitute in the new evaluated result? Start recursion just with the new result..
if (strpos($evaluated, $this->endDelimiter) !== false) {
$evaluated = $this->parse($evaluated, $recursion + 1, $debugLocal, $foundInStore);
}
$debugLocal[] = $debugIndent . "#By: '$evaluated'";
// More to substitute in the new evaluated result? Start recursion just with the new result..
if (strpos($evaluated, $this->endDelimiter) !== false) {
$evaluated = $this->parse($evaluated, $recursion + 1, $debugLocal, $foundInStore);
}
}
$result = $pre . $evaluated . $post;
$posFirstClose = strpos($result, $this->endDelimiter);
}
if ($flagTokenReplaced === true) {
$debugLocal[] = $debugIndent . "#Final: " . is_array($result) ? "array(" . count($result) .")" : "'$result'" ;
$debugLocal[] = $debugIndent . "#Final: " . is_array($result) ? "array(" . count($result) . ")" : "'$result'";
$debugStack = $debugLocal;
}
return $result;
return Support::decryptDoubleCurlyBraces($result);
}
/**
......@@ -133,7 +142,7 @@ class Evaluate {
* If neither a) or b) match, return the token itself, surrounded by single ticks, to emphase that substition failed.
*
* @param $token
* @param string $foundInStore
* @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found, return ''.
* @return array|mixed|null|string
* @throws CodeException
* @throws DbException
......@@ -154,6 +163,7 @@ class Evaluate {
// SQL Statement?
if (in_array(strtoupper($arr[0] . ' '), $this->sqlKeywords)) {
$foundInStore = 'query';
return $this->db->sql($token, $sqlMode);
}
......@@ -168,8 +178,11 @@ class Evaluate {
// search for value in stores
$value = $this->store->getVar($arr[0], $arr[1], $arr[2], $foundInStore);
// nothing replaced: put ticks around, to sanitize strings for SQL statements. Nothing to substitute is not a wished situation.
return ($value === false) ? "'" . $token . "'" : $value;
// OLD: nothing replaced: put ticks around, to sanitize strings for SQL statements. Nothing to substitute is not a wished situation.
// return ($value === false) ? "'" . $token . "'" : $value;
// NEW: nothing replaced: higher level should decide what to do
return $value;
}
public function getDebug() {
......
......@@ -418,7 +418,7 @@ class QuickFormQuery {
* @return string
*/
private function doReport() {
$report = new Report($this->t3data, $this->store->getVar(SYSTEM_SESSION_NAME, STORE_SYSTEM), $this->phpUnit);
$report = new Report($this->t3data, $this->store->getVar(SYSTEM_SESSION_NAME, STORE_SYSTEM), $this->eval, $this->phpUnit);
$html = $report->process();
......
......@@ -186,4 +186,32 @@ class Support {
return $date . ' ' . $time;
}
/**
* Encrypt curly braces by an uncommon string. Helps preventing unwished action on curly braces.
*
* @param $text
* @return mixed
*/
public static function encryptDoubleCurlyBraces($text) {
$text = str_replace('{{', '#&@[[@_#', $text);
$text = str_replace('}}', '#&@]]@_#', $text);
return $text;
}
/**
* Decrypt curly braces by an uncommon string. Helps preventing unwished action on curly braces
*
* @param $text
* @return mixed
*/
public static function decryptDoubleCurlyBraces($text) {
$text = str_replace('#&@[[@_#', '{{', $text);
$text = str_replace('#&@]]@_#', '}}', $text);
return $text;
}
}
\ No newline at end of file
......@@ -20,6 +20,7 @@ require_once(__DIR__ . '/../Database.php');
require_once(__DIR__ . '/Link.php');
require_once(__DIR__ . '/Sendmail.php');
require_once(__DIR__ . '/../exceptions/UserReportExtension.php');
require_once(__DIR__ . '/../Evaluate.php');
class Report {
......@@ -89,7 +90,7 @@ class Report {
*
* @param array $t3data
*/
public function __construct(array $t3data, $sessionName, $phpUnit = false) {
public function __construct(array $t3data, $sessionName, Evaluate $eval, $phpUnit = false) {
$this->phpUnit = $phpUnit;
......@@ -114,7 +115,7 @@ class Report {
$this->db = new Database();
$this->utils = new Utils();
$this->variables = new Variables($t3data["uid"]);
$this->variables = new Variables($eval, $t3data["uid"]);
// Set static values, which won't change during this run.
$this->fr_error["pid"] = isset($this->variables->resultArray['global.']['page_id']) ? $this->variables->resultArray['global.']['page_id'] : 0;
......@@ -123,8 +124,7 @@ class Report {
// Sanitize function for POST and GET Parameters.
// Merged URL-Parameter (key1, id etc...) in resultArray.
$this->variables->resultArray = array_merge($this->variables->resultArray, array("url." => $this->utils->sanitize()),
array("global." => $this->variables->collectGlobalVariables()));
$this->variables->resultArray = array_merge($this->variables->resultArray, array("global." => $this->variables->collectGlobalVariables()));
// Create Logclass.
$this->log = new Log($this->variables->resultArray['global.']);
......@@ -878,27 +878,6 @@ class Report {
return ($columnValue);
}
/**
* Prepare Session Array with Hash Entry: Only for form
*
* @param $formName
* @param $formRecordId
* @return string
*/
private function form2hash($formName, $formRecordId) {
$hash = $this->utils->randomAlphaNumUnique();
$_SESSION[FORMREPORT][$hash]['formName'][0] = $formName;
$_SESSION[FORMREPORT][$hash]['referrer'] = $_SERVER['REQUEST_URI'];
if (is_numeric($formRecordId) && $formRecordId >= 0) {
$_SESSION[FORMREPORT][$hash]['idMap'][1]['recordId'] = $formRecordId;
$_SESSION[FORMREPORT][$hash]['idMap'][1]['param'] = "";
}
return ($hash);
}
/**
* Generate SortArgument
*
......
......@@ -29,174 +29,6 @@ class Utils {
$this->db = null;
}
/**
* Sanitize GET and POST Parameters. Categorize Parameter: name begins with:
* 'S_' String: sanitize via t3lib_db::quoteStr, htmltospecialchars
* 'H_' HTML: no sanitize at all
* [Typo3, xdebug, zend debugger] special - no change
* [rest] has to be numeric - if not, will not be copied.
*
* @return Array of sanitized GET and POST Variables. Only correctly filled variables will be returned.
*/
public function sanitize() {
$arr = array();
// Merge GET and POST arrays. GET will be preferred.
$params = array_merge($_POST, $_GET);
foreach ($params as $key => $value) {
// if $value is an array (e.g. when using checkboxes on a 'set' field), convert it to a csv list.
if (is_array($value)) {
$value = implode(",", $value);
}
switch (substr($key, 0, 2)) {
//alphanum
// String values. HTML entitites will be converted, strings escaped.
case "S_":
// $arr[$key] = mysql_real_escape_string(htmlspecialchars($value));
// TA: htmlspecialchars darf hier nicht angewendet werden - Daten sollen so in DB geschrieben werden wie sie angegeben werden
$arr[$key] = mysql_real_escape_string($value);
break;
//default (F_ kommt vom ursprünglichen namen form)
//Tags werden bis auf die Whitelist LIST_MARKUP_TAGS (siehe define) ersetzt
case "F_":
$arr[$key] = addslashes(strip_tags($value, LIST_MARKUP_TAGS));
break;
//email
//ExtJs definition (unterstützt nicht alle erlaubten Emailadressen)
case "E_":
$pattern = "/^((\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6})?$/";
if (preg_match($pattern, $value) > 0) {
$arr[$key] = $value;
}
break;
//url
//Protokoll http / https muss angegeben werden. Definition ExtJs
case "U_":
$pattern = "/((((^https?)|(^ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?))?$/i";
if (preg_match($pattern, $value) > 0) {
$arr[$key] = $value;
}
break;
//html
// HTML allowed: no sanitize at all.
case "H_":
$arr[$key] = addslashes($value);
break;
//date
//DD.MM.YYYY or DD/MM/YYYY
case "D_":
// $pattern = "/^\d\d[(.|\/)]\d\d[(.|\/)]\d\d\d\d$/";
// if(preg_match($pattern, $value)>0){
// $arr[$key] = $value;
// }
// use strtotime instead of a complex regex:
// - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful
// - the date is automatically converted to a defined format, which makes it easier to process in later steps
if (strtotime($value)) {
$arr[$key] = date("Y-m-d", strtotime($value));
}
break;
//time
//hh:mm:ss
case "T_":
//$pattern = "/^(((0|1)\d|2[0-4])[:]([0-6]\d)[:]([0-6]\d))?$/"; // CR: restriction to 00-23 is to strong
// $pattern = "/^\d?\d[:]\d?\d[:]?\d?\d?$/";
// if(preg_match($pattern, $value)>0){
// $arr[$key] = $value;
// }
// use strtotime instead of a complex regex:
// - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful
// - the date is automatically converted to a defined format, which makes it easier to process in later steps
if (strtotime($value)) {
$arr[$key] = date("h:i:s", strtotime($value));
}
break;
//date_time
//DD.MM.YYYY hh:mm:ss
case "Z_":
//$pattern = "/^((0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)\d\d[ ]((0|1)\d|2[0-4])[:]([0-6]\d)[:]([0-6]\d))?$/";
// $pattern = "/^(\d*\d[.]\d*\d[.]\d*\d*\d*\d[ ]\d?\d[:]\d?\d[:]?\d?\d?$/";
// if(preg_match($pattern, $value)>0){
// $arr[$key] = $value;
// }
// use strtotime instead of a complex regex:
// - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful
// - the date is automatically converted to a defined format, which makes it easier to process in later steps
if (strtotime($value)) {
$arr[$key] = date("Y-m-d h:i:s", strtotime($value));
}
break;
case "N_":
//num
//Only numeric-value allowed
$pattern = "/^-?[0-9]*$/";
if (preg_match($pattern, $value) > 0) {
$arr[$key] = $value;
}
break;
default:
/* 'id' (T3 page identifier) and ZEND 'debugger' GET_VARS won't be sanitized*/
;
switch ($key) {
case 'id':
case 'start_debug':
case 'debug_host':
case 'send_sess_end':
case 'debug_session_id':
case 'original_url':
case 'debug_start_session':
case 'debug_no_cache':
case 'debug_port':
$arr[$key] = $value;
continue 2;
}
break;
}
}
return ($arr);
} // sanitize()
/**
* Create a new _unique_ (max 20 tries, else breaks) hash string and saves it in $_SESSION[FORMREPORT][$hash]
*
* @return string A random alphanumeric hash, or
* false if it was not possible to create a unique hash.
*/
public function randomAlphaNumUnique() {
for ($i = 0; $i < 20; $i++) {
$hash = $this->randomAlphaNum(LENGTH_HASH);
if (!isset($_SESSION[FORMREPORT][$hash])) {
$_SESSION[FORMREPORT][$hash] = array();
return ($hash);
}
}
// Too much tries without success
return (false);
} // randomAlphaNum ()
/**
* @param int $length Length of the required hash string
* @return string A random alphanumeric hash
*/
private function randomAlphaNum($length) {
$possible_characters = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$string = "";
while (strlen($string) < $length) {
$string .= substr($possible_characters, rand() % (strlen($possible_characters)), 1);
}
return ($string);
} // randomAlphaNumUnique()
/**
* If record locking has been enabled in ext_localconf.php, create a record in the lock table
*
......@@ -213,8 +45,7 @@ class Utils {
$query = "INSERT INTO `" . FR_LOCK . "` (`phpsession_id`, `fe_user_uid`, `form`, `record_id`, `tablename`, `dbalias`) VALUES ('" . session_id() . "', '" . $GLOBALS["TSFE"]->fe_user->user["uid"] . "', '" . $form . "', '" . $record_id . "', '" . $tablename . "', '" . $dbalias . "')";
$this->db->doQuery(DB, $query, $result, ROW_EXPECT_0);
} // if
} // eo setLockRecord
} // randomAlphaNumUnique()
/**
* If record locking has been enabled in ext_localconf.php,
......@@ -275,7 +106,7 @@ class Utils {
$this->db->doQuery(T3, $query, $result, ROW_EXPECT_1);
$username = ($result['username']) ?: "anonymous";
return $username;
}
} // eo setLockRecord
/**
* Create a unique directory in $path
......@@ -297,6 +128,20 @@ class Utils {
}
// Too many tries without success
throw new CodeReportException ("Could not create unique directory.", __FILE__, __LINE__);
}
/**
* @param int $length Length of the required hash string
* @return string A random alphanumeric hash
*/
private function randomAlphaNum($length) {
$possible_characters = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$string = "";
while (strlen($string) < $length) {
$string .= substr($possible_characters, rand() % (strlen($possible_characters)), 1);
}
return ($string);
} // eo createUniqueDir
/**
......
......@@ -24,6 +24,8 @@
namespace qfq;
require_once(__DIR__ . '/../Evaluate.php');
//use qfq;
class Variables {
......@@ -32,11 +34,17 @@ class Variables {
// TODO to explain
private $tt_content_uid = 0;
/**
* @var Evaluate
*/
private $eval;
/**
* @param int $tmp_ttcontent_uid
*/
public function __construct($tt_content_uid = 0) {
public function __construct(Evaluate $eval, $tt_content_uid = 0) {
$this->eval = $eval;
// specified once during initialisation.
$this->tt_content_uid = $tt_content_uid;
......@@ -51,7 +59,7 @@ class Variables {
*/
public function doVariables($text) {
// $str = preg_replace_callback("/(~([a-zA-Z0-9._])*)/", array($this, 'replaceVariables'), $text);
$str = preg_replace_callback("/{{(([a-zA-Z0-9._])*)}}/", array($this, 'replaceVariables'), $text);
$str = preg_replace_callback("/{{(([a-zA-Z0-9.:_])*)}}/", array($this, 'replaceVariables'), $text);
return $str;
}
......@@ -72,12 +80,21 @@ class Variables {
// index of last '.'
$pos = strrpos($matches[1], ".");
if ($pos !== false) {
$fullLevel = substr($matches[1], 0, $pos + 1);
$varName = substr($matches[1], $pos + 1, strlen($matches[1]));
$fullLevel = substr($matches[1], 0, $pos + 1);
$varName = substr($matches[1], $pos + 1, strlen($matches[1]));
if (isset($this->resultArray[$fullLevel][$varName])) {
$data = $this->resultArray[$fullLevel][$varName];
}
}
if (isset($this->resultArray[$fullLevel][$varName]))
$data = $this->resultArray[$fullLevel][$varName];
// If not replaced, try the Stores
if ($data === $matches[0]) {
$dataTmp = $this->eval->parse($data);
if ($dataTmp !== false)
$data = $dataTmp;
}
return $data;
}
......
......@@ -129,4 +129,27 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
$this->assertEquals('2016-12-31 23:48:59', Support::dateTime2mysql('31.12.2016 23:48:59'));
}
public function testEncryptDoubleCurlyBraces() {
$arr = [
['', ''],
['1', '1'],
["1\n2", "1\n2"],
['{', '{'],
['#&@[[@_#', '{{'],
['-\{-', '-\{-'],
['#&@[[@_##&@]]@_#-#&@[[@_##&@]]@_#', '{{}}-{{}}'],
['#&@[[@_#hello#&@[[@_#world#&@]]@_##&@]]@_#', '{{hello{{world}}}}'],
["\n\n##&@[[@_#\n#&@]]@_#", "\n\n#{{\n}}"],
];
foreach ($arr as $tuple) {
$this->assertEquals($tuple[0], Support::encryptDoubleCurlyBraces($tuple[1]));
$this->assertEquals($tuple[1], Support::decryptDoubleCurlyBraces($tuple[0]));
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment