PHP unserialized integer from 64-bit to 32-bit - php

I have been trying to unserialize on a 32-bit server an object that was serialized on a 64-bit server. I have isolated my problem to an integer in the object. Here is a small reproduction of the problem.
On a 64-bit machine:
$i = serialize('20110510134021'); //i:20110510134021;
On a 32-bit machine:
$i = unserialize('i:20110510134021;');
Gives the error
Notice: unserialize(): Error at offset 0 of 16 bytes
Now I understand that those serialization method shouldn't be used for cross system data transmition. However, we are merely trying to migrate the data to another system, not use it actively for transfers. This is a one time thing.
I would think that this might be due to integer overflow, but even on the 32-bit server I can do something like
$i = 20110510134021;
echo $i;
And it will work fine. I'm guessing PHP integer types scale to some double type or something like that. But why doesn't it do that when it unserializes?
How can I unserialize those objects? If I can't, is there any way to convert them to something else? Finally, has anyone written a deserialize method in PHP itself? Or has details on the protocol? I could use that and have a custom case for those integers.
Thanks.
Note: I do not have access to the original data, only the serialized result.

The max integer on 32 bit system is 4294967296;
$i = 20110510134021; works because PHP converts the variable to double.
So replace i with d
$i = unserialize('d:20110510134021;');
If you run this script, you will see the correct represenation of the variable on the system you are running (d: on 32 bit system, i: on 64 bit system):
$int = 20110510134021;
var_dump(serialize($int));

The simple solution is if you know that there is a chance that data serialized on 64 bit will be unserialized on 32 bit machine is to cast it to (double) before serializing.
Then it will be unserialized as a double, giving you more bits per integer than a standard 4-byte per integer (32 bits)
Once unserialized just work with that number as a double. In 99% of the cases this is a good solution. There is still a chance that for a very large number the number of bits allocated to the 'real' part on the number to a double on a 32 bit machine will not be enough. I think it's 56 bits, so the maximum integer is still significantly larger that the 32bits for the int type.

How about:
$serialized = 'i:20110510134021';
if (preg_match('/i\:([\d]+)/', $serialized, $match))
{
$unserialized = $match[1];
}

Related

PHP - strange behavior with unsigned integers (64bit) [duplicate]

