optimus icon indicating copy to clipboard operation
optimus copied to clipboard

What's wrong?

Open EthraZa opened this issue 7 years ago • 17 comments

Hi. Using the example numbers:

$optimus = new Jenssegers\Optimus\Optimus(1580030173, 59260789, 1163945558);

$id = "1000000000"; //10 digits
$encoded = $optimus->encode($id);
$original = $optimus->decode($encoded);
print_r(array($id, $encoded, $original), true); 
// ["1000000000", 1768948822, 1000000000]

$id = "10000000000"; //11 digits
$encoded = $optimus->encode($id);
$original = $optimus->decode($encoded);
print_r(array($id, $encoded, $original), true); 
// ["10000000000", 2109978198, 856559616]


$id = "100000000000"; //12 digits
$encoded = $optimus->encode($id);
$original = $optimus->decode($encoded);
print_r(array($id, $encoded, $original), true); 
// ["100000000000", 1163945558, 0]

My IDs are MySQL's bigint that can be 20 digits long! Optimus is not for me? What am I missing? There is a length limit?


php -v PHP 5.3.2-1ubuntu4.30 with Suhosin-Patch (cli) (built: Apr 17 2015 15:01:29) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

uname -a Linux picard 2.6.32-74-server #142-Ubuntu SMP Tue Apr 28 10:12:19 UTC 2015 x86_64 GNU/Linux


I had to change line 108 at src/Optimus.php to get it working:

if (! in_array($mode, [static::MODE_GMP, static::MODE_NATIVE])) {

to

if (! in_array($mode, array(static::MODE_GMP, static::MODE_NATIVE)) ) {

Thanks in advance.

EthraZa avatar Jul 07 '16 13:07 EthraZa

You are using PHP 5.3 which was released in 2009 and where support ended for in 2014. Short array syntax ([] instead of array()) was introduced in PHP 5.4.

This package requires PHP >= 5.4 if you have a look at the composer.json file.

Anyway, support for PHP 5.4 ended in 2015, and 5.5 was actually supported until yesterday, so I'd recommend you to upgrade to 5.6 if you can.

fabiandev avatar Jul 11 '16 20:07 fabiandev

Yes I noticed the sintaxe, because of that I have to change line 108. So are you saying that even changing this line and it seeming as it's working, it will not work properly because of the PHP version?

EthraZa avatar Jul 11 '16 20:07 EthraZa

I'm not the author of this package, but as it requires PHP >= 5.4 you may experience unexpected behavior with a lower version. What you can do is to run the tests and check if they pass.

fabiandev avatar Jul 12 '16 10:07 fabiandev

Optimus only works if the id is less than max int. it is designed that way. If you want, you can fork the library and increase MAX_INT not 9223372036854775807. https://github.com/jenssegers/optimus/issues/17

pjebs avatar Jul 22 '16 13:07 pjebs

We could add a method to override the internal max integer value.

jenssegers avatar Jul 25 '16 09:07 jenssegers

@jenssegers @pjebs i did try to increase MAX_INT in Optimus.php but it doesn't work

#uname -a
Linux web2 2.6.32-573.8.1.el6.x86_64 #1 SMP Tue Nov 10 18:01:38 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
...
const MAX_INT = 100000000000; //12 digits
...
$ob = new Jenssegers\Optimus\Optimus(615006283, 1261799779, 332484960);
$id = "10000000000"; //11 digits
$encoded = $ob->encode($id);
$original = $ob->decode($encoded);
print_r(array($id, $encoded, $original));

Result:

Array
(
    [0] => 10000000000
    [1] => 30528477536
    [2] => 73155108864
)

tamhv avatar Feb 08 '17 12:02 tamhv

are you sure const MAX_INT = 100000000000; //12 digits is within the class. I thikn jensegers added a method to override the default in new version.

pjebs avatar Feb 08 '17 12:02 pjebs

@pjebs I'm very sure. I also checked over the source but no method to override default MAX_INT. I saw your comments on repo optimus-go, it seems very easy to change, but i have no idea why it doesn't work on my test. Thank you!

v0.2.2

php -v
PHP 5.6.30 (cli) (built: Jan 19 2017 10:06:11) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
...
<?php namespace Jenssegers\Optimus;

use InvalidArgumentException;

class Optimus
{
    /**
     * @var int
     */
    const MAX_INT = 100000000000;

    /**
     * @var string
     */
    private static $mode;

    /**
     * Use GMP extension functions.
     */
    const MODE_GMP = 'gmp';

    /**
     * Use native PHP implementation.
     */
    const MODE_NATIVE = 'native';

    /**
     * @var int
     */
    private $prime;

    /**
     * @var int
     */
    private $inverse;

    /**
     * @var int
     */
    private $xor;

    /**
     * @param int $prime
     * @param int $xor
     * @param int $inverse
     */
    public function __construct($prime, $inverse, $xor = 0)
    {
        $this->prime = (int) $prime;
        $this->inverse = (int) $inverse;
        $this->xor = (int) $xor;

        // Check which calculation mode should be used.
        if (static::$mode === null) {
            static::$mode = PHP_INT_SIZE === 4 ? static::MODE_GMP : static::MODE_NATIVE;
        }
    }

    /**
     * Encode an integer.
     *
     * @param  int $value
     * @return int
     */
    public function encode($value)
    {
        if (! is_numeric($value)) {
            throw new InvalidArgumentException('Argument should be an integer');
        }

        switch (static::$mode) {
            case self::MODE_GMP:
                return (gmp_intval(gmp_mul($value, $this->prime)) & static::MAX_INT) ^ $this->xor;

            default:
                return (((int) $value * $this->prime) & static::MAX_INT) ^ $this->xor;
        }
    }

    /**
     * Decode an integer.
     *
     * @param  int $value
     * @return int
     */
    public function decode($value)
    {
        if (! is_numeric($value)) {
            throw new InvalidArgumentException('Argument should be an integer');
        }

        switch (static::$mode) {
            case static::MODE_GMP:
                return gmp_intval(gmp_mul((int) $value ^ $this->xor, $this->inverse)) & static::MAX_INT;

            default:
                return (((int) $value ^ $this->xor) * $this->inverse) & static::MAX_INT;
        }
    }

    /**
     * Set the internal calculation mode (mainly used for testing).
     *
     * @param string $mode
     */
    public function setMode($mode)
    {
        if (! in_array($mode, [static::MODE_GMP, static::MODE_NATIVE])) {
            throw new InvalidArgumentException('Unkown mode: ' . $mode);
        }

        static::$mode = $mode;
    }
}

tamhv avatar Feb 08 '17 12:02 tamhv

Try essentially creating your own Optimus class that is exactly the same as the official one and then a) test if your test works and b) if your changed MAX_INT is reflected inside the class

