Преобразование сложных PHP Поворот функций для работы в 64-битных
Несколько лет назад мой веб-хост изменился с 32-битного на 64-битный, и критический PHP script перестает работать. Это было обусловлено тем, что < и → (бит сдвига) операций, которые изменились. Я смог исправить свою проблему, заменив подпрограммы rotateleft и rotateright с помощью rotateleft32 и rotateright32 следующим образом:
function rotateleft($value, $numleft) {
return (($value << $numleft) | ($value >> (32-$numleft)));
}
function rotateleft32($value, $numleft) {
return ((($value << $numleft) | ($value >> (32-$numleft))) & 0xFFFFFFFF);
}
function rotateright($value, $numright) {
return (($value >> $numright) | ($value << (32-$numright)));
}
function rotateright32($value, $numright) {
return ((($value >> $numright) | ($value << (32-$numright))) & 0xFFFFFFFF);
}
Теперь я столкнулся с новым набором кода, который, похоже, является одной и той же проблемой, но это сложнее:
function ECC_RotateLeft($a)
{
$copya = makecopy($a);
$bit = ($copya->e[0] & ECC_UPRBIT) ? 1 : 0;
/* looped
for ($i = 0; $i < ECC_MAXLONG - 1; $i++)
$copya->e[$i] = ($copya->e[$i] << 1) | (($copya->e[$i + 1] & ECC_MSB) ? 1 : 0);
$copya->e[0] &= ECC_UPRMASK;
looped */
/* unlooped */
// These lines are optimized for ECC_MAXLONG==4 only!
$bit = ($copya->e[0] & ECC_UPRBIT) ? 1 : 0;
$copya->e[0] = (($copya->e[0] << 1) & ECC_UPRMASK) | (($copya->e[1] & ECC_MSB) ? 1 : 0);
$copya->e[1] = ($copya->e[1] << 1) | (($copya->e[2] & ECC_MSB) ? 1 : 0);
$copya->e[2] = ($copya->e[2] << 1) | (($copya->e[3] & ECC_MSB) ? 1 : 0);
/* unlooped */
$copya->e[3] = ($copya->e[3] << 1) | $bit;
return $copya;
}
function ECC_RotateRight($a)
{
$copya = makecopy($a);
$bit = ($copya->e[ECC_NUMWORD] & 1) ? ECC_UPRBIT : 0;
/* looped
for ($i = ECC_MAXLONG - 1; $i > 0; $i--)
$copya->e[$i] = (($copya->e[$i] >> 1) & 0x7FFFFFFF) | (($copya->e[$i - 1] & 1) ? ECC_MSB : 0);
looped */
/* unlooped */
// Thes lines are optimized for ECC_MAXLONG==4 only!
$copya->e[3] = (($copya->e[3] >> 1) & 0x7FFFFFFF) | (($copya->e[2] & 1) ? ECC_MSB : 0);
$copya->e[2] = (($copya->e[2] >> 1) & 0x7FFFFFFF) | (($copya->e[1] & 1) ? ECC_MSB : 0);
$copya->e[1] = (($copya->e[1] >> 1) & 0x7FFFFFFF) | (($copya->e[0] & 1) ? ECC_MSB : 0);
/* unlooped */
$copya->e[0] = (($copya->e[0] >> 1) & 0x7FFFFFFF) | $bit;
return $copya;
}
У меня есть три проблемы, пытаясь исправить это сам:
- Это не мой код, поэтому я не знаком с тем, что он пытается сделать.
- У меня больше нет 32-битного сервера, чтобы проверить его на
- Я адекватен, но не эксперт в PHP.
Я хотел бы знать, действительно ли кто-нибудь видит простое исправление, позволяющее этому коду работать на 64-битном сервере и давать тот же результат, что и на 32-битном сервере.
Если нет, как бы вы порекомендовали я отлаживать это, учитывая, что у меня нет 32-битного результата для сравнения с?
Вот некоторые обсуждения этой проблемы и попытка заставить разработчика исправить это:
Как получить устаревшее 32-разрядное keymaker.php script Работает на 64-битном уровне
Ответы
Ответ 1
Отвечая на все четыре вопроса:
1. It is not my code, so I am not familiar with what it is trying to do.
Хотя я мог бы подробно изучить процедуры отслеживания и отладки, я рекомендую классику. Я настоятельно рекомендую выбрать это, если это ваша дневная работа или у вас есть более чем интересный интерес к рефакторингу в будущем.
2. I no longer have a 32-bit server to test it against
Как упоминалось Оли в ошибках, вы захотите настроить 32-разрядную виртуальную машину или chroot, в зависимости от ОС, на которой работает ваш сервер.
3. I am adequate, but not an expert in PHP.
Как и выше, если это больше, чем просто проблема с пятнами, я рекомендую классики.
4. (Исправление фактического кода)
Прежде всего, eW. Отсутствует документация, критический комментарий, повторяющаяся логика и невыразительные имена переменных, которые не могут эффективно инкапсулировать их логику. Это не худший код, который я видел, но я сочувствую вам.
Тем не менее, результат не обязательно неправильный. Если у вас нет серии модульных тестов для него в вашей базе кода, я рекомендую добавить их.
Если вы хотите сравнить эффективность этой функции, я настоятельно рекомендую сравнить ее с результатами алгоритмов, определенных в примечаниях здесь. В идеале вам понадобится одна из реализаций ближайшая к этой ссылочной реализации.
Кража одного из вершин этого потока и повторного его применения к вашему API:
function ECC_RotateLeft($value,$amount) {
if ($amount>0) {
$amount %= 32;
$value = ($value<<$amount) | ($value>>(32-$amount));
}
return $value;
}
function ECC_RotateRight($value,$amount) {
if ($amount>0) {
$amount %= 32;
$value = ($value>>$amount) | ($value<<(32-$amount));
}
return $value;
}
(Не удивительно, что это похоже на реализацию, которую вы изначально предоставили.)
Почему я включаю $amount
как часть спецификации? Простой: он не нарушает encapsulation, как код, который вы рефакторинг. Похоже, что при необходимости можно установить ($copya->e[0] & ECC_UPRBIT) ? 1 : 0
.
Короче: самый простой способ рефакторинга - это не обязательно смотреть на его содержащуюся логику. Иногда необходимо определить намерение и найти хорошую ссылочную реализацию.