I understand Integer size, PHP_INT_MAX is platform dependent.
On 64-bit system I can get a:
$large_number = 9223372036854775807
From what I read from PHP Document Example 3 here, when integer overflows, PHP handles integer as float with a precision of roughly 14 decimals digits, i.e:
Unsigned Int64: 18446744073709551615
PHP will handles as: 1.844674407371E+19
So it seems all precision only kept up to the max of Signed Int64.
Is this really just a limitation of PHP and there is nothing I can do about it?
This is pretty hacky, and I assure you your life will be easier using GMP but it is possible using pack() and a little binary thinking:
<?php
$large_number = 9223372036854775807;
$left = 0xffffffff00000000;
$right = 0x00000000ffffffff;
$l = ($large_number & $left) >>32; //shift 32 bits left
$r = $large_number & $right;
$int64_binary_string = pack('NN', $l, $r);
I haven't tested this, and wouldn't use it in real life, but it's probably close to what you're looking for.
http://tw1.php.net/manual/en/function.pack.php
if you need precision or numbers outside of PHP_INT_MAX / PHP_INT_MIN, learn to use GMP, which will probably keep going until you run out of memory... to give you some idea of how far you can take it,
$large_number = gmp_init("9223372036854775807");
$i=0;
while(true){
echo 'iteration '.$i++.':'.gmp_strval($large_number).'*1337=';
$large_number = gmp_mul($large_number,"1337");
echo gmp_strval($large_number).PHP_EOL;
}
will eventually
iteration 1291:63173727399431265977452467325176816266767500735669001788445953704
99100022309199341754638029233101065727095873054512847649411469159231474984853877
29990385564525384931210393372816147935077346316357322846070505282141866990047417
69795035320095201175780336777052639896516690649784147989039497959127394363606555
18277493016490689369408018504673663458745651065704848764945821685549595325229654
78521759046816461228651950877052534907426557036526546565508337234675673499891633
29265311281809541141691613057522094435618917713573494707844587004419303204290366
80410319411622496279245084808349790649184389864091281089934776245296259423173088
37125998364710920001673776690982404095905353172292803413540568804924330209161221
68502039031454119485450113377479892509776976500478875924900269471621353800015849
16768619446056453580306524878177680668058129358555807454509042635315136209751306
28888008462882394248192470687562440408441365704520299664521180552207604024174563
43137016510143518117853956283018500610190006192251441907450531358798897519852285
89712288688300401723956266383086427686519451058576140512867416675873224992592868
63873656820691379608416040082157797343590944870890093034489537997624441231196880
03716995482080107872348544579795198224539076738023147659657987086535844760748293
51680757422559231216506109885022428024013042708325323490543266063675126192858475
51062320509059668456301511665702512575733290996693385011230330439062943182094596
72982868367513131107811463983324141985257032192551001490775273440704964956322520
07994322409745388858643755238449137799970426027598547825636867768578263720009398
06345603047100479826296034929890108340101488966701293667796312958087571285537092
98292308718879824518810679195685709967212889579496467906343837737351387116485926
96065604380646092415099392666166947273008556519323980631398826013377061548412499
37045775535278706790702274483174254245054418225127782273776637425449169726435461
00864900455001093729251741310689643202116980745998974559375404087598011323913589
37378336888032750432647317316783507777959680594838416103235878202519306235270714
07689264877781232001726371838121263807804664374737613209359850417045192588050394
70657700599839677955302104699239419723871651195923433991338871172082351085772713
85795544605616579911291449220540413076513145849439424174121530477862582225947332
71577283620910275735801384726436002832118799836996365693738642178527175171378406
17487708039971384270639342138853231882316669599224158264716457232654635304792216
85595639961619807370286817974879544351592128186367207420223323272766972084744559
66627509594039497325711708953969586289133165339724320993714241576206582692070672
87281148490183467979899908277488360099016745185705207507885725820344193088663031
74742220273886082811546338253396232117540977001317286430939919216858700761871025
04883648220800173612755757031087544792419044177699287860855715222255510614135023
30706372831160632288499262660942154311052431900104315094339186786507006013357031
08125929293885129152264099174616004246743029176792527824811466605161478045492703
27090040582587712800567514734685257659124144431850835544283278381310315791931357
63459289106249506321560095185194943714045276693796155870508190654607382917421646
15486864936613368395909757833185705018554557948762713677856056206953385065593915
49326215023945424937441813782143778143766220175505533500485707438756395764163323
47714668439588417016028256182365660677880890399143415948539281432076160651247693
72982310275084829961404187585100633245654443972233743905144338234758859827413170
88983027723373315156469586730671906768407758289550985343535503818941377020797426
18604249085624012174154963219214543971133251713032811649089587541472009254502083
21938426925234679535003649815691245256828585977342824147515002509080267191887689
93756807224396178461744274960675671607151017304225081498878127594506757910634207
82366257650930768410626608502254524385838019829644847875689142861722171975269086
27152913039908221672006718321592434013558052896236283594560899204934144043552210
8813052796446077685440711695302241857244755302464656726076289075058391*1337=8446
32735330396026118539488137614033486681484835894553911522401035729672982739951992
59510450846561248771271822738836773072631342658924820547496339499714549977043965
30282959394551897891984120249697406451962655622236761656933974621596222296728397
20183102709193795416428153987614058613458087713533262641419642793700816304805168
68985207407486880443429354748473827987325635935798089498320484478359184559360866
27076583226192391712293067578359927580846468827613754693551137122772118377935650
64416866579070402604224929830477624243882128249086083841362204170859705333927752
53506783887636700979595292482900428172427958399610988487824191523745981361850004
22378394358434742762254571913554781639037404921838294896485533928722618505415775
20468015856906162855718175811402571115916602835577500306211903371964419937747843
68698237621235590531937189523891145666785900034163371124374965082326731487376110
98333333092709828260861059469436406514648183983015665803213913077419107406188372
35707395503957353158240382790401778302613604267141259840425062444532997625763710
49295281541865538168765060653162998657037360956425018150966653699907916926437453
64522455898449750483810932923800543871125123028238779261102286096962295954110422
53300041031861800262087455987369484209627287346984244451204684319717267396169213
64686689162749862681054381010309575068563467271336437198517817577032252061277672
60751210970442593137554100625790557600149517970271550344604758277809500736505629
11439273457043778342886520414406889931665405902225381466032093468840906182958490
40067007538064972385604595988992584428764922065891385936525652108407127397334152
77577987012630748507156907484796296338436704249630828087630933181681675714232538
16498780846317942261636333677867775907817110548388045747416843463971305692382555
89878879946652085040124400663361621041802303798851312902275116583020189066763097
91689409840039779256377571669958449000393642378255399242442113685637190833646231
60095781323920529612304032574006289858849152651185411400724689927483641929978732
84494632525395498991320929552989623300263691567683124365569447208054714159350718
63081591475681297110348362690241888609141200075894224902233777226934570198564942
62389139828831041708163976489496312464200707570741034016781184280864313770936734
13966676078625322832980760007005101208004862489022724360915838409882820115703865
87664513792449357865428353820641409325285645926908332041329290558106564944174076
98448004396467710266573872541626995999259033200592474025071939364137062868568245
40734756324139507980786753851729563208385832156894416773034762738098032723080792
44765548714573368685710420592114171685959409873882010592984896309489553137529668
91261773670019374523853883132878624380432154218001861595424734463034850618569271
90374542447907623411522862507612119581666719929400829186215604902943767120983212
02544471505640473874642620655839478699640912521556176910985261615442047526176536
97235141776796603138771014504394692811314927335598670398583505556436746592441767
65771005964615976778954300093716097017729308511008961468237442731938425891977201
43587672002741894902489811053845671227067431958118922138122251574506953505558995
19258472626056397456785349396054603988694509052100709605927409090593842025207354
53313462229692876098074439774957481872935471486966758326990650144914948701503314
13597050267262313782154363746508982901493908456173011366863634889451170372971355
04297785158228883263267504636547471231970192746858267907181665167734883778841765
83973988012795466494399915908765156011779802198725955892514094797030806615012236
41998374589083393493611728331296674043069686059246210768061588107388102747930427
68451858240898452894051575403248691748327785429480763732692852643167679903876653
82998798035791949083798194517073558852275583546403172355538414465285125901769060
33520956224233729387609101357489339640000565938555353265179358602368647929443736
50077755675142991038654325122351616097963840061225439309347683450344473435729237
54729823959690842761271167222679111659279222369969505862293059483051588848405865
434231536619097363136237839395246042763998493353068767
*and by "eventually", i mean less than 5 seconds on my laptop..
Yes it is a limitation of PHP and there is nothing you can do about it short of recompiling your PHP interpreter. Even then you are limited to the types your native system supports which wouldn't be bigger than 64bit normally. You can, as you know, use GMP, or BCMath, but that is not what your asking.
Under the hood, depending on your system the PHP integer and PHP floating point types corresponds to a signed C integer type, and C float types (PHP always uses C doubles for 'floats' AFAIK). This is a static relationship and can't change after compile time. Since the C types have fixed precision of course the PHP ones do too.
The "overflow" into a float is just a convenient compromise so you can store really big numbers, rather than not at all. Your losing some precision yeah, but only in the significand. PHP is not going to automatically convert the number to some other bigger precision floating point format because it doesn't have one.