pjebs avatar Feb 08 '17 21:02 pjebs

hi @pjebs i forked this repo, change MAX_INT,.. and made a test https://github.com/tamhv/optimus/blob/master/tests/CustomTest.php

//        const MAX_INT = 1000000000000;//13 digits
//
//        var_dump(\Jenssegers\Optimus\Energon::generatePrime());//204370143667
//        ./optimus spark 204370143667
//        Prime: 204370143667
//        Inverse: 676326779
//        Random: 1054205207
//
//        new Optimus(204370143667, 676326779, 1054205207);


        $ob = new Optimus(204370143667, 676326779, 1054205207);

        $id = 10000000000; //11 digits

        $encoded = $ob->encode($id);
        $original = $ob->decode($encoded);

        print_r([$id, $encoded, $original]);

//        Array
//        (
//            [0] => 10000000000
//            [1] => 722264515863
//            [2] => 446746066944
//        )


//         encode?
//         (((int) $value * $this->prime) & static::MAX_INT) ^ $this->xor;
//         (((int) 10000000000 * 204370143667) & 1000000000000) ^ 1054205207; //722264515863
//
//         decode?
//         (((int) $value ^ $this->xor) * $this->inverse) & static::MAX_INT;
//         (((int) 722264515863 ^ 1054205207) * 676326779) & 1000000000000; //446746066944

It still doesn't work, can you please have a look and correct me if anything wrong. Thank you in advance.

tamhv avatar Feb 09 '17 05:02 tamhv

Can you try the example values in the ReadMe. See if you can recreate those results.

pjebs avatar Feb 09 '17 06:02 pjebs

I suspect const MAX_INT = 1000000000000;//13 digits can't just be any number. I think it has to be a power of 2 (not documented).

pjebs avatar Feb 09 '17 06:02 pjebs

it doesn't match (PRIME * INVERSE) & MAXID == 1, so there is some thing wrong with optimus spark . It gave me wrong PRIME and INVERSE if MAX_INT greater than 2147483647.

I did try with MAX_INT=8589934593 and ((366693263 * 620196719) & 8589934593) == 1 but still not work:

$ob = new Optimus(366693263, 620196719, 1066048704);
$id = 5; //11 digits

$encoded = $ob->encode($id);
$original = $ob->decode($encoded);

 print_r([$id, $encoded, $original]);
Array
(
    [0] => 5
    [1] => 1066048705
    [2] => 1
)

tamhv avatar Feb 09 '17 07:02 tamhv

@tamhv, @pjebs take a look at #29 – that should help.

ConnorVG avatar Jun 05 '17 15:06 ConnorVG

It seems the max number can only be 2147483647? even 64bit system with PHP 7.1 I'm not sure this issue is from this package code or the limitation of hashing algorithm used.

ElfSundae avatar Oct 10 '17 16:10 ElfSundae

Installed optimus package and used the below code

$optimus = new Optimus(158003, 59260, 1163);

$value = "10000"; $encoded = $optimus->encode($value); $original = $optimus->decode($encoded); print_r(array($value, $encoded, $original), true);

i am getting this error :: Call to undefined function Jenssegers\Optimus\gmp_intval()

chinnalamahesh avatar Dec 18 '17 09:12 chinnalamahesh

you prob need gmt php extension installed

pjebs avatar Dec 18 '17 09:12 pjebs