PHP: более короткое / скрытое кодирование для URL-адреса, встроенного в другой URL-адрес? - PullRequest
6 голосов
/ 28 сентября 2010

Я пишу сценарий, который позволяет отправлять URL и два целочисленных измерения в строке запроса одного запроса get. Я использую base64 для кодирования, но это чертовски долго, и я обеспокоен тем, что URL может стать слишком большим.

Кто-нибудь знает альтернативный, более короткий способ сделать это? Он должен быть декодируемым при получении в запросе get, поэтому md5 / sha1 невозможны.

Спасибо за ваше время.


Редактировать : Извините - я должен был объяснить лучше: Хорошо, на нашем сайте мы показываем скриншоты сайтов, которые публикуются для обзора. У нас есть собственный сервер с миниатюрами и скриншотами. Я собираюсь сделать так, чтобы тег image содержал закодированную строку, в которой хранится URL-адрес, на который нужно сделать снимок экрана, и ширину / высоту отображаемого изображения. Я не хочу, однако, чтобы это было в «сыром тексте», чтобы мир увидел. Очевидно, что base64 может быть решен кем угодно, но мы не хотим, чтобы ваш средний джо выбирал путь URL. На самом деле мне нужно получить: URL, ширина, высота в одном запросе GET.

Ответы [ 6 ]

5 голосов
/ 28 сентября 2010

Поскольку вы используете base64 только для запутывания строки, вы можете просто запутать ее чем-то другим, например, rot13 (или вашей собственной простой функцией замены букв).Таким образом, urlencode(str_rot13($str)) для кодирования и str_rot13(urldecode($str)) для декодирования.

Или, чтобы просто иметь более короткую строку в кодировке base64, вы можете сжать строку перед ее кодированием base64: base64_encode(gzencode($str, 9)) и gzdecode(base64_decode($str)) дляdecode.

Или, если это в первую очередь проблема безопасности (вы не против людей, которые видят URL, вы просто хотите, чтобы люди не взламывали его), вы можете передать эти параметры с помощью обычных переменных строки запроса, но сдобавлен хеш для предотвращения взлома.то есть:

function getHash($url, $width, $height) {
  $secret = 'abcdefghijklmnopqrstuvwxyz whatever you want etc.';
  return sha1($url . $width . $height . $secret);
}

// So use this hash to to construct your URL querystring:
$hash = getHash($url, $width, $height);
$urlQuerystring = '?url='.urlencode($url).'&width='.(int) $width.
                  '&height='.(int) $height.'&hash='.$hash;

// Then in your code that processes the URL, check the hash first
if ($hash != getHash($url, $width, $height))
  // URL is invalid

(Не по теме: люди говорят, что вы должны использовать POST вместо GET. Если все эти URL-адреса делают выборку скриншотов из вашей базы данных для отображения (то есть поиск в поиске), тогда GETЭто правильно и правильно. Но если вызов этих URL-адресов на самом деле выполняет действие, например, переход на другой сайт, создание и сохранение снимка экрана, то это POST. Как следует из их имен, GET предназначен для поиска, POST - для отправки данных.чтобы использовать GET в дорогостоящей операции, такой как создание снимка экрана, вы можете в конечном итоге сделать DOS на своем собственном сайте, когда Google и т. д. проиндексируют эти URL.)

3 голосов
/ 28 сентября 2010

URL не предназначены для отправки длинных строк данных, закодированных или не закодированных.После определенного момента, когда вы имеете дело с такими большими объемами данных, отправляемых через URL, вам следует просто начать использовать POST или какую-либо форму локального хранилища.К вашему сведению, IE имеет ограничение URL-адреса в 2038 символов.


РЕДАКТИРОВАТЬ: Я не понимаю одну вещь.Почему вы не кэшируете снимки экрана?Кажется ужасно ресурсоемким делать новый скриншот каждый раз, когда кто-то просматривает страницу с IMG-ссылкой на этот URL.

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

Как только веб-сайт будет опубликован, сохраните URL-адрес в каком-то локальном хранилище, предпочтительно в sql,Я собираюсь продолжить этот пример, как будто вы выбираете SQL, но, конечно, ваша реализация - ваш выбор.У меня будет первичный ключ, поле URL и отметка времени last_updated, а также, возможно, путь к уменьшенному изображению.

Используя локальное хранилище, вы теперь можете извлекать изображение из кэшированной копии, хранящейся локально на сервере каждый раз, когда запрашивается страница с миниатюрой.Сохраняется значительное количество ресурсов, и, поскольку есть вероятность, что эти сайты не будут обновляться очень часто, у вас может быть задание cron или сценарий, который запускается каждые x раз для обновления снимков экрана во всей базе данных.Теперь все, что вам нужно сделать, это напрямую связать (опять же, это зависит от вашей реализации) с изображением, и ничего из этого огромного URL-строки не произойдет.