Is it possible to use a large unsigned int64 without losing precision in PHP?

I understand Integer size, PHP_INT_MAX is platform dependent.
On 64-bit system I can get a:
$large_number = 9223372036854775807
From what I read from PHP Document Example 3 here, when integer overflows, PHP handles integer as float with a precision of roughly 14 decimals digits, i.e:
Unsigned Int64: 18446744073709551615
PHP will handles as: 1.844674407371E+19
So it seems all precision only kept up to the max of Signed Int64.
Is this really just a limitation of PHP and there is nothing I can do about it?
This is pretty hacky, and I assure you your life will be easier using GMP but it is possible using pack() and a little binary thinking:
<?php
$large_number = 9223372036854775807;
$left = 0xffffffff00000000;
$right = 0x00000000ffffffff;
$l = ($large_number & $left) >>32; //shift 32 bits left
$r = $large_number & $right;
$int64_binary_string = pack('NN', $l, $r);
I haven't tested this, and wouldn't use it in real life, but it's probably close to what you're looking for.
http://tw1.php.net/manual/en/function.pack.php
if you need precision or numbers outside of PHP_INT_MAX / PHP_INT_MIN, learn to use GMP, which will probably keep going until you run out of memory... to give you some idea of how far you can take it,
$large_number = gmp_init("9223372036854775807");
$i=0;
while(true){
echo 'iteration '.$i++.':'.gmp_strval($large_number).'*1337=';
$large_number = gmp_mul($large_number,"1337");
echo gmp_strval($large_number).PHP_EOL;
}
will eventually
iteration 1291:63173727399431265977452467325176816266767500735669001788445953704
99100022309199341754638029233101065727095873054512847649411469159231474984853877
29990385564525384931210393372816147935077346316357322846070505282141866990047417
69795035320095201175780336777052639896516690649784147989039497959127394363606555
18277493016490689369408018504673663458745651065704848764945821685549595325229654
78521759046816461228651950877052534907426557036526546565508337234675673499891633
29265311281809541141691613057522094435618917713573494707844587004419303204290366
80410319411622496279245084808349790649184389864091281089934776245296259423173088
37125998364710920001673776690982404095905353172292803413540568804924330209161221
68502039031454119485450113377479892509776976500478875924900269471621353800015849
16768619446056453580306524878177680668058129358555807454509042635315136209751306
28888008462882394248192470687562440408441365704520299664521180552207604024174563
43137016510143518117853956283018500610190006192251441907450531358798897519852285
89712288688300401723956266383086427686519451058576140512867416675873224992592868
63873656820691379608416040082157797343590944870890093034489537997624441231196880
03716995482080107872348544579795198224539076738023147659657987086535844760748293
51680757422559231216506109885022428024013042708325323490543266063675126192858475
51062320509059668456301511665702512575733290996693385011230330439062943182094596
72982868367513131107811463983324141985257032192551001490775273440704964956322520
07994322409745388858643755238449137799970426027598547825636867768578263720009398
06345603047100479826296034929890108340101488966701293667796312958087571285537092
98292308718879824518810679195685709967212889579496467906343837737351387116485926
96065604380646092415099392666166947273008556519323980631398826013377061548412499
37045775535278706790702274483174254245054418225127782273776637425449169726435461
00864900455001093729251741310689643202116980745998974559375404087598011323913589
37378336888032750432647317316783507777959680594838416103235878202519306235270714
07689264877781232001726371838121263807804664374737613209359850417045192588050394
70657700599839677955302104699239419723871651195923433991338871172082351085772713
85795544605616579911291449220540413076513145849439424174121530477862582225947332
71577283620910275735801384726436002832118799836996365693738642178527175171378406
17487708039971384270639342138853231882316669599224158264716457232654635304792216
85595639961619807370286817974879544351592128186367207420223323272766972084744559
66627509594039497325711708953969586289133165339724320993714241576206582692070672
87281148490183467979899908277488360099016745185705207507885725820344193088663031
74742220273886082811546338253396232117540977001317286430939919216858700761871025
04883648220800173612755757031087544792419044177699287860855715222255510614135023
30706372831160632288499262660942154311052431900104315094339186786507006013357031
08125929293885129152264099174616004246743029176792527824811466605161478045492703
27090040582587712800567514734685257659124144431850835544283278381310315791931357
63459289106249506321560095185194943714045276693796155870508190654607382917421646
15486864936613368395909757833185705018554557948762713677856056206953385065593915
49326215023945424937441813782143778143766220175505533500485707438756395764163323
47714668439588417016028256182365660677880890399143415948539281432076160651247693
72982310275084829961404187585100633245654443972233743905144338234758859827413170
88983027723373315156469586730671906768407758289550985343535503818941377020797426
18604249085624012174154963219214543971133251713032811649089587541472009254502083
21938426925234679535003649815691245256828585977342824147515002509080267191887689
93756807224396178461744274960675671607151017304225081498878127594506757910634207
82366257650930768410626608502254524385838019829644847875689142861722171975269086
27152913039908221672006718321592434013558052896236283594560899204934144043552210
8813052796446077685440711695302241857244755302464656726076289075058391*1337=8446
32735330396026118539488137614033486681484835894553911522401035729672982739951992
59510450846561248771271822738836773072631342658924820547496339499714549977043965
30282959394551897891984120249697406451962655622236761656933974621596222296728397
20183102709193795416428153987614058613458087713533262641419642793700816304805168
68985207407486880443429354748473827987325635935798089498320484478359184559360866
27076583226192391712293067578359927580846468827613754693551137122772118377935650
64416866579070402604224929830477624243882128249086083841362204170859705333927752
53506783887636700979595292482900428172427958399610988487824191523745981361850004
22378394358434742762254571913554781639037404921838294896485533928722618505415775
20468015856906162855718175811402571115916602835577500306211903371964419937747843
68698237621235590531937189523891145666785900034163371124374965082326731487376110
98333333092709828260861059469436406514648183983015665803213913077419107406188372
35707395503957353158240382790401778302613604267141259840425062444532997625763710
49295281541865538168765060653162998657037360956425018150966653699907916926437453
64522455898449750483810932923800543871125123028238779261102286096962295954110422
53300041031861800262087455987369484209627287346984244451204684319717267396169213
64686689162749862681054381010309575068563467271336437198517817577032252061277672
60751210970442593137554100625790557600149517970271550344604758277809500736505629
11439273457043778342886520414406889931665405902225381466032093468840906182958490
40067007538064972385604595988992584428764922065891385936525652108407127397334152
77577987012630748507156907484796296338436704249630828087630933181681675714232538
16498780846317942261636333677867775907817110548388045747416843463971305692382555
89878879946652085040124400663361621041802303798851312902275116583020189066763097
91689409840039779256377571669958449000393642378255399242442113685637190833646231
60095781323920529612304032574006289858849152651185411400724689927483641929978732
84494632525395498991320929552989623300263691567683124365569447208054714159350718
63081591475681297110348362690241888609141200075894224902233777226934570198564942
62389139828831041708163976489496312464200707570741034016781184280864313770936734
13966676078625322832980760007005101208004862489022724360915838409882820115703865
87664513792449357865428353820641409325285645926908332041329290558106564944174076
98448004396467710266573872541626995999259033200592474025071939364137062868568245
40734756324139507980786753851729563208385832156894416773034762738098032723080792
44765548714573368685710420592114171685959409873882010592984896309489553137529668
91261773670019374523853883132878624380432154218001861595424734463034850618569271
90374542447907623411522862507612119581666719929400829186215604902943767120983212
02544471505640473874642620655839478699640912521556176910985261615442047526176536
97235141776796603138771014504394692811314927335598670398583505556436746592441767
65771005964615976778954300093716097017729308511008961468237442731938425891977201
43587672002741894902489811053845671227067431958118922138122251574506953505558995
19258472626056397456785349396054603988694509052100709605927409090593842025207354
53313462229692876098074439774957481872935471486966758326990650144914948701503314
13597050267262313782154363746508982901493908456173011366863634889451170372971355
04297785158228883263267504636547471231970192746858267907181665167734883778841765
83973988012795466494399915908765156011779802198725955892514094797030806615012236
41998374589083393493611728331296674043069686059246210768061588107388102747930427
68451858240898452894051575403248691748327785429480763732692852643167679903876653
82998798035791949083798194517073558852275583546403172355538414465285125901769060
33520956224233729387609101357489339640000565938555353265179358602368647929443736
50077755675142991038654325122351616097963840061225439309347683450344473435729237
54729823959690842761271167222679111659279222369969505862293059483051588848405865
434231536619097363136237839395246042763998493353068767
*and by "eventually", i mean less than 5 seconds on my laptop..
Yes it is a limitation of PHP and there is nothing you can do about it short of recompiling your PHP interpreter. Even then you are limited to the types your native system supports which wouldn't be bigger than 64bit normally. You can, as you know, use GMP, or BCMath, but that is not what your asking.
Under the hood, depending on your system the PHP integer and PHP floating point types corresponds to a signed C integer type, and C float types (PHP always uses C doubles for 'floats' AFAIK). This is a static relationship and can't change after compile time. Since the C types have fixed precision of course the PHP ones do too.
The "overflow" into a float is just a convenient compromise so you can store really big numbers, rather than not at all. Your losing some precision yeah, but only in the significand. PHP is not going to automatically convert the number to some other bigger precision floating point format because it doesn't have one.

