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 >> >>