سؤال

أرغب في إنشاء معرف قصير وفريد ​​دون الحاجة إلى التحقق من التصادمات.

أقوم حاليًا بشيء من هذا القبيل، لكن المعرف الذي أقوم بإنشائه حاليًا عشوائي والتحقق من التصادمات في الحلقة أمر مزعج وسيصبح مكلفًا إذا زاد عدد السجلات بشكل ملحوظ.

عادةً لا يمثل القلق بشأن الاصطدامات مشكلة، ولكن المعرف الفريد الذي أرغب في إنشائه هو سلسلة فريدة قصيرة مكونة من 5 إلى 8 أحرف، أبجدية رقمية، كما يفعل tinyurl.

يحرر:أود أن أبدأ بـ 5 أحرف وإذا وصلت إلى 60 مليون إدخال، فانتقل إلى 6..هكذا وهكذا دواليك.

ولتحقيق هذه الغاية، كنت أفكر في أنه يمكنني استخدام قيمة زيادة تلقائية مخفية عن المستخدمين، وتقديمها لهم بدلاً من ذلك MD5 أو طريقة أخرى لإنشاء سلسلة فريدة من ذلك.

لا ينبغي أن تبدو السلاسل التي تم إنشاؤها خطية، لذا قم ببساطة بتحويل المعرف الذي تمت زيادته تلقائيًا إلى base 36 [0-9A-Z] هو أمر مبسط بعض الشيء، ولكن وظيفة كهذه هي ما سأذهب إليه.

يحرر:الأمن ليس مشكلة لأنه لن يتم استخدامه لتأمين المعلومات.إنه ببساطة اختصار لسلسلة أطول.شكرًا لك.

أشكركم على اقتراحاتكم وآسف على التأخير.طبيب أسنان..

هل كانت مفيدة؟

المحلول

ستحتاج إلى شيء صحيح من خلال البناء، أي.وظيفة التقليب:هذه هي الوظيفة التي تقوم بتعيين واحد لواحد وقابل للعكس لعدد صحيح واحد (العداد المتسلسل الخاص بك) إلى آخر.بعض الأمثلة (أي مجموعة من هذه يجب أن تعمل أيضًا):

  • قلب بعض البتات (f.i.باستخدام XOR، ^ في PHP)
  • تبديل أماكن البتات (($i & 0xc) >> 2 | ($i & 0x3) << 2)، أو مجرد عكس ترتيب جميع البتات
  • إضافة قيمة ثابتة modulo لنطاقك الأقصى (يجب أن يكون عاملًا اثنين، إذا كنت تجمع هذا مع ما سبق)

مثال:ستقوم هذه الدالة بتحويل 0، 1، 2، 3، 5، ..إلى 13، 4، 12، 7، 15، ..للأعداد حتى 15:

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

يحرر

الطريقة الأسهل هي استخدام مولد التطابق الخطي (LCG، والذي يستخدم عادة لتوليد أرقام عشوائية)، والذي يتم تعريفه بصيغة من النموذج:

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

ل القيم الجيدة من a، c و m، تسلسل X_0، X_1 ..سيحتوي X_m-1 على جميع الأرقام بين 0 وm-1 مرة واحدة بالضبط.يمكنك الآن البدء من فهرس متزايد خطيًا واستخدام التالي القيمة في تسلسل الواقيات الأساسية لإنقاذ الحياة كمفتاحك "السري".

تحرير2

تطبيق:أنت تستطيع تصميم معلمات الواقيات الأساسية لإنقاذ الحياة الخاصة بك, ، ولكن إذا أخطأت في ذلك، فلن يغطي النطاق الكامل (وبالتالي يكون هناك نسخ مكررة) لذا سأستخدم مجموعة من المعلمات المنشورة والمجربة هنا من هذه الورقة:

a = 16807, c = 0, m = 2147483647

يمنحك هذا نطاقًا قدره 2**31.باستخدام pack() يمكنك الحصول على العدد الصحيح الناتج كسلسلة، وbase64_encode() يجعلها سلسلة قابلة للقراءة (تصل إلى 6 أحرف مهمة، 6 بت لكل بايت) لذلك يمكن أن تكون هذه وظيفتك:

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

نصائح أخرى