How to compare two 64 bit numbers

In PHP I have a 64 bit number which represents tasks that must be completed. A second 64 bit number represents the tasks which have been completed:
$pack_code = 1001111100100000000000000011111101001111100100000000000000011111
$veri_code = 0000000000000000000000000001110000000000000000000000000000111110
I need to compare the two and provide a percentage of tasks completed figure. I could loop through both and find how many bits are set, but I don't know if this is the fastest way?
Assuming that these are actually strings, perhaps something like:
$pack_code = '1001111100100000000000000011111101001111100100000000000000011111';
$veri_code = '0000000000000000000000000001110000000000000000000000000000111110';
$matches = array_intersect_assoc(str_split($pack_code),str_split($veri_code));
$finished_matches = array_intersect($matches,array(1));
$percentage = (count($finished_matches) / 64) * 100
Because you're getting the numbers as hex strings instead of ones and zeros, you'll need to do a bit of extra work.
PHP does not reliably support numbers over 32 bits as integers. 64-bit support requires being compiled and running on a 64-bit machine. This means that attempts to represent a 64-bit integer may fail depending on your environment. For this reason, it will be important to ensure that PHP only ever deals with these numbers as strings. This won't be hard, as hex strings coming out of the database will be, well, strings, not ints.
There are a few options here. The first would be using the GMP extension's gmp_xor function, which performs a bitwise-XOR operation on two numbers. The resulting number will have bits turned on when the two numbers have opposing bits in that location, and off when the two numbers have identical bits in that location. Then it's just a matter of counting the bits to get the remaining task count.
Another option would be transforming the number-as-a-string into a string of ones and zeros, as you've represented in your question. If you have GMP, you can use gmp_init to read it as a base-16 number, and use gmp_strval to return it as a base-2 number.
If you don't have GMP, this function provided in another answer (scroll to "Step 2") can accurately transform a string-as-number into anything between base-2 and 36. It will be slower than using GMP.
In both of these cases, you'd end up with a string of ones and zeros and can use code like that posted by #Mark Baker to get the difference.
Optimization in this case is not worth of considering. I'm 100% sure that you don't really care whether your scrip will be generated 0.00000014 sec. faster, am I right?
Just loop through each bit of that number, compare it with another and you're done.
Remember words of Donald Knuth:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
This code utilizes the GNU Multi Precision library, which is supported by PHP, and since it is implemented in C, should be fast enough, and supports arbitrary precision.
$pack_code = gmp_init("1001111100100000000000000011111101001111100100000000000000011111", 2);
$veri_code = gmp_init("0000000000000000000000000001110000000000000000000000000000111110", 2);
$number_of_different_bits = gmp_popcount(gmp_xor($pack_code, $veri_code));
$a = 11111;
echo sprintf('%032b',$a)."\n";
$b = 12345;
echo sprintf('%032b',$b)."\n";
$c = $a & $b;
echo sprintf('%032b',$c)."\n";
$n=0;
while($c)
{
$n += $c & 1;
$c = $c >> 1;
}
echo $n."\n";
Output:
00000000000000000010101101100111
00000000000000000011000000111001
00000000000000000010000000100001
3
Given your PHP-setuo can handle 64bit, this can be easily extended.
If not you can sidestep this restriction using GNU Multiple Precision
You could also split up the HEx-Representation and then operate on those coresponding parts parts instead. As you need just the local fact of 1 or 0 and not which number actually is represented! I think that would solve your problem best.
For example:
0xF1A35C and 0xD546C1
you just compare the binary version of F and D, 1 and 5, A and 4, ...

