Dear list,

I recently ran into big problems with crc32() and ip2long() both of which I
was using in the same codebase.

I know these issues have been debated at length in the past, but this
really needs to be fixed.

Anytime you persist these values (to any external medium, files or
databases) you're sitting on a time bomb.

I realize some of you have countless technical arguments why these
functions "work as they're supposed to", but php is a high-level language,
and these functions do not work consistently across platforms.

It can't be the developer's responsibility to write unit-tests for
return-values on internal functions - nor should we need to write elaborate
wrapper-functions for these functions to get them to work consistently.

There are dozens (if not nearing 100) different user-land solutions to this
problem, so it's not like the need isn't there - anyone who has ever used
these functions probably needed a work-around. The need for an enormous red
WARNING label, and elaborate explanation on the crc32() documentation page
says it all - nothing this simple, that has been standardized for this
long, should require an elaborate explanation, complicated work-arounds or
for that matter a lot of thought on the developer's side.

Since a signed 32-bit integer value is the lowest common denominator,
that's what the functions ought to return, so that at least the return
value is consistent across platforms, and you can decide (for example)
whether to persist it to a signed or unsigned INT in a database, and except
it to work the same everywhere. (Databases at large, and at least MySQL,
correctly persists either signer or unsigned INT values across platforms.)

The simplest work-around I have been able to come up with so far, is this:

    var_dump(unpack('l', pack('l', ip2long('255.255.255.0'))));

    var_dump(unpack('l', pack('l', crc32('123456789_00_0'))));

Forcing the value into smaller (on some platforms) 32-bit integer, and then
unpacking it, provides a consistent value on 32-bit and 64-bit systems, and
on Windows.

Of course there is backwards compatibility to consider for this broken
behavior, so I propose the simplest solutions is to just add a new pair of
replacement functions. You don't need to deprecate the existing functions,
because they work as prescribed, however useless they may be for any
practical applications.

The new functions and backwards compatible implementations for older
versions of php might look like this:

/**
 * @param string
 * @return int a signed (32-bit) integer value
 */
function ip2int($ip_string) {
    return unpack('l', pack('l', ip2long($ip_string)));
}

/**
 * @param int a signed integer value
 * @return string
 */
function int2ip($ip_int) {
    return long2ip($ip_int);
}

/**
 * @param string
 * @return int a signed integer value
 */
function crc32i($string) {
    return unpack('l', pack('l', crc32($string)));
}

int2ip() would just be an alias for long2ip().

I spent almost a full day fighting with these functions and testing
work-arounds, and I bet every php developer who encounters a need for one
of these functions will some day sooner or later go through the same.

Userland solutions are not solutions to fundamental problems that affect
everyone who uses the functions.

Arguing that this behavior is "correct" by some technical definition, is
futile - the behavior is problematic for practical reasons, so technical
circumstances don't really matter here. Core functions need to actually
work consistently and predictably for as many users as possible -
optimizing for C developers and people with deep technical knowledge of
operating system and compiler specifics does not make sense for a language
like php.

Please look for reasons to agree rather than disagree out of spite.

As said, I know this has been debated at length in the past, and always
with the same outcome - but the simple fact is that these functions don't
work for the end-users, and they do not provide proper cross-platform
support.

No one cares how integers work internally, in C, in the CPU, or in the VM,
and it's not relevant.

There is no need to put anyone through all this unnecessary hardship.

These functions need to work **for php developers**.

- Rasmus Schultz

Reply via email to