• 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
تولید یک ترکیب عدد و حروف یکتا و بدون تکرار
#1
سلام...
توی بخشی از یک پروژه باید یک ترکیب عدد و حروف 6یا 7کاراکتری ایجاد بشه که در کل دیتابیس منحصربفرد باشه و تکرار نشده باشه.
از طریق تابع زیر به صورت رندوم این ترکیب رو ایجاد میکنم و هردفعه یه عبارتی رو برام ایجاد میکنه و خوشبختانه تاحالا هم به مورد تکراری برخورد نکردم
کد پی‌اچ‌پی:
function getRandomString(){
        
$length=6;
        
$characters='0123456789abcdefghijklmnopqrstuvwxyz';
        
$string='';
            for(
$p=0;$p<$length;$p++){
            
$string.=$characters[mt_rand(0,strlen($characters))];
            }
            return 
$string;
        } 
اما نگرانم که نشه یه وقتی یه مورد تکراری پیش بیاد....شما راه حل بهتری سراغ دارین؟ به نظرتون همین تابع کارآمد هست؟
الگوریتم دیگه ای میتونین پیشنهاد بدین که مطمئن باشیم حالت تکراری پیش نمیاد؟
امروز به روش های مختلفی داشتم فکر میکردم..
مثلا یه روشش این بود که با توجه به اینکه به جز این عبارت 6.7کاراکتری یه عدد منحصر به فرد دیگه هم توی این جدول و در فیلد دیگه ای قرار میگیره که اون هم تکرار نشدنیه...
داشتم فکر میکردم مثلا اون عدد رو با الگوریتم های رمزنگاری ، رمزنگاریش کنم و 7کاراکتر اولش رو جدا کنم و از اون استفاده کنم. به نظرتون خوبه؟ یا همین روش بالا جوابگو هست برای کار من.
برای همون نرم افزار رزرواسیون.
بنده طعم ايمان را نمي چشد، تا اينكه دريابد آنچه اتفاق نيفتاده است نمي شد كه اتفاق بيفتد؛و آنچه شده و اتفاق افتاده است,نمي شد كه نشود و اتفاق نيفتد....حضرت علي(ع)
  پاسخ
تشکر شده توسط :
#2
اگه واسه کد رهگیری یا مثل اون میخوای من خودم معمولا timestamp ( حداقل چند رقمش ) رو هم اضافه میکنم بهش که خیلی احتمال تکرار پایین بیاد.
ولی اگه موارد امنیتی میخوای مثل تولید کلید رمزنگاری، تو همین انجمن زیاد دیدم راجع بهش صحبت شده . میتونی ایده بگیری...
  پاسخ
تشکر شده توسط : hamid_80386 webnevesht
#3
یه چیزی مثل کد رهگیریه....
توی بلیت های هواپیماها یه چیزی داریم به اسم کد رفرنس...یا کد رزرو....
یه ترکیب 6کاراکتری از حروف و اعداده...یعنی میگی timestamp رو تبدیل به کد رمز کنم و 6کاراکترش رو جدا کنم؟ چون خود timestamp که عدده فقط.
بنده طعم ايمان را نمي چشد، تا اينكه دريابد آنچه اتفاق نيفتاده است نمي شد كه اتفاق بيفتد؛و آنچه شده و اتفاق افتاده است,نمي شد كه نشود و اتفاق نيفتد....حضرت علي(ع)
  پاسخ
تشکر شده توسط :
#4
آقای vejmad تو این تاپیک یک نمونه تابع rand گذاشتند.
http://forum.iranphp.org/Thread-%D8%AA%D...A%A9%D8%AC
آرام باش ؛ توكل كن ؛ تفكر كن و سپس آستينها را بالا بزن , آنگاه دستان خداوند را خواهي ديد كه زودتر از تو دست به كار شده است.امام علي عليه السلام.
  پاسخ
