Hướng dẫn dùng random 1-10 trong PHP

Vietnamese (Tiếng Việt) translation by Vy Cam Nguyen (you can also view the original English article)

Hãy để tôi bắt đầu bài viết này bằng việc nói rằng hầu như không có sự kiện nào thực sự ngẫu nhiên. Ngay cả kết quả của trò tung đồng xu kinh điển về mặt lý thuyết cũng có thể được dự đoán nếu chúng ta biết tác động của mọi yếu tố liên quan, như ma sát không khí, trọng lực và lực ban đầu.

Việc tạo ra các chuỗi ngẫu nhiên gồm chữ và số cũng có nguyên tắc tương tự. Điều tốt đẹp nhất có thể chờ đợi là tạo ra những số và chuỗi không tuân theo một pattern(hình mẫu) và một kẻ tấn công về thực tiễn sẽ không thể đoán ra.

Trong hướng dẫn này, chúng tôi sẽ đề cập đến các kỹ thuật khác nhau để tạo số và chuỗi ký tự chữ ngẫu nhiên trong PHP. Một số trong số chúng sẽ được mã hóa, trong khi một số khác chỉ dành cho nhu cầu thông thường, như gán tên file giả ngẫu nhiên hoặc tạo URL và đề xuất username(tên người dùng).

Tạo ra các số ngẫu nhiên trong PHP

Có ba hàm khác nhau để tạo số ngẫu nhiên trong PHP. Tất cả các hàm đó sẽ nhận một giá trị tối thiểu và tối đa có thể cho các số ngẫu nhiên và trả về một số ngẫu nhiên cho bạn. Đó là rand($min, $max), mt_rand($min, $max)random_int($min, $max).

Với rand(), giá trị tối thiểu và tối đa của các integer (số nguyên) mà bạn có thể tạo nằm giữa 0 và giá trị được trả về bởi getrandmax(). Trước khi có PHP 7.1.0, hàm này chậm hơn khoảng bốn lần so với mt_rand(). Tuy nhiên, bắt đầu từ PHP 7.1.0, nó đã thành một alias của mt_rand(). Tuy nhiên, không giống như mt_rand(), bạn có thể đặt giá trị của $max thấp hơn $min mà không gây ra lỗi.

Với mt_rand(), các giá trị tối thiểu và tối đa của integer bạn có thể tạo nằm giữa 0 và giá trị được trả về bởi mt_getrandmax(). Nó dựa vào triển khai của Mersenne Twister để tạo ra các số ngẫu nhiên. Xem ra, mặc dù trước khi có PHP 7.1.0, hàm này đã triển khai một phiên bản thuật toán không chính xác để tạo ra các số. Tuy nhiên, hàm này đã được sửa trong các phiên bản mới hơn.

Hàm này thậm chí còn trở nên tốt hơn trong PHP 7.2.0 bằng cách loại bỏ lỗi modulo. Điều này có nghĩa là đối với một số seed cụ thể, chuỗi số ngẫu nhiên của bạn bây giờ sẽ tốt hơn một chút so với các phiên bản cũ hơn. Măc dù một số code chuyên dụng thực sự có thể dựa vào khuynh hướng này. Nếu vậy, bạn có thể sử dụng thuật toán seed cũ hơn bằng cách gọi hàm mt_srand() để seed trình tạo số ngẫu nhiên và truyền MT_RAND_PHP làm giá trị của tham số thứ hai.

Hàm mt_rand() có chu kỳ 219937−1, về cơ bản có nghĩa là trong trường hợp tốt nhất bạn có được số lượng ngẫu nhiên 219937−1 trước khi chuỗi bắt đầu lặp lại. Bạn nên lưu ý rằng việc lặp lại một chuỗi không giống như việc lặp lại một số cụ thể. Nói cách khác, bạn có thể nhận được cùng một số ngẫu nhiên hai lần, nhưng điều đó không có nghĩa là chính chuỗi đó đã bắt đầu lặp lại. Trình tự sau đây là một ví dụ:

187 3276 1267 15 1267 34598 3467 125 17

Trong chuỗi trên, chúng tôi đã có 1267 hai lần trong kết quả, nhưng điều đó không có nghĩa là toàn bộ chuỗi bắt đầu lặp lại sau đó. Không thể có cùng một số lặp lại sớm như vậy trong một chuỗi ngẫu nhiên, nhưng điều đó có thể!

Số nguyên ngẫu nhiên được mã hóa an toàn

