PHP base_convert для сокращения URL - PullRequest
6 голосов
/ 19 июля 2011

Я хочу, чтобы мои URL были короче, аналогичны tinyurl или любому другому сервису сокращения URL. У меня есть следующий тип ссылок:

localhost/test/link.php?id=1000001
localhost/test/link.php?id=1000002

и т.д.

Идентификаторы в вышеуказанных ссылках являются автоматически увеличивающимися идентификаторами строк из базы данных. Приведенные выше ссылки отображаются так:

localhost/test/1000001
localhost/test/1000002

Теперь вместо использования указанных длинных идентификаторов я бы хотел их сократить. Я обнаружил, что могу использовать функцию base_convert(). Например:

print base_convert(100000000, 10, 36);

//output will be "1njchs"

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

Спасибо.

Ответы [ 3 ]

4 голосов
/ 19 июля 2011

Функция base_convert достаточно быстрая, но если вы хотите добиться большего, просто сохраните закодированную строку в базе данных.

3 голосов
/ 21 апреля 2014

С помощью base_convert() вы можете преобразовать строку в более короткий код, а затем с помощью intval() создать идентификатор для хранения элемента в базе данных

Фрагмент моего кода: -

$code = base_convert("long string", 10, 36);
$ID= intval($code ,36); 
0 голосов
/ 24 февраля 2018

К сожалению, я не был удовлетворен ответами здесь и в других местах, так как base_convert() и другие стратегии преобразования на основе плавающей запятой теряют недопустимую точность для криптографических целей. Кроме того, большинство этих реализаций не способны работать с числами, достаточно большими для криптографического применения. Ниже приведены два метода преобразования баз, которые должны быть безопасными для больших баз ». Например, преобразование base256 (двоичная строка) в представление base85 и обратно.

Использование GMP

Вы можете использовать GMP для достижения этой цели за счет преобразования bin <-> hex в два ненужных раза, а также ограничения в base62.

<?php
// Not bits, bytes.
$data = openssl_random_pseudo_bytes(256);

$base62 = gmp_strval( gmp_init( bin2hex($data), 16), 62 );
$decoded = hex2bin( gmp_strval( gmp_init($base62, 62), 16 ));

var_dump( strcmp($decoded, $data) === 0 ); // true

Чистый PHP

Если вы хотите перейти от base62 к base85 или немного улучшить производительность, вам потребуется что-то вроде следующего.

<?php

/**
* Divide a large number represented as a binary string in the specified base
* and return the remainder.
* 
* @param string &$binary
* @param int $base
* @param int $start
*/
function divmod(&$binary, $base, $divisor, $start = 0)
{
    /** @var int $size */
    $size = strlen($binary);

    // Do long division from most to least significant byte, keep remainder.
    $remainder = 0;
    for ($i = $start; $i < $size; $i++) {
        // Get the byte value, 0-255 inclusive.
        $digit = ord($binary[$i]);

        // Shift the remainder left by base N bits, append the last byte.
        $temp = ($remainder * $base) + $digit;

        // Calculate the value for the current byte.
        $binary[$i] = chr($temp / $divisor);

        // Carry the remainder to the next byte.
        $remainder = $temp % $divisor;
    }

    return $remainder;
}

/**
* Produce a base62 encoded string from a large binary number.
* 
* @param string $binary
* return string
*/
function encodeBase62($binary)
{
    $charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $base = strlen($charMap);

    $size = strlen($binary);
    $start = $size - strlen(ltrim($binary, "\0"));

    $encoded = "";
    for ($i = $start; $i < $size; ) {
        // Do long division from most to least significant byte, keep remainder.
        $idx = divmod($binary, 256, $base, $i);

        $encoded = $charMap[$idx] . $encoded;

        if (ord($binary[$i]) == 0) {
            $i++; // Skip leading zeros produced by the long division.
        }
    }

    $encoded = str_pad($encoded, $start, "0", STR_PAD_LEFT);

    return $encoded;
}

/**
* Produce a large binary number from a base62 encoded string.
* 
* @param string $ascii
* return string
*/
function decodeBase62($ascii)
{
    $charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $base = strlen($charMap);

    $size = strlen($ascii);
    $start = $size - strlen(ltrim($ascii, "0"));

    // Convert the ascii representation to binary string.
    $binary = "";
    for ($i = $start; $i < $size; $i++) {
        $byte = strpos($charMap, $ascii[$i]);
        if ($byte === false) {
            throw new OutOfBoundsException("Invlaid encoding at offset '{$ascii[$i]}'");
        }

        $binary .= chr($byte);
    }

    $decode = "";
    for ($i = 0; $i < $size; ) {
        // Do long division from most to least significant byte, keep remainder.
        $idx = divmod($binary, $base, 256, $i);

        $decode = chr($idx) . $decode;

        if (ord($binary[$i]) == 0) {
            $i++; // Skip leading zeros produced by the long division.
        }
    }

    $decode = ltrim($decode, "\0");
    $decode = str_pad($decode, $start, "\0", STR_PAD_LEFT);

    return $decode;
}

// Not bits, bytes.
$data = openssl_random_pseudo_bytes(256);

$base62 = encodeBase62($data);
$decoded = decodeBase62($base62);

var_dump( strcmp($decoded, $data) === 0 ); // true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...