ZF-11279: Zend_Currency creates invalid cache ids for values with fractions

Description

I'm not skilled enough to provide a php_unit testcase reproducer, but here is the behavior I'm seeing. The application has a Zend_Locale object set with the en_US locale stored in the Zend_Locale registry key. I run the following code:

    $cur = new Zend_Currency(array('value' => 1234), 'aa_DJ');
    echo "$cur\n";

I get reasonable output (I can't swear it's correct since I don't know the currency):

    Fdj1,234.00

But if give the value a fractional part, say:

    $cur = new Zend_Currency(array('value' => 1234.56), 'aa_DJ');
    echo "$cur\n";

I get (using ZF 1.11.1 sources, but the 1.11.5 sources are identical in this regard):

Zend_Cache_Exception: Invalid id or tag 'Zend_LocaleC_aa_DJ_nametocurrency_1234.56' : must use only [a-zA-Z0-9_] in C:\xampp\htdocs\OSH0\library\Zend\Cache.php on line 209

A more complete traceback is:

Locale/Data.php.Zend_Locale_Data::getContent : lineno 948() Locale/Data.php at line 948 
Currency.php.Zend_Currency->getName : lineno 405() Currency.php at line 405 
Currency.php.Zend_Currency->__construct : lineno 95() Currency.php at line 95   

In XDebug, I can see that this happens because __construct() calls getName() directly at line 110 with a first parameter $options that is array('value' => 1234.56), and within getName() the first parameter is called $currency, which gets passed to self::_checkParams($currency, $locale), which returns $params as follows:

  array(
    'locale' => 'aa_DJ',
    'currency' => array(
      1234.56
    )
    'name' => array(
      1234.56
    )
    'country' => 'DJ'
  )

So when getName() at line 405 makes the call

$name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency'])

The value of $params['currency'] is array(1234.56).

getContent() constructs a cache id by imploding an array value passed in with '_', urlencoding that into a variable named $val, and finally producing the cache id as:

$id = strtr('Zend_LocaleC_' . $locale . '_' . $path . '_' . $val, array('-' => '_', '%' => '_', '+' => '_'));

The implode() and urlencode() on the passed-in value don't change anything, so $val is just "1234.56", and the strtr() doesn't do anything to the '.', which results in the invalid cache id.

But I don't know whether the strtr should be replacing more characters, or whether the problem is that the "1234.56" should not have gotten into $params['currency']. It seems suspicious that $params['names'] got that same value, array(1234.56), but it is the $params['currency'] value that directly causes the problem. If that value is correct, and it's the strtr call that should be changed to replace '.' characters, then would it also need to replace ',' characters to handle default locales where ',' is the radix point?

Comments

Please fix this :(