Nếu bạn muốn các số pseudo (giả) ngẫu nhiên được bảo mật bằng mã hóa, hàm random_int() trong PHP là lựa chọn tốt nhất của bạn. Nó sẽ tạo các số ngẫu nhiên giữa các giá trị $min$max được cung cấp, mặc định là PHP_INT_MINPHP_INT_MAX. Thật không may, hàm này chỉ có bắt đầu hỗ trợ từ PHP 7.0. Đối với các phiên bản trước đó, bạn có thể sử dụng polyfill này trên GitHub.

Các số float ngẫu nhiên

Thay vì tạo integer ngẫu nhiên, có thể bạn cũng muốn tạo số float. Điều này có thể được thực hiện dễ dàng bằng cách chia một số ngẫu nhiên với giá trị được trả về bởi mt_getrandmax(). Ví dụ sau đây sẽ minh họa cách tạo ra một số float ngẫu nhiên trong khoảng từ 0 đến 1 hoặc giữa bất kỳ giới hạn tối thiểu và tối đa nào khác.

Khi tạo số float ngẫu nhiên giữa các giới hạn nhất định, chúng tôi đảm bảo rằng các integer ngẫu nhiên không vượt quá $max - 1. Bằng cách này, chúng tôi có thể chắc chắn rằng việc thêm phần float sẽ không lấy số vượt quá giới hạn tối đa.

Seed cho trình tạo số ngẫu nhiên

Một khái niệm cần một chút giải thích là seeds. Nói một cách đơn giản, đây chỉ là những số có thể được sử dụng để khởi tạo các hàm rand()mt_rand() trước khi tạo bất kỳ số ngẫu nhiên nào. Hàm mà seed rand() được gọi là srand($seed) và hàm tạo seed mt_rand() được gọi là mt_srand($seed, $mode).

Điều quan trọng cần nhớ là việc cung cấp một giá trị seed ban đầu mỗi lần trước khi gọi rand()mt_rand() sẽ không nhất thiết tạo ra các số ngẫu nhiên tốt hơn. Trong thực tế, sử dụng cùng một seed mỗi lần sẽ cho bạn cùng một số ngẫu nhiên!

Seed một số ngẫu nhiên rất hữu ích trong các tình huống mà bạn muốn tạo một chuỗi ngẫu nhiên nhưng có thể lặp lại. Đoạn mã sau tạo ra cùng một chuỗi các số ngẫu nhiên khi chạy hai lần.

Việc tạo các chuỗi ngẫu nhiên có thể lặp lại theo cách này có thể giúp gỡ lỗi các chương trình đang được thử nghiệm bằng cách sử dụng dữ liệu ngẫu nhiên nếu bạn theo dõi seed, bạn có thể sao chép cùng một dữ liệu đầu vào để tìm ra lỗi sai.

Tạo chuỗi ký tự ngẫu nhiên trong PHP

Có nhiều cách để tạo chuỗi ký tự chữ và số ngẫu nhiên và bạn sử dụng cái gì thì sẽ phụ thuộc nhu cầu của bạn.

Tạo ra các chuỗi xáo trộn

Nếu bạn muốn tạo các chuỗi ký tự chữ và số ngẫu nhiên từ một bộ ký tự cố định, bạn có thể sử dụng hàm str_shuffle($string). Hàm này sẽ trả về cho bạn một chuỗi xáo trộn ngẫu nhiên. Bắt đầu từ PHP 7.1, thuật toán xác định thứ tự ngẫu nhiên của các ký tự trong chuỗi kết quả đã được thay đổi thành Mersenne Twister.

Hãy nhớ rằng chuỗi ngẫu nhiên được tạo theo cách này không an toàn về mặt bảo mật mã hóa. Tuy nhiên, chuỗi vẫn sẽ không thể đoán trước được khi nhu cầu sử dụng phổ biến như tạo tên file hoặc URL ngẫu nhiên. Đây là vài ví dụ:

Kết quả của bạn có thể sẽ khác nhau trong cả hai trường hợp. Trong trường hợp đầu tiên, chúng tôi chỉ xáo trộn chuỗi ký tự được phép và sau đó lấy 10 ký tự đầu tiên của chuỗi đó. Trong trường hợp thứ hai, chúng tôi đã thêm "video" vào đầu chuỗi được tạo và ".mp4" ở cuối.