How can you parse a Java 64-bit long from a binary file into a PHP string?

I've used unpack to convert most of the data types I have in a binary file that I'm parsing with little problems. I have no idea how to work with a big endian 64-bit signed long. I think this data type is stored using 2's complement. The application of the data file I'm reading is a java app so I assume it's 2's complement. I don't need to work with it as a number but simply work with it as a string.
Java 64-bit integers are indeed stored natively as "network-order" (big endian, i.e. start with the most significant byte) 8-byte 2's complement format. So typically you take byte at a time, shift left by 8, repeat. Byte values can be thought of as unsigned (while result is signed), but with left-shifting this should not matter.
So: first you just created equivalent 64-bit int from bytes, and display from there. No point in using short cuts; while it is possible, you just end up with more complicated and less efficient code.
32-bit PHP will only have signed 32-bit integers, thus as far as I know, there's no way to natively unpack the data.
The following code should be able to read a big endian, two's complement 64-bit integer:
<?php
function read_int64($fp)
{
$hex = unpack('H16a', fread($fp, 8));
$hex = '0x'.$hex['a'];
$n = gmp_init($hex);
if (gmp_testbit($n, 63))
{
$n = gmp_xor($n, '0xffffffffffffffff'); // flip the bits
$n = gmp_neg(gmp_add($n, 1)); // add one and negate
}
return gmp_strval($n);
}
?>
It returns the integer as a string. It can be used like:
$fp = fopen('test.bin', 'rb');
echo read_int64($fp)."\n";
fclose($fp);
(Edit: Updated code to call fewer GMP functions.)

