zendframework / zf1

This project reached its end-of-life on 2016-09-28. Contains conversion of ZF1 subversion repo to git, from version 15234 forward, and only containing master and release-1.12 branches and 1.12 tags.
https://framework.zend.com/blog/2016-06-28-zf1-eol.html
BSD 3-Clause "New" or "Revised" License
357 stars 800 forks source link

Notice in Zend_Currency in version 1.12.7 #384

Open SobolevLexa opened 10 years ago

SobolevLexa commented 10 years ago

Notice: iconv_strpos(): Detected an illegal character in input string in vendor/zendframework/zendframework1/library/Zend/Currency.php on line 199

dotZoki commented 10 years ago

I'm also experiencing this issue.

froschdesign commented 10 years ago

Please give an example to reproduce the problem.

gerardroche commented 10 years ago

@froschdesign this is possibly related to what I describe here https://github.com/zendframework/zf1/pull/347#issuecomment-47002031

froschdesign commented 10 years ago

@gerardroche Please test this:

public function toCurrency($value = null, array $options = array())
{
    // …

    if ($options['position'] !== self::STANDARD) {
        $value = str_replace('¤', '', $value);
        $space = '';

        $oenc = self::_getEncoding();
        self::_setEncoding('UTF-8');

        if (iconv_strpos($value, ' ') !== false) {
            $value = str_replace(' ', '', $value);
            $space = ' ';
        }

        self::_setEncoding($oenc);

        if ($options['position'] == self::LEFT) {
            $value = '¤' . $space . $value;
        } else {
            $value = $value . $space . '¤';
        }
    }

    // …
}

/**
 * Internal method to retrieve the current encoding via the ini setting
 * default_charset for PHP >= 5.6 or iconv_get_encoding otherwise.
 *
 * @return string
 */
protected static function _getEncoding()
{
    $oenc = PHP_VERSION_ID < 50600
        ? iconv_get_encoding('internal_encoding')
        : ini_get('default_charset');

    return $oenc;
}

/**
 * Internal method to set the encoding via the ini setting
 * default_charset for PHP >= 5.6 or iconv_set_encoding otherwise.
 *
 * @param string $encoding
 * @return void
 */
protected static function _setEncoding($encoding)
{
    if (PHP_VERSION_ID < 50600) {
        iconv_set_encoding('internal_encoding', $encoding);
    } else {
        ini_set('default_charset', $encoding);
    }
}
gerardroche commented 10 years ago

I think there's an edge-case issue the way the encoding is being set, because the iconv and mbstring encoding settings take precedence over default_charset.

For example:

function _setEncoding($encoding) {
    if (PHP_VERSION_ID < 50600) {
        iconv_set_encoding('internal_encoding', $encoding);
    } else {
        ini_set('default_charset', $encoding);
    }
}

function dump_encoding_info() {
    echo "Encoding Info: ";
    print_r(array(
        'default_charset' => ini_get('default_charset'),
        'iconv.internal_encoding ' => ini_get('iconv.internal_encoding')
    ));
}

var_dump(PHP_VERSION_ID);

@ini_set('iconv.internal_encoding', 'UTF-8');
@ini_set('default_charset', 'UTF-8');
dump_encoding_info();
var_dump(iconv_strlen('¤'));

_setEncoding('UTF-8');
dump_encoding_info();
var_dump(iconv_strlen('¤'));

@ini_set('iconv.internal_encoding', 'ISO-8859-1');
@ini_set('default_charset', 'ISO-8859-1');
dump_encoding_info();
var_dump(iconv_strlen('¤'));

_setEncoding('UTF-8');
dump_encoding_info();
var_dump(iconv_strlen('¤'));

Prints

int(50600)
Encoding Info: Array
(
    [default_charset] => UTF-8
    [iconv.internal_encoding ] => UTF-8
)
int(1)
Encoding Info: Array
(
    [default_charset] => UTF-8
    [iconv.internal_encoding ] => UTF-8
)
int(1)
Encoding Info: Array
(
    [default_charset] => ISO-8859-1
    [iconv.internal_encoding ] => ISO-8859-1
)
int(2)
Encoding Info: Array
(
    [default_charset] => UTF-8
    [iconv.internal_encoding ] => ISO-8859-1
)
int(2)

Notice the last one where iconv_strlen() is still using ISO-8859-1 because it takes precendence over the default_charset settings.

Without error suppression, setting iconv.internal_encoding via ini_set triggers a deprecated error:

Deprecated: ini_set(): Use of iconv.internal_encoding is deprecated in path/to/file.php on line #

So a fix like this will cause deprecated errors and using error suppression might be an issue too.

function _setEncoding($encoding) {
    if (PHP_VERSION_ID < 50600) {
        iconv_set_encoding('internal_encoding', $encoding);
    } else {
        ini_set('default_charset', $encoding);
        iconv_set_encoding('internal_encoding', $encoding);
    }
}
barbazul commented 8 years ago

I am having this same issue.

I tracked down to Locale/Format.php::_getEncoding() which is missing the return statement.

So when Zend_Currency calls Zend_Locale_Format::toNumber, this method gets the "current" encoding, then forces UTF-8 (I assume this is in order to parse ¤ for symbol position) and later "reverts" the original encoding. Only it really attempts to set a null encoding.

Adding return $oenc fixes the issue

soulmktpro commented 8 years ago

Barbazul, em qual arquivo você fez essa alteração??

barbazul commented 8 years ago

@soulmktpro please use english as my portuguese is really bad.

The file is mentioned in my previous comment: Locale/Format.php

barbazul commented 8 years ago

This was fixed in 820aab2 but some versions of Magento contain the unpatched file, thats how i recently run into this issue.