Bug #29461 » typo3-29461-escape_typoscript_key.diff
typo3/sysext/core/Classes/TypoScript/Parser/TypoScriptParser.php | ||
---|---|---|
*/
|
||
class TypoScriptParser {
|
||
/**
|
||
* The character that can be used to escape dots in TypoScript keys
|
||
*/
|
||
const TYPOSCRIPT_KEY_ESCAPE_CHARACTER = '\\';
|
||
// If set, then key names cannot contain characters other than [:alnum:]_\.-
|
||
/**
|
||
* @todo Define visibility
|
||
... | ... | |
*/
|
||
public function getVal($string, $setup) {
|
||
if ((string) $string != '') {
|
||
$keyLen = strcspn($string, '.');
|
||
$keyLen = $this->getKeyLengthAndStripEscapeChars($string, '.');
|
||
if ($keyLen == strlen($string)) {
|
||
// Added 6/6/03. Shouldn't hurt
|
||
$retArr = array();
|
||
... | ... | |
*/
|
||
public function setVal($string, &$setup, $value, $wipeOut = 0) {
|
||
if ((string) $string != '') {
|
||
$keyLen = strcspn($string, '.');
|
||
$keyLen = $this->getKeyLengthAndStripEscapeChars($string);
|
||
if ($keyLen == strlen($string)) {
|
||
if ($value == 'UNSET') {
|
||
unset($setup[$string]);
|
||
... | ... | |
}
|
||
/**
|
||
* Determines the string lenght of a TypoScript key and either
|
||
* stopps at the end or at the first dot that was found.
|
||
*
|
||
* Additionally any escape characters in the key are stripped.
|
||
*
|
||
* @param string $key the key, possibly consisting of multiple keys seperated by dots
|
||
* @param int $offset Internal use only! If an escaped dot was found the offset will be used to search for the next dot after the escaped one
|
||
* @param int $escapeCharCount Internal use only! Counts the number of escaped dots to correctly determine the key length after the escape chars have been stripped
|
||
* @return int The position of the first dot or the last character of the string
|
||
*/
|
||
public function getKeyLengthAndStripEscapeChars(&$key, $offset = 0, $escapeCharCount = 0) {
|
||
$testKey = $key;
|
||
if ($offset > 0) {
|
||
$testKey = substr($key, $offset);
|
||
}
|
||
$possibleMatchPosition = strcspn($testKey, '.') + $offset;
|
||
if ($key[$possibleMatchPosition - 1] === static::TYPOSCRIPT_KEY_ESCAPE_CHARACTER) {
|
||
return $this->getKeyLengthAndStripEscapeChars($key, $possibleMatchPosition + 1, $escapeCharCount + 1);
|
||
} else {
|
||
$key = str_replace(static::TYPOSCRIPT_KEY_ESCAPE_CHARACTER . '.', '.', $key);
|
||
return $possibleMatchPosition - $escapeCharCount;
|
||
}
|
||
}
|
||
/**
|
||
* Stacks errors/messages from the TypoScript parser into an internal array, $this->error
|
||
* If "TT" is a global object (as it is in the frontend when backend users are logged in) the message will be registered here as well.
|
||
*
|
typo3/sysext/core/Tests/Unit/TypoScript/Parser/TypoScriptParserTest.php | ||
---|---|---|
),
|
||
),
|
||
),
|
||
'nested assignment with escaped key' => array(
|
||
'lib\.key = value',
|
||
array(
|
||
'lib.key' => 'value',
|
||
),
|
||
),
|
||
'nested structured assignment' => array(
|
||
'lib {' . LF .
|
||
'key = value' . LF .
|
||
... | ... | |
),
|
||
),
|
||
),
|
||
'nested structured assignment with escaped key' => array(
|
||
'lib {' . LF .
|
||
'key\\.nextkey = value' . LF .
|
||
'}',
|
||
array(
|
||
'lib.' => array(
|
||
'key.nextkey' => 'value',
|
||
),
|
||
),
|
||
),
|
||
'multiline assignment' => array(
|
||
'key (' . LF .
|
||
'first' . LF .
|
||
... | ... | |
'key' => 'first' . LF . 'second',
|
||
),
|
||
),
|
||
'multiline assignment with escaped key' => array(
|
||
'key\\.nextkey (' . LF .
|
||
'first' . LF .
|
||
'second' . LF .
|
||
')',
|
||
array(
|
||
'key.nextkey' => 'first' . LF . 'second',
|
||
),
|
||
),
|
||
'copying values' => array(
|
||
'lib.default = value' . LF .
|
||
'lib.copy < lib.default',
|
||
... | ... | |
),
|
||
),
|
||
),
|
||
'copying values with escaped key' => array(
|
||
'lib\.default = value' . LF .
|
||
'lib.copy < lib\.default',
|
||
array(
|
||
'lib.default' => 'value',
|
||
'lib.' => array(
|
||
'copy' => 'value',
|
||
),
|
||
),
|
||
),
|
||
'one-line hash comment' => array(
|
||
'first = 1' . LF .
|
||
'# ignore = me' . LF .
|
||
... | ... | |
);
|
||
}
|
||
/**
|
||
* @test
|
||
* @dataProvider keyOffsetDetectionRespectsEscaptedTypoScriptKeysDataProvider
|
||
*/
|
||
public function keyOffsetDetectionRespectsEscaptedTypoScriptKeys($key, $expectedLength) {
|
||
$length = $this->typoScriptParser->getKeyLengthAndStripEscapeChars($key);
|
||
$this->assertEquals($expectedLength, $length);
|
||
}
|
||
/**
|
||
* @return array
|
||
*/
|
||
public function keyOffsetDetectionRespectsEscaptedTypoScriptKeysDataProvider() {
|
||
return array(
|
||
'key with normal seperator' => array(
|
||
'test.key',
|
||
4
|
||
),
|
||
'key without seperator' => array(
|
||
'testkey',
|
||
7
|
||
),
|
||
'key with escaped seperator' => array(
|
||
'test\\.key',
|
||
8
|
||
),
|
||
);
|
||
}
|
||
/**
|
||
* @test
|
||
* @dataProvider typoScriptKeyEscapeCharactersAreStrippedDataProvider
|
||
*/
|
||
public function typoScriptKeyEscapeCharactersAreStripped($key, $strippedKey) {
|
||
$this->typoScriptParser->getKeyLengthAndStripEscapeChars($key);
|
||
$this->assertEquals($strippedKey, $key);
|
||
}
|
||
/**
|
||
* @return array
|
||
*/
|
||
public function typoScriptKeyEscapeCharactersAreStrippedDataProvider() {
|
||
return array(
|
||
'key with normal seperator' => array(
|
||
'test.key',
|
||
'test.key',
|
||
),
|
||
'key without seperator' => array(
|
||
'testkey',
|
||
'testkey',
|
||
),
|
||
'key with escaped seperator' => array(
|
||
'test\\.key',
|
||
'test.key',
|
||
),
|
||
);
|
||
}
|
||
}
|
||
?>
|