Я шукаю функцію PHP, яка створює короткий хеш із рядка або файлу, подібну до тих веб-сайтів, що скорочують URL-адреси, таких як tinyurl.com
Хеш не повинен перевищувати 8 символів.
Я шукаю функцію PHP, яка створює короткий хеш із рядка або файлу, подібну до тих веб-сайтів, що скорочують URL-адреси, таких як tinyurl.com
Хеш не повинен перевищувати 8 символів.
Alphabet::convert($hash, Alphabet::HEX, Alphabet::ALPHANUMERIC)
ви можете отримати MD5 до 22 (з 32) символів. Натомість потрібно кодувати цілі ідентифікатори файлів (наприклад, з вашої бази даних) за допомогою (new Id())->encode($id)
.
Відповіді:
Служби скорочення URL-адрес, скоріше, використовують автоматично збільшене ціле значення (наприклад, додатковий ідентифікатор бази даних) і кодують це за допомогою Base64 або інших кодувань, щоб мати більше інформації на символ (64 замість лише 10, як цифри).
0
- 9
для представлення числа, у вас є 10 можливих значень на кодований символ (ld (10) ≈ 3,32 біта / символ). Однак, якщо ви представляєте одне і те ж число з символами Base64, у вас буде 64 можливих значення на кодований символ (ld (64) = 6 біт / символ). Отже, у Base64 більше інформації зберігається в кодованому символі, тобто 6 бітів інформації замість 3,32 біта.
TinyURL нічого не хеш, він використовує цілі числа Base 36 (або навіть base 62, використовуючи малі та великі літери), щоб вказати, який запис відвідати.
База 36 до цілого числа:
intval($str, 36);
Ціле до бази 36:
base_convert($val, 10, 36);
Тоді, замість того, щоб перенаправляти на такий маршрут, яким /url/1234
він стає /url/ax
натомість. Це дає вам набагато більше користі, ніж хеш, оскільки зіткнень не буде. За допомогою цього ви можете легко перевірити, чи існує URL-адреса, і повернути правильний, існуючий ідентифікатор в базі 36, не знаючи, що користувач вже був у базі даних.
Не хеш, використовуйте інші основи для такого роду речей. (Це швидше, і його можна зробити стійким до зіткнень.)
intval()
перетворює все на число. Я думаю, можливо, я збентежений тим, як intval()
зв’язується з іншими кроками, необхідними для перенаправлення, як роль бази даних.
intval()
, чи є у вас $str
похилі риски (/) або тире (-). Я зрозумів це on/stuff
, on-stuff
і on
всі повернули номер 887
. Ви маєте на увазі рішення для роботи з URL-адресами, де в них є коса риса?
Я написав крихітну бібліотеку, щоб генерувати незрозумілі хеші з цілих чисел.
http://web.archive.org/web/20130727034425/http://blog.kevburnsjr.com/php-unique-hash
$ids = range(1,10);
foreach($ids as $id) {
echo PseudoCrypt::unhash($id) . "\n";
}
m8z2p 8hy5e uqx83 gzwas 38vdh phug6 bqtiv xzslk k8ro9 6hqqy
14.07.2015: Додавання фактичного коду нижче, оскільки його важко знайти:
<?php
/**
* PseudoCrypt by KevBurns (http://blog.kevburnsjr.com/php-unique-hash)
* Reference/source: http://stackoverflow.com/a/1464155/933782
*
* I want a short alphanumeric hash that’s unique and who’s sequence is difficult to deduce.
* I could run it out to md5 and trim the first n chars but that’s not going to be very unique.
* Storing a truncated checksum in a unique field means that the frequency of collisions will increase
* geometrically as the number of unique keys for a base 62 encoded integer approaches 62^n.
* I’d rather do it right than code myself a timebomb. So I came up with this.
*
* Sample Code:
*
* echo "<pre>";
* foreach(range(1, 10) as $n) {
* echo $n." - ";
* $hash = PseudoCrypt::hash($n, 6);
* echo $hash." - ";
* echo PseudoCrypt::unhash($hash)."<br/>";
* }
*
* Sample Results:
* 1 - cJinsP - 1
* 2 - EdRbko - 2
* 3 - qxAPdD - 3
* 4 - TGtDVc - 4
* 5 - 5ac1O1 - 5
* 6 - huKpGQ - 6
* 7 - KE3d8p - 7
* 8 - wXmR1E - 8
* 9 - YrVEtd - 9
* 10 - BBE2m2 - 10
*/
class PseudoCrypt {
/* Key: Next prime greater than 62 ^ n / 1.618033988749894848 */
/* Value: modular multiplicative inverse */
private static $golden_primes = array(
'1' => '1',
'41' => '59',
'2377' => '1677',
'147299' => '187507',
'9132313' => '5952585',
'566201239' => '643566407',
'35104476161' => '22071637057',
'2176477521929' => '294289236153',
'134941606358731' => '88879354792675',
'8366379594239857' => '7275288500431249',
'518715534842869223' => '280042546585394647'
);
/* Ascii : 0 9, A Z, a z */
/* $chars = array_merge(range(48,57), range(65,90), range(97,122)) */
private static $chars62 = array(
0=>48,1=>49,2=>50,3=>51,4=>52,5=>53,6=>54,7=>55,8=>56,9=>57,10=>65,
11=>66,12=>67,13=>68,14=>69,15=>70,16=>71,17=>72,18=>73,19=>74,20=>75,
21=>76,22=>77,23=>78,24=>79,25=>80,26=>81,27=>82,28=>83,29=>84,30=>85,
31=>86,32=>87,33=>88,34=>89,35=>90,36=>97,37=>98,38=>99,39=>100,40=>101,
41=>102,42=>103,43=>104,44=>105,45=>106,46=>107,47=>108,48=>109,49=>110,
50=>111,51=>112,52=>113,53=>114,54=>115,55=>116,56=>117,57=>118,58=>119,
59=>120,60=>121,61=>122
);
public static function base62($int) {
$key = "";
while(bccomp($int, 0) > 0) {
$mod = bcmod($int, 62);
$key .= chr(self::$chars62[$mod]);
$int = bcdiv($int, 62);
}
return strrev($key);
}
public static function hash($num, $len = 5) {
$ceil = bcpow(62, $len);
$primes = array_keys(self::$golden_primes);
$prime = $primes[$len];
$dec = bcmod(bcmul($num, $prime), $ceil);
$hash = self::base62($dec);
return str_pad($hash, $len, "0", STR_PAD_LEFT);
}
public static function unbase62($key) {
$int = 0;
foreach(str_split(strrev($key)) as $i => $char) {
$dec = array_search(ord($char), self::$chars62);
$int = bcadd(bcmul($dec, bcpow(62, $i)), $int);
}
return $int;
}
public static function unhash($hash) {
$len = strlen($hash);
$ceil = bcpow(62, $len);
$mmiprimes = array_values(self::$golden_primes);
$mmi = $mmiprimes[$len];
$num = self::unbase62($hash);
$dec = bcmod(bcmul($num, $mmi), $ceil);
return $dec;
}
}
Найкоротший хеш - це довжина 32 символи, однак ви можете використовувати перші 8 символів хешу md5
echo substr(md5('http://www.google.com'), 0, 8);
Оновлення : ось ще один клас, знайдений тут, написаний Travell Perkins, який бере номер запису та створює для нього короткий хеш. 14-значне число утворює 8-значний рядок. На момент досягнення цього числа ви стаєте популярнішим за tinyurl;)
class BaseIntEncoder {
//const $codeset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
//readable character set excluded (0,O,1,l)
const codeset = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ";
static function encode($n){
$base = strlen(self::codeset);
$converted = '';
while ($n > 0) {
$converted = substr(self::codeset, bcmod($n,$base), 1) . $converted;
$n = self::bcFloor(bcdiv($n, $base));
}
return $converted ;
}
static function decode($code){
$base = strlen(self::codeset);
$c = '0';
for ($i = strlen($code); $i; $i--) {
$c = bcadd($c,bcmul(strpos(self::codeset, substr($code, (-1 * ( $i - strlen($code) )),1))
,bcpow($base,$i-1)));
}
return bcmul($c, 1, 0);
}
static private function bcFloor($x)
{
return bcmul($x, '1', 0);
}
static private function bcCeil($x)
{
$floor = bcFloor($x);
return bcadd($floor, ceil(bcsub($x, $floor)));
}
static private function bcRound($x)
{
$floor = bcFloor($x);
return bcadd($floor, round(bcsub($x, $floor)));
}
}
ось приклад, як ним користуватися:
BaseIntEncoder::encode('1122344523');//result:3IcjVE
BaseIntEncoder::decode('3IcjVE');//result:1122344523
const codeset
може бути в будь-якому довільному порядку, просто щоб
Для короткого хешу , зручного для URL-адреси , з метою заборони можливого повторення вмісту, ми можемо використовувати, hash()
особливо тип хешу CRC , оскільки він створений саме для цього:
Циклічна перевірка надмірності
Циклічна перевірка надмірності (CRC) - це код виявлення помилок, який зазвичай використовується в цифрових мережах та пристроях зберігання даних для виявлення випадкових змін необроблених даних. Блоки даних, що надходять у ці системи, отримують коротке контрольне значення, додане на основі залишку поліноміального поділу їх вмісту. Після отримання обчислення повторюється, і якщо контрольні значення не збігаються, можна вжити коригувальних дій
echo hash("crc32", "Content of article...");
// Output fd3e7c6e
І все-таки найкраща відповідь: найменший унікальний рядок "Hash Like" з урахуванням унікального ідентифікатора бази даних - рішення PHP, не потрібні сторонні бібліотеки.
Ось код:
<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of $database_id maps to $base36value\n";
// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
//DebugBreak();
global $error;
$string = null;
$base = (int)$base;
if ($base < 2 | $base > 36 | $base == 10) {
echo 'BASE must be in the range 2-9 or 11-36';
exit;
} // if
// maximum character string is 36 characters
$charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// strip off excess characters (anything beyond $base)
$charset = substr($charset, 0, $base);
if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
$error['dec_input'] = 'Value must be a positive integer with < 50 digits';
return false;
} // if
do {
// get remainder after dividing by BASE
$remainder = bcmod($decimal, $base);
$char = substr($charset, $remainder, 1); // get CHAR from array
$string = "$char$string"; // prepend to output
//$decimal = ($decimal - $remainder) / $base;
$decimal = bcdiv(bcsub($decimal, $remainder), $base);
} while ($decimal > 0);
return $string;
}
?>
Насправді найкращим рішенням для "випадкового" хешу є створення списку випадкових хешів, розміщення його на Mysql з унікальним ІНДЕКСОМ (ви можете написати простий UDF, щоб вставити 100 000 рядків за 1 секунду).
Я думаю, що така структура, як цей | HASH | СТАТУС | URL | ПЕРЕГЛЯДИ | ......
Де статус вказує, безкоштовний цей Хеш чи ні.
Простий спосіб перевірки дублікатів у базі даних:
$unique = false;
// While will be repeated until we get unique hash
while($unique == false) {
// Getting full hash based on random numbers
$full_hash = base64_encode( rand(9999,999999) );
// Taking only first 8 symbols
$hash = substr($full_hash, 0, 8);
// Checking for duplicate in Database - Laravel SQL syntax
$duplicate = \App\Item::where('url', $hash)->count();
// If no Duplicate, setting Hash as unique
if ($duplicate==0) {
// For stoping while
$unique=true;
// New Hash is confirmed as unique
$input['url']=$hash;
}
}
Я робив скорочувач URL-адрес. У моєму випадку я використовував "ідентифікатор" бази даних, щоб створювати кожен раз унікальну коротку URL-адресу.
Що я зробив, це, по-перше -
Вставте такі дані, як "Оригінальна URL-адреса" та "Дата створення", в db, залишивши "коротку URL-адресу" порожньою в db. Потім дістаньте "id" звідти та передайте функцію нижче.
<?php
function genUniqueCode($id){
$id = $id + 100000000000;
return base_convert($id, 10, 36);
}
//Get Unique Code using ID
/*
id Below is retrived from Database after Inserting Original URL.
*/
$data['id'] =10;
$uniqueCode = genUniqueCode($data['id']);
// Generating the URL
$protocol = strtolower(substr($_SERVER["SERVER_PROTOCOL"],0,5))=='https'?'https':'http';
echo "<a href='{$protocol}://{$_SERVER['HTTP_HOST']}/{$uniqueCode}'>{$protocol}://{$_SERVER['HTTP_HOST']}/{$uniqueCode}</a>";
?>
А потім ОНОВИТИ значення короткого url-коду в базі даних.
Тут я використовую "id" для створення короткого коду. Оскільки ідентифікатор не може бути однаковим для декількох записів. Це унікально, отже, унікальний код або URL-адреса буде унікальним.