تشکر شده توسط : vejmad oia Reza
#5
خب اینکه گذاشتی 36 کاراکتر ممکن داره و چون طولش 6 هست، نتیجه میشود که 36 به توان 6 یعنی کمی بیشتر از دو میلیارد حالت داره.
بنابراین بعد از 2 میلیارد و خورده ای رکورد حتما یک مقدار تکراری خواهی داشت.
اما شاید تعداد رکوردهات هیچوقت اینقدر نمیشه که بخوای نگرانش باشی.
بهرحال اگر یکتا بودنش رو در دیتابیس با کوئری چک نکنی، همیشه یک احتمالی هرچند ناچیز وجود داره که دوتا رشتهء رندوم یکسان تولید بشن. اگر این احتمال بنظرت قابل قبوله، پس مشکلی نیست، اما اگر غیرقابل قبوله و باید 100% مطمئن باشی، پس باید به فکر چک کردن یکتا بودن مقدار باشی یا از یک روش دیگر استفاده کنی که یکتا بودن رو تضمین کنه.

بعد تابع mt_rand هم کلا جالب نیست چون هم فضای seed اون بیش از حد محدوده و هم از منابع محدودی برای تولید seed خودکار استفاده میکنه.
همونطور که کاربر دیگر گفت، از اون تابعی که بنده معرفی کردم برای تولید اعداد رندوم امنیتی استفاده کنید.

دست آخر هم باید بگم که اصلا چرا میخوای از رشتهء رندوم استفاده کنی؟ اگر نیاز امنیتی نداری، میتونی بجاش از مقدار یک فیلد auto increment استفاده کنی.

از رشتهء رندوم جاهایی استفاده میشه که مثلا اون رشته در دسترس کاربر هست ولی کاربر نباید بتونه اون رو پیشبینی کنه یا با ضریب موفقیت معقولی حدس بزنه و یا Brute-force کنه.

حالا یه کار دیگه هم که میتونی بکنی اینه که فیلد auto increment رو هم به اول یا آخر رشتهء خودت اضافه کنی. به این شکل هم رشتهء رندوم داری (که کسی نتونه پیشبینی یا Brute-force کنه) و هم یکتا بودن اون تضمین شده هست (مگر اینکه فیلد auto increment به هر دلیلی reset بشه که بنده دقیقا نمیدونم در چه مواردی اینطور میشه چون تحقیق و تست نکردم؛ ولی فکر میکنم در موقع خالی کردن و ایجاد دوبارهء جدول. ضمنا اگر فیلد auto increment از نوع عددی کوچکی باشه و جدول رکوردهای خیلی زیادی داشته باشه، احتمال Overflow شدن رو هم باید درنظر گرفت).

البته مقدار auto increment رو از رشتهء رندوم توسط یک کاراکتری که در هیچکدام از اونها وجود نداره جدا کن. مثلا با یک خط فاصله. چون اگر این کار رو نکنی، اونوقت ممکنه ترکیب رشتهء رندوم و عدد auto increment باهم منجر به ایجاد رشته های غیریکتا بشه. مثلا اگر مقدار فعلی auto عدد 10 باشه، اونوقت یک رشته ای که قبلا ساختی و اون موقع auto برابر 1 بوده و کاراکتر اول رشتهء رندوم 0 بوده، دچار یکسان بودن تصادفی میشه. نه؟ این مورد رو الان به ذهنم رسید!

ضمنا طول رشتهء رندوم شما هم برای مقاصد امنیتی کافی نیست. یعنی اگر میخوای حرفه ای باشه بهتره تعداد حالت بیشتری داشته باشه. مثلا 2 به توان 128 حالت (اینطوری حتی در برابر حمله های آفلاین هم امنه).
همونطور که قبلا گفته شد، بازهم تاکید میکنم که برای مقاصد امنیتی از یک تابع رندوم امنیتی استفاده کن، نه mt_rand و اینطور چیزها.
  پاسخ
تشکر شده توسط : oia ali786
#6
نقل قول:بنابراین بعد از 2 میلیارد و خورده ای رکورد حتما یک مقدار تکراری خواهی داشت.
البته حداکثر در بهترین حالت !
وگرنه ممکنه کمتر از این هم رکورد تکراری باشه .

شما شناسه رکورد قبلی رو هم اضافه کن .
بعد اون فیلد رو یونیک بذار تا تکراری نگیره .
وبلاگ rezaonline.net/blog
سفارش برنامه نویسی reza.biz
Php , mysql , postgresql , redis , Yii and ... Cool
  پاسخ
تشکر شده توسط :
#7
نقل قول:البته حداکثر در بهترین حالت !
وگرنه ممکنه کمتر از این هم رکورد تکراری باشه .
...
نقل قول:بهرحال اگر یکتا بودنش رو در دیتابیس با کوئری چک نکنی، همیشه یک احتمالی هرچند ناچیز وجود داره که دوتا رشتهء رندوم یکسان تولید بشن.

