Kısaca cevap
PHP rastgele şifre oluşturma için rand() veya mt_rand() değil, PHP 7.0'dan beri yerleşik olan random_int() kullanın: havuzdan her karakteri $alfabe[random_int(0, strlen($alfabe) - 1)] ile seçin. Token gerekiyorsa bin2hex(random_bytes(16)) yeterlidir. PHP 8.3 ve sonrasında Random\Randomizer::getBytesFromString() tek satırlık bir yol sunar.
Bu sayfada
PHP rand ile şifre üretmek neden güvensiz?
İnternetteki eski PHP şifre örneklerinin çoğu rand() kullanır. PHP belgeleri bu fonksiyon için açık bir uyarı içerir: rand() kriptografik olarak güvenli değer üretmez ve tahmin edilmemesi gereken değerler için kullanılmamalıdır. Aynı uyarı mt_rand(), str_shuffle(), shuffle() ve array_rand() için de geçerlidir.
PHP 7.1'den beri rand(), mt_rand() ile aynı üreteci (Mersenne Twister) kullanır. Bu üreteç hızlıdır ama öngörülebilirdir ve mt_srand() ile aynı tohum verildiğinde aynı sonuçları tekrarlar. Test için yararlı olan bu özellik, şifre üretirken açıktır. Konunun teorisini kriptografi ve rastgelelik yazısında bulabilirsiniz.
PHP random_int vs rand: hangisi ne zaman?
| Özellik | rand() / mt_rand() | random_int() / random_bytes() |
|---|---|---|
| Kaynak | Mersenne Twister (sözde rastgele) | İşletim sisteminin kriptografik kaynağı |
| Tohumla tekrarlanabilir mi? | Evet (mt_srand) | Hayır |
| Şifre, token, doğrulama kodu | Kullanılmamalı | Uygun |
| Oyun, örnek veri | Uygun | Uygun ama gerekmez |
| Sürüm | Eski sürümlerden beri | PHP 7.0+ |
random_int($min, $max) iki sınırı da sonuca dahil eder ve aralıktaki her sayıyı eşit olasılıkla seçer. Bu yüzden kendi hesabınızla mod almanız gerekmez; rastgele baytı % strlen($alfabe) ile küçültmek, havuz boyutu 256'ya tam bölünmüyorsa bazı karakterleri daha sık seçtirir (modulo sapması). random_int bu sorunu sizin yerinize çözer.
random_int ile PHP rastgele şifre oluşturma
<?php
function sifreUret(int $uzunluk = 16): string
{
$alfabe = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+?';
$sonIndeks = strlen($alfabe) - 1;
$sifre = '';
for ($i = 0; $i < $uzunluk; $i++) {
$sifre .= $alfabe[random_int(0, $sonIndeks)];
}
return $sifre;
}
echo sifreUret(), PHP_EOL;
echo sifreUret(24), PHP_EOL;
Fonksiyon, harf, rakam ve 15 özel karakterden oluşan 77 karakterlik havuzdan her karakteri bağımsız olarak seçer ve her çalıştırmada farklı bir 16 ve 24 karakterlik şifre yazdırır. 77 karakterlik havuzdan 16 karakter yaklaşık 100 bit rastgelelik verir; uzunluğun etkisini şifre kaç karakter olmalı yazısında görebilirsiniz.
strlen() karakter değil bayt sayar ve $alfabe[$i] tek bir bayt döndürür. Havuza ç, ş, ğ gibi Türkçe karakterler veya emoji eklerseniz bunlar UTF-8'de birden fazla bayt tuttuğu için bölünür ve bozuk karakterler çıkar. Havuzu ASCII karakterlerle sınırlı tutun.
PHP random string with numbers and letters: yalnızca harf ve rakam
Davet kodu, dosya adı veya özel karakter kabul etmeyen bir sistem için yalnızca harf ve rakamdan oluşan bir string gerekebilir. Aynı fonksiyonu havuzu parametre alacak şekilde genelleştirebilirsiniz:
<?php
function rastgeleString(
int $uzunluk = 10,
string $alfabe = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
): string {
$sonIndeks = strlen($alfabe) - 1;
$sonuc = '';
for ($i = 0; $i < $uzunluk; $i++) {
$sonuc .= $alfabe[random_int(0, $sonIndeks)];
}
return $sonuc;
}
echo rastgeleString(), PHP_EOL; // 10 karakter, harf + rakam
echo rastgeleString(8, '0123456789ABCDEF'), PHP_EOL; // 8 karakter, onaltılık
Uzunluk seçerken şunu hatırlayın: 62 karakterlik harf ve rakam havuzunda 10 karakter yaklaşık 59,5 bit, 16 karakter yaklaşık 95,3 bit, 20 karakter yaklaşık 119,1 bit rastgelelik verir. Kullanıcı şifresi olarak kullanılacaksa 16 karakterin altına inmemek iyi bir kuraldır.
Her karakter türünü garanti eden sürüm
"En az bir büyük harf, bir rakam ve bir özel karakter" isteyen formlar için önce her gruptan bir karakter seçin, kalanını tüm havuzdan doldurun, sonra sırayı yine random_int ile karıştırın (Fisher–Yates):
<?php
function gucluSifre(int $uzunluk = 16): string
{
$gruplar = [
'abcdefghijklmnopqrstuvwxyz',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'0123456789',
'!@#$%^&*()-_=+?',
];
if ($uzunluk < count($gruplar)) {
throw new InvalidArgumentException('Uzunluk en az ' . count($gruplar) . ' olmalı');
}
$tum = implode('', $gruplar);
$karakterler = [];
// Her gruptan en az bir karakter
foreach ($gruplar as $grup) {
$karakterler[] = $grup[random_int(0, strlen($grup) - 1)];
}
// Kalan konumlar tüm havuzdan
while (count($karakterler) < $uzunluk) {
$karakterler[] = $tum[random_int(0, strlen($tum) - 1)];
}
// Fisher–Yates karıştırma (random_int ile)
for ($i = count($karakterler) - 1; $i > 0; $i--) {
$j = random_int(0, $i);
$gecici = $karakterler[$i];
$karakterler[$i] = $karakterler[$j];
$karakterler[$j] = $gecici;
}
return implode('', $karakterler);
}
echo gucluSifre(16), PHP_EOL;
Karıştırma adımında shuffle() veya str_shuffle() kullanmayın; ikisi de güvenli olmayan Mersenne Twister üretecine dayanır. Karıştırmazsanız ilk dört karakter her zaman aynı tür sırasıyla gelir ve kalıp tahmin edilebilir hâle gelir.
PHP 8.2 ve 8.3: Random\Randomizer ile kısa yol
PHP 8.2 ile gelen Random\Randomizer sınıfı, motor belirtilmeden oluşturulduğunda kriptografik olarak güvenli Random\Engine\Secure motorunu kullanır. PHP 8.3'teki getBytesFromString() metodu ise verilen havuzdan istenen uzunlukta seçim yapar:
<?php
$rastgele = new \Random\Randomizer(); // varsayılan motor: Random\Engine\Secure
// PHP 8.3+: harf ve rakamlardan 12 karakterlik random string
echo $rastgele->getBytesFromString(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
12
), PHP_EOL;
Bu metot da bayt düzeyinde çalışır; havuzda çok baytlı karakter kullanmayın. Yukarıdaki gucluSifre fonksiyonunda PHP 8.2 ve sonrasındaysanız elle yazılan karıştırma döngüsü yerine $karakterler = (new \Random\Randomizer())->shuffleArray($karakterler); satırını da kullanabilirsiniz. shuffleArray diziyi yerinde değiştirmez, karıştırılmış yeni bir dizi döndürür.
PHP random string generator: random_bytes ile token
Şifre sıfırlama bağlantısı, API anahtarı veya oturum belirteci gibi insanların yazmayacağı değerler için karakter havuzuyla uğraşmanıza gerek yoktur:
<?php
$token = bin2hex(random_bytes(16)); // 16 bayt = 128 bit, 32 onaltılık karakter
echo $token, PHP_EOL;
random_bytes() ham baytlar döndürür; bunlar yazdırılamayan karakterler içerebilir. bin2hex() her baytı iki onaltılık karaktere çevirdiği için 16 bayt 32 karakterlik, yalnızca 0-9 ve a-f içeren bir metin olur. Bu değer adres satırında ve veritabanında sorunsuz kullanılabilir. Rastgele sayı gerekiyorsa (ör. 6 haneli doğrulama kodu) str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT) kalıbı başındaki sıfırları korur.
Eski PHP örneklerinde sık görülen hatalar
İnternetteki PHP şifre üretici örneklerinin çoğu çalışır ama güvenli değildir. Kopyaladığınız bir kodu şu kalıplara karşı kontrol edin:
rand()veyamt_rand()ile indeks seçmek: En yaygın hatadır; yerinerandom_int()yazmak çoğu zaman tek satırlık bir düzeltmedir.substr(str_shuffle($havuz), 0, 10): Hem güvenli olmayan üreteci kullanır hem de her karakteri en fazla bir kez seçer; tekrar eden karakter olmadığı için olası şifre sayısı azalır.md5(rand())veyamd5(time()): Özet almak rastgelelik eklemez. Girdi tahmin edilebiliyorsa çıktı da tahmin edilebilir; üstelik sonuç yalnızca onaltılık karakter içerir.uniqid()ile token üretmek: PHP belgelerine göre bu fonksiyon zamana dayanır, benzersizliği garanti etmez ve güvenlik amaçlı kullanılmamalıdır.
PHP şifreleme mi, hashleme mi?
"PHP şifreleme" diye aranan konuların çoğu aslında kullanıcı şifresini veritabanında güvenli saklamaktır. Bunun için md5() veya sha1() kullanmayın; PHP'nin yerleşik password_hash() ve password_verify() fonksiyonları tuzu kendisi üretir ve bilerek yavaş çalışan bir algoritma kullanır. Ayrıntılar PHP password_hash kullanımı ve şifre saklama yazılarında.
Dikkat edilmesi gerekenler
- Şifreyi günlüğe yazmayın: Üretilen şifreyi log dosyasına, hata mesajına veya oturum verisine düz metin olarak koymayın.
- Hata olursa geri dönmeyin:
random_intgüvenli kaynak bulamazsa istisna fırlatır (PHP 8.2+Random\RandomException). Bu durumdarand()'a düşen bir yedek yazmayın. - Kapanış etiketi gerekmez: Yalnızca PHP içeren dosyalarda
?>yazmamak, sonda kalan boşlukların çıktıya karışmasını önler. - Güncel PHP kullanın:
random_intPHP 7.0'dan beri vardır; daha eski bir sürümdeyseniz önce PHP'yi güncelleyin.
Aynı mantığın diğer dillerdeki karşılıkları: Python, JavaScript, C# ve Java. Kod yazmadan bir şifreye ihtiyacınız varsa şifre üretici tarayıcınızda çalışır ve şifreyi hiçbir yere göndermez.
Sık sorulan sorular
PHP'de rand ile şifre üretmek neden güvensiz?
PHP belgelerine göre rand ve mt_rand kriptografik olarak güvenli değerler üretmez ve tahmin edilmemesi gereken değerler için kullanılmamalıdır. PHP 7.1'den beri rand, mt_rand ile aynı üreteci (Mersenne Twister) kullanır; aynı tohumla aynı dizi elde edilir. Şifre ve token için random_int ile random_bytes kullanın.
random_int ile rand arasındaki fark nedir?
random_int işletim sisteminin kriptografik rastgele sayı kaynağını kullanır ve verilen aralıktan eşit olasılıkla bir tamsayı seçer; belgeler onu şifreleme anahtarı gibi uzun ömürlü gizli değerler için bile uygun sayar. rand ise hızlı ama öngörülebilir bir üreteçtir. random_int PHP 7.0'dan beri vardır ve iki sınır da sonuca dahildir.
PHP ile harf ve rakamlardan oluşan random string nasıl üretilir?
Harf ve rakamlardan oluşan 62 karakterlik bir havuz tanımlayın ve istediğiniz uzunluk kadar random_int(0, strlen($havuz) - 1) ile karakter seçin. PHP 8.3 ve sonrasında aynı işi new Random\Randomizer() nesnesinin getBytesFromString metodu tek satırda yapar.
random_int hata verirse ne olur?
Uygun bir rastgelelik kaynağı bulunamazsa random_int ve random_bytes istisna fırlatır; PHP 8.2'den beri bu istisnanın türü Random\RandomException'dır. Böyle bir durumda rand'a geri dönmek yerine hatayı kaydedip işlemi durdurun.
PHP'de şifreleri nasıl saklamalıyım?
Kullanıcı şifrelerini md5 veya sha1 ile değil, password_hash ile özetleyip password_verify ile doğrulayın. password_hash her şifre için rastgele bir tuzu kendisi üretir ve algoritma, maliyet ve tuz bilgisini sonucun içine yazar.