2009-10-30 39 views
7

Tôi muốn tạo một ID ngắn, duy nhất mà không phải kiểm tra các xung đột.Tạo ID duy nhất ngắn PHP bằng cách sử dụng auto_increment?

Tôi hiện đang làm một cái gì đó như thế này, nhưng ID tôi hiện tạo là ngẫu nhiên và kiểm tra va chạm trong vòng lặp là gây phiền nhiễu và sẽ tốn kém nếu số lượng bản ghi tăng lên đáng kể.

Thông thường đáng lo ngại về sự va chạm không phải là vấn đề, nhưng ID duy nhất tôi muốn tạo là một chuỗi ngắn 5-8 ký tự, số alpha, giống như tinyurl.

EDIT: Tôi muốn bắt đầu với 5 ký tự và nếu tôi đạt 60 triệu mục nhập, sau đó chuyển đến 6 .. v.v.

Để kết thúc này, tôi đã nghĩ rằng tôi có thể sử dụng giá trị auto_increment bị ẩn khỏi người dùng và hiển thị chúng thay thế bằng MD5 hoặc một số phương pháp khác để tạo chuỗi duy nhất từ ​​đó.

Chuỗi được tạo có vẻ không tuyến tính, vì vậy chỉ cần chuyển đổi ID tự động thành base 36 [0-9A-Z] hơi đơn giản, nhưng một chức năng giống như vậy là tôi sẽ làm điều này.

EDIT: Bảo mật không phải là vấn đề vì điều này sẽ không được sử dụng để bảo mật thông tin. Nó chỉ đơn giản là một phím tắt cho một chuỗi dài hơn. Cảm ơn bạn.

Cảm ơn bạn đã đề xuất và xin lỗi vì sự chậm trễ. Nha sĩ ..

Trả lời

6

Bạn sẽ cần thứ gì đó đúng bằng cách xây dựng, tức là hàm hoán vị: đây là hàm thực hiện -to-one, ánh xạ đảo ngược của một số nguyên (bộ đếm tuần tự) của bạn cho một số nguyên khác. Một số ví dụ (bất kỳ sự kết hợp của những cũng nên làm việc):

  • đảo ngược một số bit (fi sử dụng một XOR,^trong PHP)
  • trao đổi những nơi bit (($ i & 0xc)> > 2 | ($ i & 0x3) < < 2) hoặc chỉ đảo ngược thứ tự của tất cả các bit
  • thêm giá trị không đổi modulo phạm vi tối đa của bạn (phải là hệ số hai, nếu bạn kết hợp điều này với ở trên)

Ví dụ: chức năng này sẽ chuyển đổi 0, 1, 2, 3, 5, .. vào 13, 4, 12, 7, 15, .. cho số lên đến 15:

$i=($input+97) & 0xf; 
$result=((($i&0x1) << 3) + (($i&0xe) >> 1))^0x5; 

EDIT

một cách dễ dàng hơn sẽ sử dụng một máy phát điện congruential tuyến tính (LCG, mà thường được sử dụng để tạo ra các số ngẫu nhiên), được xác định bởi một công thức có dạng:

X_n+1 = (a * X_n + c) mod m 

đối good values của a, c và m , chuỗi X_0, X_1 .. X_m-1 sẽ chứa al l số giữa 0 và m-1 chính xác một lần. Bây giờ bạn có thể bắt đầu từ chỉ mục tăng tuyến tính và sử dụng giá trị tiếp theo trong chuỗi LCG làm khóa "bí mật" của bạn.

EDIT2

Thực hiện: Bạn có thể design your own LCG parameters, nhưng nếu bạn nhận được nó sai nó sẽ không bao gồm đầy đủ (và do đó có bản sao) vì vậy tôi sẽ sử dụng một công bố và đã cố gắng thiết lập các thông số ở đây từ this paper:

a = 16807, c = 0, m = 2147483647 

Điều này cung cấp cho bạn phạm vi 2 ** 31. Với gói(), bạn có thể nhận được số nguyên kết quả như là một chuỗi, base64_encode() làm cho nó một chuỗi có thể đọc được (lên đến 6 nhân vật quan trọng, 6 bit mỗi byte) vì vậy đây có thể là chức năng của bạn:

substr(base64_encode(pack("l", (16807 * $index) % 2147483647)), 0, 6) 
+0

Tôi thích ý tưởng này. Có một số mã cho tôi? 1-60000000 ánh xạ tới một chuỗi số 5 ký tự alpha? –

+0

Xin lỗi tôi không tin tưởng toán học của tôi tại thời điểm này trong ngày vì vậy nó là một 31-bit. Đối với một 30-bit, bạn sẽ có chính xác 5 (đáng kể, tức là không có padding = 's) ký tự sau base64_encode nhưng tôi không thể tìm thấy một tham số thiết lập cho điều đó. – Wim

+0

Tôi nghĩ rằng điều này có thể làm việc cho một cái 30-bit: a = 357913942, c = 1, m = 1073741823 (Nếu tôi không nhầm, nó đáp ứng các tiêu chí trong bài viết Wikipedia để nó có đầy đủ khoảng thời gian: m = 2 ** 31-1 = 3 ** 2 * 7 * 11 * 31 * 151 * 331, c = 1 vì vậy rõ ràng là trùng với m và a-1 = 3 * 7 * 11 * 31 * 151 * 331 là chia hết cho tất cả các yếu tố chính của m ...) – Wim

0

Tôi nghĩ điều này sẽ không bao giờ thực sự an toàn vì bạn chỉ cần tìm phương pháp mã hóa đằng sau chuỗi ngắn duy nhất để chiếm đoạt ID. Kiểm tra va chạm trong một vòng lặp thực sự có vấn đề trong cài đặt của bạn?

+0

Không phải bây giờ, nhưng tại 50 triệu liên kết và 5 ký tự, khoảng 80% trở thành va chạm. –

-1

Một MD5 của số gia tăng sẽ ổn, nhưng tôi lo rằng nếu bạn cắt ngắn MD5 (thường là 128 bit) xuống còn 5-8 ký tự, bạn gần như chắc chắn sẽ làm hỏng khả năng hoạt động của nó một chữ ký duy nhất ...

+0

MD5 (hoặc bất kỳ băm cho vấn đề đó) không bao giờ có thể hoạt động như một chữ ký duy nhất. Vì vậy, mối quan tâm trunication của bạn là một chút tranh luận. –

+0

Hash's được sử dụng như là chữ ký tất cả các thời gian ... – dicroce

+0

Tôi không chắc chắn làm thế nào mà phủ nhận phản ứng của tôi. Mọi người làm những thứ ngu ngốc mọi lúc, điều đó không làm cho băm trở nên "độc đáo" một cách kỳ diệu. –

1

Bạn có thể tạo một số băm MD5 của số ngày giờ/số ngẫu nhiên hiện tại và cắt ngắn nó thành độ dài bạn cần (5-8 ký tự) và lưu nó làm trường id.

Nếu bạn đang sử dụng lưu trữ thông tin này trong một cơ sở dữ liệu, bạn không cần phải sử dụng một vòng lặp for để làm việc kiểm tra va chạm, nhưng bạn chỉ có thể làm một tuyên bố chọn - một cái gì đó giống như

SELECT count(1) c FROM Table WHERE id = :id 

nơi : id sẽ là id mới được tạo. Nếu c lớn hơn 0 thì bạn biết nó đã tồn tại.

EDIT

Điều này có thể có thể không phải là cách tốt nhất để đi về nó. Nhưng tôi sẽ cung cấp cho nó một shot, vì vậy tôi đoán những gì bạn cần là một cách nào đó của việc chuyển đổi một số thành một chuỗi ngắn duy nhất và đó không phải là theo thứ tự.

Tôi đoán như bạn đã nói, mã hóa base64 đã thực hiện số để chuyển đổi chuỗi ngắn. Để tránh sự cố trình tự, bạn có thể có một số ánh xạ giữa id được tạo tự động của bạn với một số giá trị "ngẫu nhiên" (ánh xạ duy nhất). Sau đó, bạn có thể mã hóa base64 giá trị duy nhất này.

Bạn có thể tạo ánh xạ này như sau. Có giá trị lưu trữ bảng tạm thời từ 1 - 10.000.000. Sắp xếp nó theo thứ tự ngẫu nhiên và lưu nó vào bảng Map của bạn.

INSERT INTO MappingTable (mappedId) SELECT values FROM TemporaryTable ORDER BY RAND() 

Trường hợp MappingTable sẽ có 2 trường id (id được tạo tự động của bạn sẽ tra cứu) và ánh xạId (đó là thứ bạn sẽ tạo mã hóa base64).

Khi bạn đến gần hơn 10.000.000 bạn có thể chạy lại mã trên và thay đổi các giá trị trong bảng tạm thời với 10.000.001-20.000.000 hoặc một cái gì đó tương tự.

+0

Vòng lặp bắt nguồn để tạo ra một id duy nhất nếu tôi thất bại. Tôi biết điều này về việc tối ưu hóa sớm, nhưng tôi hy vọng có một cách tốt hơn. –

0

Một MD5 của một số incrementing nên được tốt, nhưng tôi lo lắng rằng nếu bạn đang cắt xén MD5 của bạn (đó là thường 128 bit) xuống 5-8 ký tự, bạn sẽ gần như chắc chắn làm tổn hại đến khả năng hoạt động của nó là một chữ ký duy nhất ...

Hoàn toàn đúng. Đặc biệt là nếu bạn đạt đến cơ hội va chạm 80%, MD5 bị cắt ngắn sẽ tốt bằng bất kỳ số ngẫu nhiên nào để đảm bảo tính độc đáo của chính nó, tức là vô giá trị.

Nhưng vì bạn đang sử dụng cơ sở dữ liệu, tại sao không chỉ sử dụng một INDI UNIQUE? Bằng cách này, việc kiểm tra tính duy nhất được thực hiện (một cách hiệu quả hơn nhiều so với việc sử dụng một vòng lặp) bởi chính MySQL. Chỉ cần cố gắng thực hiện INSERT bằng khóa được tạo MD5 của bạn và nếu không thành công, hãy thử lại ...

+0

Đúng, nhưng tôi vẫn còn lại để tính lại ngẫu nhiên và thử lại phần chèn. Đó là những gì tôi làm bây giờ. Tôi đang tìm kiếm một cách để tự động đảm bảo rằng tôi là duy nhất trong lần thử đầu tiên. Phương pháp cơ sở 36 sẽ làm điều này trong lần thử đầu tiên, nhưng liên kết đầu tiên sẽ là 00000, giây thứ hai 00001 và tiếp tục như vậy. –

+0

Có lẽ một lời bình luận bạn trích dẫn là theo thứ tự? :) – dicroce

+0

Chắc chắn, một khi tôi có đủ danh tiếng ...;) – Wim

1

bạn có thể sử dụng một Bitwise XOR để tranh giành một số bit:

select thefield^377 from thetable; 

+-----+---------+ 
| a | a^377 | 
+-----+---------+ 
| 154 |  483 | 
| 152 |  481 | 
| 69 |  316 | 
| 35 |  346 | 
| 72 |  305 | 
| 139 |  498 | 
| 96 |  281 | 
| 31 |  358 | 
| 11 |  370 | 
| 127 |  262 | 
+-----+---------+ 
+0

Có, điều đó dường như cũng hoạt động. –

0

Nếu bạn không thể sử dụng một lĩnh vực tự động tăng, và muốn có một giá trị hoàn toàn độc đáo, sử dụng UUID. Nếu bạn quyết định sử dụng bất cứ điều gì khác (ngoài tăng tự động), bạn sẽ là ngớ ngẩn để KHÔNG kiểm tra va chạm.

Các vấn đề liên quan