PHP 64 bit numbers?

I have a simple function that I'm using but for some reason the number doesn't calculate correctly as it would in a calculator. I think it has something to do with the numbers being too large, or something to do with 64 bit. Is there any way I can convert them so that they would work correctly?
$sSteamComID = 76561197990369545;
$steamBase = 76561197960265728;
function convertToSteamID($sSteamComID) {
$sServer = bcmod($sSteamComID, '2') == '0' ? '0' : '1';
$sCommID = bcsub($sSteamComID, $sServer);
$sCommID = bcsub($sCommID, $steamBase);
$sAuth = bcdiv($sCommID, '2');
echo "$sServer:$sAuth";
}
convertToSteamID($sSteamComID);
This function outputs 0:15051912 on a server when it should be printing 1:15051908
The missing global $steamBase was the problem, as already mentioned in a comment. (Tip: turn on E_NOTICE during development.) However, I'd like to address your question:
I think it has something to do with
the numbers being too large, or
something to do with 64 bit. Is there
any way I can convert them so that
they would work correctly?
PHP integers are signed and platform-dependent. Using 64-bit numbers will not work if you are on a 32-bit host.
So your concern is valid. But even on a 64-bit system:
$x = 9223372036854775808; // highest bit (64th) set
var_dump($x);
--> float(9.2233720368548E+18)
Note that PHP's BC Math routines operate on strings, not integers. Thus, you should be storing your big numbers as strings.
This will work around the potential problem of integers being converted to floats, which will happen even on your 64-bit environment if you are using large, unsigned integers.

Categories