我刚发现这个great tutorial,因为它是我需要的东西。
然而,看了之后,这似乎效率低下。它的工作方式是,首先生成一个唯一的密钥,然后检查它是否存在于数据库中以确保它确实是唯一的。但是,数据库越大,函数越慢,对吧?
相反,我在想,有没有办法为这个功能添加排序?所以必须要做的就是检查数据库中的上一个条目并增加密钥。所以它永远是独一无二的?
function generate_chars()
{
$num_chars = 4; //max length of random chars
$i = 0;
$my_keys = "123456789abcdefghijklmnopqrstuvwxyz"; //keys to be chosen from
$keys_length = strlen($my_keys);
$url = "";
while($i<$num_chars)
{
$rand_num = mt_rand(1, $keys_length-1);
$url .= $my_keys[$rand_num];
$i++;
}
return $url;
}
function isUnique($chars)
{
//check the uniqueness of the chars
global $link;
$q = "SELECT * FROM `urls` WHERE `unique_chars`='".$chars."'";
$r = mysql_query($q, $link);
//echo mysql_num_rows($r); die();
if( mysql_num_rows($r)>0 ):
return false;
else:
return true;
endif;
}
答案 0 :(得分:13)
微小的网址人们喜欢使用随机令牌,因为那样你就不能仅仅使用微小的网址链接。 “#2去哪了?” “哦,很酷!” “#3去哪了?” “更酷!”您可以键入随机字符,但不太可能达到有效值。
由于密钥相当稀疏(4个值各有36 *个可能性给你1,679,616个唯一值,5个给你60,466,176)碰撞的机会很小(实际上,它是设计的一个理想部分)和一个好的SQL索引将使查找变得微不足道(实际上,它是URL的主要查找,因此它们围绕它进行优化)。
如果你真的想避免查找并且只是不使用自动增量,你可以创建一个函数,将一个整数转换成一串看似随机的字符,并具有转换回来的能力。所以“1”变成“54jcdn”而“2”变成“pqmw21”。与Base64编码类似,但不使用连续字符。
(*)我实际上喜欢使用少于36个字符 - 单个字符,没有元音,没有类似字符(1,l,I)。这可以防止意外发誓,并且还可以让某人更容易向其他人说出价值。我甚至将相似的字符映射到彼此,接受“0”表示“O”。如果您完全基于机器,则可以使用大写和小写以及所有数字以获得更大的可能性。
答案 1 :(得分:9)
在数据库表中,unique_chars
字段上有一个索引,所以我不明白为什么会这么慢或效率低。
UNIQUE KEY `unique_chars` (`unique_chars`)
不要急于对你认为可能很慢的事情进行过早优化。
此外,网址缩短服务可能会产生一些好处,即生成随机网址而不是连续网址。
答案 2 :(得分:8)
我不知道为什么你会打扰。本教程的前提是创建一个“随机”URL。如果随机空间足够大,那么你可以简单地依靠纯粹,愚蠢的运气。如果随机字符空间为62个字符(A-Za-z0-9),则给定合理的随机数生成器时,它们使用的4个字符在62 ^ 4中为1,在14,776,336中为1。 916,132,832中有5个字符是1。因此,冲突实际上是“十亿分之一”。
显然,随着文件填写,你的赔率几率会增加。
有10,000个文件,91,613中有1个,近10个中有1个(圆形数字)。
这意味着,对于每个新文档,你有一个91,613的机会再次击中数据库再次拉动老虎机。
这不是确定性的。这是随机的。这很幸运。从理论上讲,你可以击中一串真的,真的,坏运气,碰撞后碰撞后碰撞。而且,它最终会填满。您计划散列多少个网址?
但是,如果91,613赔率中的1分不够好,将它提升到6个字符会使得它在10,000个文档中超过5分钟。我们这里谈的几乎是LOTTO赔率。
简单地说,让密钥足够大(7个字符?8?),问题几乎“希望”自己不存在。
答案 3 :(得分:3)
无法在生成URL时将URL编码为Base36,然后在访问时对其进行解码 - 这样可以完全删除数据库吗?
Channel9的摘录:
公式很简单,只需转动即可 我们的帖子的条目ID,这是一个很长的 由Base-36编成一个短串 编码然后坚持 “http://ch9.ms/”就在它前面。 这会产生相当短的网址, 并且可以在任何一端计算 无需任何数据库外观 起来。结果,一个URL就好了 然后使用http://ch9.ms/A49H 创建推特链接。
答案 4 :(得分:2)
我通过实现一个用于在 base36 中逐个生成序列号的alogirthm解决了类似的问题。我有自己的 oredring of base36 characters 所有这些都是独一无二的。由于它是连续生成数字,我不必担心重复。数字的复杂性和随机性取决于base36数字[字符]的排序......对于公众而言,这也只是因为我的应用程序它们是序列号:)
答案 5 :(得分:2)
查看这些人的功能 - http://www.pgregg.com/projects/php/base_conversion/base_conversion.php来源 - http://www.pgregg.com/projects/php/base_conversion/base_conversion.inc.phps
您可以使用任何您喜欢的基础,例如将554512转换为基础62,调用
$tiny = base_base2base(554512, 10, 62);
,评估为$tiny = '2KFk'
。
因此,只需传入数据库记录的唯一ID即可。
在一个项目中,我在$sChars
字符串中删除了几个字符时使用了这个字符,并使用了基数58.如果您希望值不易猜测,也可以重新排列字符串中的字符
答案 6 :(得分:1)
您当然可以通过简单地为网址编号来添加排序:
http://mytinyfier.com/1
http://mytinyfier.com/2
等等。但是如果哈希键在数据库中被索引(显然应该是这样),性能提升最多也是最小的。
答案 7 :(得分:1)
我不打算做有序枚举,原因有两个:
1)SQL服务器在检查此类哈希冲突(给定正确的索引)时非常有效
2)这可能会损害隐私,因为用户可以轻松找出其他用户的微观内容。
答案 8 :(得分:0)
这可能有效,但解决问题的最简单方法可能是哈希。从理论上讲,散列运行在O(1)时间内,因为它只需要执行散列,然后只对数据库执行一次实际命中以检索值。然后,您将引入检查哈希冲突的复杂性,但似乎这可能是大多数微型提供商所做的。并且,一个好的哈希函数并不是很难写。
答案 9 :(得分:0)
在数据库上使用自动增量,并按http://www.acuras.co.uk/articles/24-php-use-mysqlinsertid-to-get-the-last-entered-auto-increment-value
所述获取最新的ID答案 10 :(得分:0)
也许这有点无法回答,但是,我创建始终唯一键的一般规则是简单的md5(time()* 100 + rand(0,100));如果两个人在同一秒内使用相同的服务,他们将获得相同的结果(不可能),有十分之一的机会。
那就是说,md5(rand(0,n))也可以。
答案 11 :(得分:0)
我还创建了小型的tinyurl服务。
我在Python中编写了一个脚本,该脚本生成密钥并存储在名为tokens的MySQL表中,状态为U(未使用)。
但是,我是在离线模式下进行的。我的VPS上有玉米工作。它每10分钟运行一次脚本。脚本检查表中是否有少于1000个键,如果它们是唯一的并且在表中不存在,它会继续生成键并插入它们,直到键计数到1000为止。
对于我的服务,10分钟的1000个密钥绰绰有余,您可以根据需要设置生成密钥的时间或数量。
现在,当我的网站上需要创建任何小网址时,我的PHP脚本只需获取表中未使用的任何密钥,并将其状态标记为T(已采用)。 PHP脚本不必担心其独特性,因为我的python脚本只填充了唯一键。
答案 12 :(得分:-1)
难道你不能把哈希修剪到你想要的长度吗?
$tinyURL = substr(md5($longURL . time()),0,4);
当然,这可能无法提供与使用整个字符串长度一样多的伪随机性。但是,如果您对与time()
连接的长URL进行哈希处理,这不足够吗?关于使用这种方法的想法?谢谢!