رضا یکم خوب بخون Angel

نقل قول:شما شناسه رکورد قبلی رو هم اضافه کن .
بعد اون فیلد رو یونیک بذار تا تکراری نگیره .
البته اینم نکته بود واسه خودش
  پاسخ
تشکر شده توسط :
#8
نه بحث امنیتی نیست....
ببینین روی یک بلیت چندتا پارامتر داریم.
یکی شماره واچر اون بلیته...یکی شماره رفرنس-که ترکیب عدد و حرف و 6 کاراکتری هم هست- و یکی هم شماره بلیت...این سه تا پارامتر رو باید داشته باشن...پس بحث امنیتی نیست....معمولا برای پیگیری یک بلیت از شماره رفرنس اون استفاده میشه..یه چیزی تو مایه های کد رهگیریه...
بنده طعم ايمان را نمي چشد، تا اينكه دريابد آنچه اتفاق نيفتاده است نمي شد كه اتفاق بيفتد؛و آنچه شده و اتفاق افتاده است,نمي شد كه نشود و اتفاق نيفتد....حضرت علي(ع)
  پاسخ
تشکر شده توسط :
#9
من اینطور نتیجه گرفتم که در برخی از موارد این رشته های رندوم از لحاظ امنیتی برای سیستم مهم نیستند اما اینکه قبل از ثبت اونها در دیتابیس از منحصر به فرد بودن اونها مطمئن نشیم قاعدتا یک باگ خواهیم داشت دیر یا زود ، مگر اینکه از لحاظ منطقی همچین چیزی (تکرار) قابل رخداد نباشد ، مثل اینکه بیایم یه همچین فرمولی استفاده کنیم :

آیدی رکورد آخر - رشته رندوم - timestamp

و البته نسبت به نیاز می شود چیز های دیگری هم به این رشته اضافه کرد اما وجود id و timestamp در رشته رندوم که با خط تیره (یا یک همچین چیزی) از هم جدا شده اند با عث می شود رشته همیشه یونیک باشد .

ممنون
  پاسخ
تشکر شده توسط :
#10
(۱۳۹۱ مرداد ۰۴, ۱۱:۳۷ ق.ظ)webnevesht نوشته: نه بحث امنیتی نیست....
ببینین روی یک بلیت چندتا پارامتر داریم.
یکی شماره واچر اون بلیته...یکی شماره رفرنس-که ترکیب عدد و حرف و 6 کاراکتری هم هست- و یکی هم شماره بلیت...این سه تا پارامتر رو باید داشته باشن...پس بحث امنیتی نیست....معمولا برای پیگیری یک بلیت از شماره رفرنس اون استفاده میشه..یه چیزی تو مایه های کد رهگیریه...
بنده دقیقا نمیدونم و مطمئن نیستم که چرا به حداقل سه عدد نیازه و چرا فرمت شماره رفرنس باید حتما اینطور باشه. احتمالا اونایی که تجربه و اطلاعات عملی بیشتری دارن میدونن. و شاید هم اصلا اجبار نباشه حتما اینطور باشه. ضمنا گاهی حتی دلایل غیرفنی هم ممکنه دخیل باشن. یک وقت هم میبینی اصلا اون قضیه لزوما از پایه درست نیست (مثلا یک کسی یک فکری کرده و یه چیزی پیاده کرده که لزوما صحیح یا بهترین روش نبوده).

ولی بهرحال دلیلش هرچی هست (فرض کنیم درسته و باید این رشته با این فرمت حتما باشه)، برای اطمینان 100% از یکتا بودن باید به ازای هر رشتهء رندوم جدید یک کوئری به دیتابیس بفرستی، یا یک جزء غیر رندوم و یکتا هم درش باشه.

اما شاید در سیستمهای دیگر هم یکتا بودن 100% تضمین نشده و همون احتمال ناچیز تکراری شدن رو کافی دونستن.

ضمنا بهرحال استفاده از یک تابع رندوم امن برای کاهش احتمال تکراری شدن بنظرم مفیده. یعنی حتی اگر کاربردت امنیتی نیست.
  پاسخ
تشکر شده توسط :


پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان