以0.1为步长验证HTML5数字输入

Trying to do server side validation (PHP), where there is the HTM5 number input:

<input ... min="1" max="20" step="0.1" />

The browser will allow you to enter a value such as "10.5", but how should this be double checked in PHP? for those browsers which won't do the validation (and the fact you shouldn't trust data from the browser).

if (fmod(floatval($value), 0.1) == 0) {
    // valid
}

This does not work, as fmod() in this case returns "0.099999...", as per:

Why different results of 0.5 mod 0.1 in different programming languages?

You could multiply the $value by 10, and use the modulus check of 1 (rather than 0.1), so your doing integer maths... but what happens if the step was 0.01, or 0.003?

If the number will be stored as a float underneath the hood, it will always get rounded to the nearest representable number.

You can either accept the value as float, and simply do the check like this:

// get the nearest multiple of $step that is representable in float
$normalized = round($number, $allowed_digits); // for steps like '0.1', '0.01' only
$normalized = round($number / $step) * $step;  // works for any arbitrary step, like 0.2 or 0.3

// verify if they are not too different, where EPSILON is a very small constant
// we cannot directly == as the calculations can introduce minuscule errors
if (abs($normalized - $number) > EPSILON)
   die("Did not validate.");

Or, you can simply treat the value from the client-side as a string, and verify the number of digits used in the string (and convert to float later). You should do this if you want to be 100% sure that the user entered something like 0.01, not 0.099999999999 (which would get rounded to the same thing as 0.01).