Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Hotfix for #5772: token processor should not cast booleans to strings #5773

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 66 additions & 33 deletions library/Zend/Config/Processor/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,30 @@ public function setToken($token, $value)

/**
* Build replacement map
*
* @return array
*/
protected function buildMap()
{
if (!$this->suffix && !$this->prefix) {
$this->map = $this->tokens;
} else {
$this->map = array();
foreach ($this->tokens as $token => $value) {
$this->map[$this->prefix . $token . $this->suffix] = $value;
if (null === $this->map) {
if (!$this->suffix && !$this->prefix) {
$this->map = $this->tokens;
} else {
$this->map = array();

foreach ($this->tokens as $token => $value) {
$this->map[$this->prefix . $token . $this->suffix] = $value;
}
}

foreach (array_keys($this->map) as $key) {
if (empty($key)) {
unset($this->map[$key]);
}
}
}

return $this->map;
}

/**
Expand All @@ -198,28 +211,7 @@ protected function buildMap()
*/
public function process(Config $config)
{
if ($config->isReadOnly()) {
throw new Exception\InvalidArgumentException('Cannot process config because it is read-only');
}

if ($this->map === null) {
$this->buildMap();
}

/**
* Walk through config and replace values
*/
$keys = array_keys($this->map);
$values = array_values($this->map);
foreach ($config as $key => $val) {
if ($val instanceof Config) {
$this->process($val);
} else {
$config->$key = str_replace($keys, $values, $val);
}
}

return $config;
return $this->doProcess($config, $this->buildMap());
}

/**
Expand All @@ -230,12 +222,53 @@ public function process(Config $config)
*/
public function processValue($value)
{
if ($this->map === null) {
$this->buildMap();
return $this->doProcess($value, $this->buildMap());
}

/**
* Applies replacement map to the given value by modifying the value itself
*
* @param mixed $value
* @param array $replacements
*
* @return mixed
*
* @throws Exception\InvalidArgumentException if the provided value is a read-only {@see Config}
*/
private function doProcess($value, array $replacements)
{
if ($value instanceof Config) {
if ($value->isReadOnly()) {
throw new Exception\InvalidArgumentException('Cannot process config because it is read-only');
}

foreach ($value as $key => $val) {
$value->$key = $this->doProcess($val, $replacements);
}

return $value;
}

if ($value instanceof Traversable || is_array($value)) {
foreach ($value as & $val) {
$val = $this->doProcess($val, $replacements);
}

return $value;
}

if (!is_string($value) && (is_bool($value) || is_numeric($value))) {
$stringVal = (string) $value;
$changedVal = strtr($value, $this->map);

// replace the value only if a string replacement occurred
if ($changedVal !== $stringVal) {
return $changedVal;
}

return $value;
}
$keys = array_keys($this->map);
$values = array_values($this->map);

return str_replace($keys, $values, $value);
return strtr((string) $value, $this->map);
}
}
69 changes: 69 additions & 0 deletions tests/ZendTest/Config/ProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,75 @@ public function testTokenChangeParams()
$this->assertEquals('@@ some text with some replaced value inside @@', $config->nested->inside);
}

/**
* @group ZF2-5772
*/
public function testTokenChangeParamsRetainsType()
{
$config = new Config(
array(
'trueBoolKey' => true,
'falseBoolKey' => false,
'intKey' => 123,
'floatKey' => (float) 123.456,
'doubleKey' => (double) 456.789,
),
true
);

$processor = new TokenProcessor();

$processor->process($config);

$this->assertSame(true, $config['trueBoolKey']);
$this->assertSame(false, $config['falseBoolKey']);
$this->assertSame(123, $config['intKey']);
$this->assertSame((float) 123.456, $config['floatKey']);
$this->assertSame((double) 456.789, $config['doubleKey']);
}

/**
* @group ZF2-5772
*/
public function testTokenChangeParamsReplacesInNumerics()
{
$config = new Config(
array(
'foo' => 'bar1',
'trueBoolKey' => true,
'falseBoolKey' => false,
'intKey' => 123,
'floatKey' => (float) 123.456,
'doubleKey' => (double) 456.789,
),
true
);

$processor = new TokenProcessor(array('1' => 'R', '9' => 'R'));

$processor->process($config);

$this->assertSame('R', $config['trueBoolKey']);
$this->assertSame('barR', $config['foo']);
$this->assertSame(false, $config['falseBoolKey']);
$this->assertSame('R23', $config['intKey']);
$this->assertSame('R23.456', $config['floatKey']);
$this->assertSame('456.78R', $config['doubleKey']);
}

/**
* @group ZF2-5772
*/
public function testIgnoresEmptyStringReplacement()
{
$config = new Config(array('foo' => 'bar'), true);;
$processor = new TokenProcessor(array('' => 'invalid'));

$processor->process($config);

$this->assertSame('bar', $config['foo']);
}

/**
* @depends testTokenSurround
*/
Expand Down