2013-10-06 2 views
0

Требуется много времени, чтобы выяснить, что привело к сбою в работе моего сайта при переходе на лучшую подписку на хостинг.Как бороться с целым максимальным разницей между 32-битными и 64-битными серверами?

Я использую «самодельный» уникальный уникальный генератор для генерации всего, что должно быть уникальным, но эта уникальность не случайна. Я использую это для связи между несколькими службами, генерируя воспроизводимые уникальные «числа» для файлов, статей и т. Д.

Это функция, которую я создал и никогда не имел проблем с (я думаю, что она никогда не работает на 64-битной системе раньше?) Для создания уникального идентификатора. Я знаю, что эта уникальность ограничена (64 000), но до сих пор не приводит к проблеме.

function suGetHashCode($s) 
{ 
$hash=0; 
$c=(is_string($s))?strlen($s):0; 
$i=0; 
while($i<$c) 
{ 
    $hash = (($hash << 5)-$hash)+ord($s{$i++}); 
    //hash = hash & hash; // Convert to 32bit integer 
} 
return ($hash < 0)?(($hash*-1)+0xFFFFFFFF):$hash; // convert to unsigned int 
} 

function suUniqueId($s, $bAddLen = false) 
{ 
    $i = base_convert(suGetHashCode($s), 10, 32); 
    if($bAddLen && is_string($s)) 
    { $i.=('-'.suGetLz(dechex(strlen($s)*4), 3)); } 

    return $i; 
} 

function suGetLz($i, $iMaxLen) // Leading zero 
{ 
    if(!is_numeric($i) || $i < 0 || $iMaxLen <= 0) 
    { return $i; } 
    $c = strlen($i); 
    while($c < $iMaxLen) 
    { $c++; $i='0'.$i; } 
    return $i; 
} 

Максимальное ИНТ значение целого числа на новой системе:

PHP_INT_MAX = 9223372036854775807 

На другой системе (ах) это:

PHP_INT_MAX = 2147483647 

Ну, я не математика человек, я думаю, что это вызывает проблему из-за приращения 0xFFFFFFFF, когда отрицательный (я думаю, что он никогда не будет отрицательным в этой новой системе).

Но как я могу изменить функцию, которая создает тот же уникальный идентификатор, что и на других системах?

Например: Он производит один и тот же идентификатор для различных строк на новый хостинг-сервер:

$sThisUrl = '<censored>'; 
var_dump(suUniqueId($sThisUrl)); // Produce: 1l5kc37uicb 
$sThisUrl = '<censored>'; 
var_dump(suUniqueId($sThisUrl)); // Produce the same id as above: 1l5kc37uicb 

Но это должно быть, как на старых системах:

$sThisUrl = '<censored>'; 
var_dump(suUniqueId($sThisUrl)); // Produce: a46q6nd 
$sThisUrl = '<censored>'; 
var_dump(suUniqueId($sThisUrl)); // Produce: 2mirj1h 

Извещение: строка разделяется на части, чтобы избежать переполнения stackoverflow, см. ссылку.

EDIT: Удалены имена файлов

ли кто-нибудь, как справиться с этой проблемой?

+0

Нет смысла говорить «отредактировать: удалить X», потому что он просто обращает внимание на исходное сообщение http://stackoverflow.com/revisions/19214266/1 –

+0

В некотором роде вы правы, но все в порядке, поставьте два разных длинных URL-адреса в примере, и вы увидите, что он дает те же результаты, когда на 64-битной. – Codebeat

+0

Вы не можете легко вернуть материал, который вы разместили под лицензией cc-by-sa. Редактирование вопроса сделает его менее заметным, но вопрос в его первоначальной форме больше не является вашей исключительной собственностью. Кроме того, удаление строк затрудняет воспроизведение этой проблемы другими. И поскольку у немногих людей есть 32-битные и 64-битные установки PHP под рукой, это значительно снижает шансы на сравнение. – MvG

ответ

1

Я предлагаю вам усечение после каждого символа обрабатывается:

$hash = (($hash << 5)-$hash)+ord($s{$i++}); 
$hash = $hash & 0xFFFFFFFF; // Convert to 32bit integer 

По крайней мере, на моей 64-битной системы это приводит к желаемому 2mirj1h в вашем втором примере, хотя и без этой модификации я 1c6ta2qjga7 и не 1l5kc37uicb, как вы сделал.

Я также изменил бы возвращаемое значение, чтобы просто вернуть $hash. Либо он может представлять неподписанные 32-битные числа правильно, тогда предыдущая маска должна принудительно интерпретировать эту интерпретацию. Или ваша система не может их представлять, тогда добавленное вычисление не приведет вас туда, и вам придется разбить число на группы бит и подстроить их индивидуально.

Конечно, самым простым решением было бы использовать некоторый хорошо известный общий алгоритм хэширования, например. используя the hash function. Добавьте какую-то секретную соль, если вы подвигаете, это может открыть вам атаки. Если результат такого хеш-кода слишком длинный, вы можете просто принять участие в выходе.Вы можете конвертировать базу так, как вам нравится, поэтому вам не придется использовать шестнадцатеричную нотацию, общую для хэшей. Использование криптографического хэша также уменьшит вероятность конфликта; например, в вашем случае документ generbM.js в том же пути даст такой же хеш.

+0

Большое вам спасибо! Все проблемы пошли с этим изменением. Причина, по которой я использую это, потому что результаты, которые он производит, не настолько велики, как другие хеши. Я не использую его для обеспечения безопасности, для простых задач, иногда как контрольная сумма, иногда как идентификатор или идентификатор файла (темп или что-то еще) и между различными платформами. Еще раз спасибо! – Codebeat

+0

* Если результат такого хеш-кода слишком длинный, вы можете просто принять участие в выпуске * Таким образом, больше не гарантируя уникальность ... –

+1

@ ta.speot.is: Хэши не гарантируют уникальность, они просто разработаны так что конфиденциальные (а в случае криптографических хешей не столь аккуратные) столкновения крайне маловероятны. Уменьшите размер и шансы на увеличение столкновений, но я все равно буду больше доверять усеченному MD5, чем любой самодельный материал с той же выходной длиной (или той же энтропией, если быть более точным, и учитывать разные основания). – MvG

1

Если бы я был вами, я бы написал блок-тест, чтобы убедиться, что вы получите одинаковые результаты на 32-битной и 64-битной машинах для этой функции.

Петля должна быть изменена в чем-то вроде этого:

while($i<$c) 
{ 
    $hash = (($hash << 5)-$hash)+ord($s{$i++}); 
    hash = hash & 0xFFFFFFFF; // Convert to 32bit integer 
} 
$hash = ($hash < 0)?(($hash*-1)+0xFFFFFFFF):$hash; // convert to unsigned int 
return $hash & 0xFFFFFFFF; // Convert to 32bit integer 

Ваш тест блок может работать с оригиналом на 32-разрядной версии и сохранить результат. Затем запустите это на 64 бит и сравните с этими 32-битными результатами. Если кто-то другой, вы знаете, что у вас все еще нет эквивалента 1 к 1.

+0

Как и в первом ответе, но спасибо в любом случае. Кроме того, отрицательная проверка не нужна, потому что она работает на 64-битной и может создавать WORD. – Codebeat

+0

Он не упоминает '$ hash & 0xFFFFFFFF' и не пишет блок-тесты ... На самом деле, он говорит, что вы можете просто вернуть $ хэш, но это может изменить способ его работы, который, если вы использовали это какое-то время, означал бы вас имеют данные в базах данных, которые полагаются на него, поэтому, вероятно, это не очень хорошая идея. –

+0

Ну, я прочитал его сообщение и заработал его. Я имею в виду, я понимаю смысл его должности. Спасибо, в любом случае! – Codebeat

 Смежные вопросы

  • Нет связанных вопросов^_^