Hi,

On 30 Aug, 2013, at 11:29 PM, Rasmus Schultz <ras...@mindplay.dk> wrote:

> No replies probably means no one cares. oh well.
> 
> For the record, the examples I posted are wrong - the correct way to
> convert the long values consistently appears to be:
> 
> list($v) = array_values(unpack('l', pack('l', ip2long('255.255.255.0'))));

I recognise this from a comment on one of my SO answers here: 
http://stackoverflow.com/questions/13419921/how-should-a-crc32-be-stored-in-mysql/13420281#13420281

Instead of using list() and array_values() you can use current() on the return 
value to get the first array element from unpack()'s result. 

echo current(unpack('l', pack('l', crc32(...))));
Admittedly only makes it marginally nicer to look at :)

> 
> I missed the fact that array_values() returns an array, and for some reason
> the return-value from unpack() is base-1 with apparently no way to change
> the key to a 0.
> 
> As an aside, the information I posted on the manual pages in the comments
> is wrong, and the site currently offers no way to edit or remove a
> comment... dangit...
> 
> 
> 
> On Tue, Aug 27, 2013 at 12:05 PM, Rasmus Schultz <ras...@mindplay.dk> wrote:
> 
>> 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