ZF-8946: Invalid Zend_Validate_Float string validations

Description

Zend_Validate_Float is returning some invalid validations. For example, strings "74.8960196583719" and "169.76664148522" are evaluated as invalid. See example below (first tests are for baseline and were taken from ZF-5879):

Tests:

<?php
require_once 'Zend/Validate.php';

$floats = array(// floats
                0.000000234,
                1.0000000234,
                0.000050004,
                0.005000004,
                // strings
                '0.000000234',
                '1.0000000234',
                '0.000050004',
                '0.005000004');

foreach ($floats as $f) {
    echo "$f: ";
    var_dump(Zend_Validate::is($f,'Float'));
}

echo "----------------------------------------------------------\n";

$floats = array(// floats
                74.8960196583719,
                169.76664148522,
                // strings
                '74.8960196583719',
                '169.76664148522');

foreach ($floats as $f) {
    echo "$f: ";
    var_dump(Zend_Validate::is($f,'Float'));
}

Result/output:

2.34E-7: bool(true)
1.0000000234: bool(true)
5.0004E-5: bool(true)
0.005000004: bool(true)
0.000000234: bool(true)
1.0000000234: bool(true)
0.000050004: bool(true)
0.005000004: bool(true)
----------------------------------------------------------
74.8960196584: bool(true)
169.766641485: bool(true)
74.8960196583719: bool(false)
169.76664148522: bool(false)

Comments

Please test with release 1.10. 1.9.7 is outdated and several bug fixes have been integrated.

Additionally we need some informations from your system for reproduction. * Systems locale * OS * PHP version * PHP's settings for number calculation

Downloaded and tested with release 1.10.0rc1. Created new test script with additional environment output. Also logic change because "Zend_Validate::is($f,'Float')" threw the exception "Validate class not found from basename 'float'".

OS is RHEL 4.

String "169.7666414852" validates correctly with release 1.10.0rc1, but string "74.8960196583719" still does not.

Test:

<?php
require_once 'Zend/Version.php';

echo "Zend Framework version = " . Zend_Version::VERSION . "\n";
echo "PHP version = " . phpversion() . "\n";
echo "\$_ENV['OSTYPE'] = " . $_ENV['OSTYPE'] . "\n";
echo "\$_ENV['VENDOR'] = " . $_ENV['VENDOR'] . "\n";
echo "\$_ENV['MACHTYPE'] = " . $_ENV['MACHTYPE'] . "\n";
echo "\$_ENV['LANG'] = " . $_ENV['LANG'] . "\n";
echo "\$_ENV['SUPPORTED'] = " . $_ENV['SUPPORTED'] . "\n";

echo "----------------------------------------------------------\n" .
     "localeconv() =\n";

var_dump( localeconv() );

echo "----------------------------------------------------------\n";

require_once 'Zend/Validate/Float.php';

$floatValidator = new Zend_Validate_Float();

$floats = array(// floats
                0.000000234,
                1.0000000234,
                0.000050004,
                0.005000004,
                // strings
                '0.000000234',
                '1.0000000234',
                '0.000050004',
                '0.005000004');

foreach ($floats as $f) {
    echo "$f: ";
    var_dump( $floatValidator->isValid( $f ) );
}

echo "----------------------------------------------------------\n";

$floats = array(// floats
                74.8960196583719,
                169.76664148522,
                // strings
                '74.8960196583719',
                '169.76664148522');

foreach ($floats as $f) {
    echo "$f: ";
    var_dump( $floatValidator->isValid( $f ) );
}

Result/output:

Zend Framework version = 1.10.0rc1
PHP version = 5.2.10
$_ENV['OSTYPE'] = linux
$_ENV['VENDOR'] = intel
$_ENV['MACHTYPE'] = i386
$_ENV['LANG'] = en_US.UTF-8
$_ENV['SUPPORTED'] = en_US.UTF-8:en_US:en
----------------------------------------------------------
localeconv() =
array(18) {
  ["decimal_point"]=>
  string(1) "."
  ["thousands_sep"]=>
  string(0) ""
  ["int_curr_symbol"]=>
  string(0) ""
  ["currency_symbol"]=>
  string(0) ""
  ["mon_decimal_point"]=>
  string(0) ""
  ["mon_thousands_sep"]=>
  string(0) ""
  ["positive_sign"]=>
  string(0) ""
  ["negative_sign"]=>
  string(0) ""
  ["int_frac_digits"]=>
  int(127)
  ["frac_digits"]=>
  int(127)
  ["p_cs_precedes"]=>
  int(127)
  ["p_sep_by_space"]=>
  int(127)
  ["n_cs_precedes"]=>
  int(127)
  ["n_sep_by_space"]=>
  int(127)
  ["p_sign_posn"]=>
  int(127)
  ["n_sign_posn"]=>
  int(127)
  ["grouping"]=>
  array(0) {
  }
  ["mon_grouping"]=>
  array(0) {
  }
}
----------------------------------------------------------
2.34E-7: bool(true)
1.0000000234: bool(true)
5.0004E-5: bool(true)
0.005000004: bool(true)
0.000000234: bool(true)
1.0000000234: bool(true)
0.000050004: bool(true)
0.005000004: bool(true)
----------------------------------------------------------
74.896019658372: bool(true)
169.76664148522: bool(true)
74.8960196583719: bool(false)
169.76664148522: bool(true)

Main reason is that long floats are automatically converted by PHP but it takes into account the precision setting in your PHP ini configuration.

This means that long precision values are stripped and therefor are no longer identical with the original value...

For example: 10.1234567890123456789 will automatically be rounded to 10.1234567890123 (when you use the default setting of a precision to 13 digits within PHP.ini)

As both values are NOT identical a false is returned.

Seems to be fixed in the latest version.

Marked as resolved according to latest reply. Not reproduceable with latest release.