Phương pháp tạo chuỗi ký tự chữ và số ngẫu nhiên này rất dễ dàng, nhưng gặp phải một vài vấn đề. Ví dụ: bạn sẽ không bao giờ có được các ký tự giống nhau trong chuỗi ngẫu nhiên của mình hai lần. Ngoài ra, độ dài của chuỗi kết quả ngẫu nhiên chỉ có thể dài bằng chuỗi nhập vào.

Tạo chuỗi ngẫu nhiên

Nếu các vấn đề tôi liệt kê ở trên là một tác nhân làm hỏng vấn đề, bạn có thể muốn xem xét một số triển khai khác. Các code sau đây sẽ giải quyết cả hai vấn đề này.

Bạn có thể sửa đổi nó để bổ sung các hậu tố và tiền tố cụ thể vào chuỗi ngẫu nhiên vừa được tạo. Những người đang sử dụng PHP 7 có thể cải thiện hơn nữa việc tạo chuỗi bằng cách sử dụng hàm bảo mật mã hóa random_int() thay vì mt_rand().

Tạo chuỗi hexadecimal (thập lục phân) ngẫu nhiên

Nếu bạn muốn tạo các chuỗi thập lục phân ngẫu nhiên trong PHP, bạn cũng có thể sử dụng hàm md5($string, $rawDefput) hoặc hàm sha1($string, $rawDefput). Cả hai sẽ tạo ra hash của một chuỗi nhập vào.

Bạn sẽ tiếp tục nhận được các giá trị hash duy nhất miễn là dữ liệu vào là duy nhất. Điều này có thể đạt được bằng cách sử dụng kết quả của hàm như time() làm dữ liệu nhập vào. Theo mặc định, md5() sẽ trả về chuỗi hexadecimal 32 ký tự và sha1() sẽ trả về chuỗi hexadecimal 40 ký tự. Chúng có thể được cắt theo một độ dài cụ thể bằng cách sử dụng hàm substr().

Dưới đây là một ví dụ kết quả được trả về bởi các hàm này:

Như bạn có thể thấy, việc tạo các chuỗi hexadecimal ngẫu nhiên và duy nhất dài tới 40 ký tự rất dễ dàng trong PHP.

Tạo chuỗi ngẫu nhiên có bảo mật mã hóa

Ba hàm để tạo các chuỗi ký tự chữ và số ngẫu nhiên mà chúng ta đã thảo luận cho đến nay không có bảo mật mã hóa. May mắn thay, PHP cũng có một hàm random_bytes($length) để tạo các byte giả ngẫu nhiên được bảo mật mã hóa. Tham số $length xác định chuỗi kết quả sẽ dài bao nhiêu.

Khi bạn có kết quả dưới dạng byte ngẫu nhiên, bạn có thể sử dụng hàm bin2hex() để chuyển đổi chúng thành giá trị hexadecimal. Điều này sẽ làm tăng gấp đôi chiều dài của chuỗi.

Một chức năng khác mà bạn có thể sử dụng để tạo các byte ngẫu nhiên được bảo mật mã hóa là openssl_random_pseudo_bytes($length, & $crypto_strong). Giá trị của tham số thứ hai có thể được dùng để xác định xem chuỗi kết quả sẽ được tạo bằng thuật toán bảo mật mã hóa hay không.

Tổng kết

Trong hướng dẫn này, chúng tôi đã xem xét việc tạo ra các số và các chuỗi ký tự chữ ngẫu nhiên trong PHP. Việc tạo ra số ngẫu nhiên có thể hữu ích trong nhiều tình huống, như trong các trò chơi mà bạn phải tạo ra những kẻ thù hoặc ngẫu nhiên cung cấp cho người chơi một số manh mối về các chữ cái để họ có thể tạo thành một từ hoàn chỉnh.

Cũng giống như các số ngẫu nhiên, việc tạo ra các chuỗi chữ và số ngẫu nhiên cũng có thể khá hữu ích trong nhiều trường hợp. Với sự trợ giúp của str_shuffle(), bạn có thể chọn bộ ký tự nào xuất hiện trong chuỗi ngẫu nhiên của mình. Với sha1 () và md5 (), bạn có thể dễ dàng tạo các chuỗi thập lục phân ngẫu nhiên và với Random_bytes () bạn có thể tạo các chuỗi bảo mật bằng mật mã. Điều này sẽ cho phép bạn tạo ra các tên file và username ngẫu nhiên nhưng khó đoán.

Tôi hy vọng bạn thích hướng dẫn này. Nếu bạn có bất kỳ câu hỏi, hãy nêu lên trong phần bình luận.