ربما يمكنك إنشاء تجزئة MD5 للتاريخ/الرقم العشوائي الحالي واقتطاعه إلى الطول الذي تحتاجه (5-8 أحرف) وتخزينه كحقل معرف.

إذا كنت تستخدم تخزين هذه المعلومات في قاعدة بيانات، فلن تحتاج إلى استخدام حلقة for لإجراء التحقق من التصادم، ولكن يمكنك فقط إجراء عبارة تحديد - شيء من هذا القبيل

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

حيث :id سيكون المعرف الذي تم إنشاؤه حديثًا.إذا كان c أكبر من 0 فأنت تعلم أنه موجود بالفعل.

يحرر

قد لا تكون هذه هي أفضل طريقة للقيام بذلك.لكنني سأجربها، لذا أعتقد أن ما تحتاجه هو بطريقة ما تحويل الأرقام إلى سلسلة قصيرة فريدة وليست متسلسلة.

أعتقد كما قلت، أن ترميز base64 يقوم بالفعل بتحويل الرقم إلى سلسلة قصيرة.لتجنب مشكلة التسلسل، يمكن أن يكون لديك بعض التعيينات بين المعرفات التي تم إنشاؤها تلقائيًا وبعض القيم "العشوائية" (تعيين فريد).ثم يمكنك تشفير base64 لهذه القيمة الفريدة.

يمكنك إنشاء هذا التعيين على النحو التالي.لديك جدول مؤقت يخزن القيم من 1 - 10,000,000.قم بفرزها بترتيب عشوائي وتخزينها في جدول الخريطة.

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

حيث سيكون لدى MappingTable معرف الحقلين (سيبحث المعرف الذي تم إنشاؤه تلقائيًا مقابل هذا) وmappedId (وهو ما ستقوم بإنشاء ترميز base64 له).

عندما تقترب من 10,000,000، يمكنك إعادة تشغيل الكود أعلاه مرة أخرى وتغيير القيم في الجدول المؤقت باستخدام 10,000,001-20,000,000 أو شيء من هذا القبيل.

ويمكنك استخدام أحادي المعامل XOR ليتبارى بعض البتات:

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 |
+-----+---------+

وأعتقد أن هذا لن يكون آمنا حقا، وتحتاج فقط إلى العثور على طريقة التشفير وراء سلسلة فريدة قصيرة لخطف ID. والتحقق من وجود تصادم في حلقة حقا أن إشكالية في الإعداد؟

<اقتباس فقرة>   

وهناك MD5 من عدد تزايد   يجب أن يكون على ما يرام، ولكن أخشى أنه إذا   كنت اقتطاع MD5 الخاص بك (والذي هو   عادة 128 بت) وصولا الى 5-8   الشخصيات، وسوف يكاد يكون من المؤكد   يتم إتلاف انها القدرة على القيام بدور   توقيع فريد من نوعه ...

وصحيح تماما. خصوصا إذا وصلت بك 80٪ الاصطدام فرصة سوف MD5 اقتطاع تكون جيدة مثل أي رقم عشوائي لضمان التفرد في حد ذاته، أي لا قيمة لها.

ولكن منذ كنت تستخدم قاعدة بيانات على أي حال، لماذا لا مجرد استخدام INDEX فريد؟ بهذه الطريقة يتم فحص uniquness (بطريقة أكثر كفاءة بكثير من استخدام حلقة) من قبل الخلية نفسها. مجرد محاولة للقيام INSERT مع مفتاح ولدت MD5 الخاص بك، واذا فشلت، حاول مرة أخرى ...

إذا لم تتمكن من استخدام حقل الزيادة التلقائية، وتريد قطعاً قيمة فريدة من نوعها، والاستخدام UUID.إذا قررت استخدام أي شيء آخر (إلى جانب الزيادة التلقائية)، فسيكون من السخافة عدم التحقق من وجود تصادمات.

يحتوي منشور المدونة هذا على شيء قريب مما تبحث عنه.

http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl/

وهناك MD5 من عدد تزايد يجب أن يكون على ما يرام، ولكن أخشى أنه إذا كنت اقتطاع MD5 الخاص بك (والذي هو عادة 128 بت) وصولا الى 5-8 حرفا، سوف يكاد يكون من المؤكد أن الإضرار بها من القدرة على القيام بدور توقيع فريد من نوعه ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top