ИЛИ, просто займите легкий путь и сделайте это на стороне клиентас http://www.snap.com/

2 голосов
/ 16 сентября 2011

Похоже, ваши цели: 1. до визуально скрыть URL , и 2. чтобы вообще кодировать данные компактно для использования в URL .

Во-первых, нам нужно скрыть URL. Поскольку URL-адреса используют большую часть словаря Base64, любая кодировка, создающая двоичный файл (который затем должен быть Base64-ed), вероятно, просто увеличит размер. Лучше всего держать словарь в безопасном для URL диапазоне с минимальной необходимостью экранирования при применении urlencode(). То есть Вы хотите это:

/**
 * Rot35 for URLs. To avoid increasing size during urlencode(), commonly encoded
 * chars are mapped to more rarely used chars (end of the uppercase alpha).
 *
 * @param string $url
 * @return string
 */
function rotUrl($url) {
    return strtr($url,
        'abcdefghijklmnopqrstuvwxyz0-:/?=&%#123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
        '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0-:/?=&%#');
}

Теперь, для сохранения байтов, мы можем закодировать схему URL в один символ (скажем, h для HTTP, H для HTTPS) и преобразовать измерения в основание 32. Подводя итог:

function obscure($width, $height, $url) {
    $dimensions = base_convert($width, 10, 32) . "."
                . base_convert($height, 10, 32) . ".";
    preg_match('@^(https?)://(.+)@', $url, $m);
    return $dimensions . (($m[1] === 'http') ? 'h' : 'H') . rotUrl($m[2]);
}

function unobscure($str) { /* exercise for the reader! */ }

$url = 'https://en.wikipedia.org/w/index.php?title=Special%3ASearch&search=Base64';
$obs = obscure(550, 300, $url);
// h6.9c.H5E.N9B9G5491.FI7UNU9E45O.G8GVK9KC5W-G5391CYcj-51I38XJ51I38Wk1J5fd

Поскольку мы избегали использования символов, не безопасных для URL, если они помещаются в строку запроса (с urlencode), она не сильно возрастает (в данном случае вовсе).

Кроме того, вы можете захотеть подписать эту строку, чтобы люди, которые знают кодировку, все еще не могли указать свои собственные параметры через URL. Для этого вы должны использовать HMAC и Base64URL-кодировать хэш. Вы также можете просто сохранить подстроку хеша (~ 6 бит на символ) для экономии места. sign() (ниже) добавляет 8-символьный MAC-адрес (48 бит хеш-функции при 6 битах / символ):

function sign($key, $data) {
    return $data . _hmac($key, $data, 8);
}
function verify($key, $signed) {
    $mac = substr($signed, -8);
    $data = substr($signed, 0, -8);
    return $mac === _hmac($key, $data, 8) ? $data : false;
}
function _hmac($key, $data, $macLength) {
    $mac = substr(base64_encode(hash_hmac('sha256', $data, $key, true)), 0, $macLength);
    return strtr($mac, '+/', '-_'); // for URL
}

$key = "Hello World!";
$signed = sign($key, $obs); // appends MAC: "w-jjw2Wm"

$obs = verify($key, $signed); // strips MAC and returns valid data, or FALSE

Обновление: улучшена Функция RotURL .

1 голос
/ 28 сентября 2010

Вы все еще можете использовать POST для того, что вы описываете, при условии, что я вас правильно понял, у меня может не быть.

Полагаю, вы делаете что-то вроде этого:

<a href="scripturl?w=11&h=100&url=really-long-secret-base64">
  <img src="imgurl">
</a>

вместо этого сделайте что-то вроде этого:

<form method="POST" action="scripturl">
  <input type="hidden" name="width" value="100">
  <input type="hidden" name="height" value="100">
  <input type="hidden" name="url" value="secret-url-string-here">
  <input type="image" src="imgurl" name="submit">
</form>
1 голос
/ 28 сентября 2010

Только не base64_encode($whole_file). Отправьте содержимое кусками и закодируйте куски . Кроме того, если вы должны знать, насколько большим может стать ваш чанк после вызова на base64_encode(), он увеличится более чем в два раза (но меньше 2.1*strlen($chunk))

0 голосов
/ 28 сентября 2010

Является ли скрипт, который генерирует URL-адреса, запущенные на сервере, отличным от скрипта, который их интерпретирует?Если они находятся на одном сервере, очевидным подходом было бы сохранить целевой URL, ширину и высоту в базе данных и просто передать случайно сгенерированный идентификатор записи в строке запроса.

...