CREATE TABLE `otp` (
`user_email` varchar(255) NOT NULL,
`otp_pass` varchar(64) NOT NULL,
`otp_timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`otp_tries` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `otp`
ADD PRIMARY KEY (`user_email`);
--------------------------------------------------------------------------------------------------
2-otp.php adında dosya oluşturun içerisine aşağıdakileri yapıştırın
class OTP {
// (A) CONSTRUCTOR - CONNECT TO DATABASE
protected $pdo = null;
protected $stmt = null;
public $error = "";
function __construct() {
try {
$this->pdo = new PDO(
"mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
} catch (Exception $ex) { die($ex->getMessage()); }
}
// (B) DESTRUCTOR - CLOSE CONNECTION
function __destruct() {
if ($this->stmt !== null) { $this->stmt = null; }
if ($this->pdo !== null) { $this->pdo = null; }
}
// (C) GENERATE OTP
function generate ($email) {
// @TODO -
// YOU SHOULD CHECK IF THE PROVIDED EMAIL IS A VALID USER IN YOUR SYSTEM
// (C1) CHECK IF USER ALREADY HAS EXISTING OTP REQUEST
$this->stmt = $this->pdo->prepare(
"SELECT * FROM `otp` WHERE `user_email`=?"
);
$this->stmt->execute([$email]);
$otp = $this->stmt->fetch(PDO::FETCH_NAMED);
// (C2) ALREADY HAS OTP REQUEST
if (is_array($otp)) {
// @TODO -
// ADD YOUR OWN RULES HERE - ALLOW NEW REQUEST IF EXIPRED?
// $validTill = strtotime($otp['otp_timestamp']) + (OTP_VALID * 60);
// if (strtotime("now") > $validTill) { DELETE OLD REQUEST }
// else { ERROR }
$this->error = "You already have a pending OTP.";
return false;
}
// (C3) CREATE RANDOM PASSWORD
$alphabets = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
$count = strlen($alphabets) - 1;
$pass = "";
for ($i=0; $i
// (C4) DATABASE ENTRY
try {
$this->stmt = $this->pdo->prepare(
"REPLACE INTO `otp` (`user_email`, `otp_pass`) VALUES (?,?)"
);
$this->stmt->execute([$email, $pass]);
} catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
// (C5) SEND VIA EMAIL
// @TODO - FORMAT YOUR OWN "NICE" EMAIL OR SEND VIA SMS.
$mailSubject = "Your OTP";
$mailBody = "Your OTP is $pass. Enter it at 3b-challenge.php within 15 minutes.";
if (@mail($email, $mailSubject, $mailBody)) {
return true;
} else {
$this->error = "Failed to send OTP email.";
return false;
}
}
// (D) CHALLENGE OTP
function challenge ($email, $pass) {
// (D1) GET THE OTP ENTRY
$this->stmt = $this->pdo->prepare(
"SELECT * FROM `otp` WHERE `user_email`=?"
);
$this->stmt->execute([$email]);
$otp = $this->stmt->fetch(PDO::FETCH_NAMED);
// (D2) OTP ENTRY NOT FOUND
if (!is_array($otp)) {
$this->error = "The specified OTP request is not found.";
return false;
}
// (D3) TOO MANY TRIES
if ($otp['otp_tries'] >= OTP_TRIES) {
$this->error = "Too many tries for OTP.";
return false;
}
// (D4) EXPIRED
$validTill = strtotime($otp['otp_timestamp']) + (OTP_VALID * 60);
if (strtotime("now") > $validTill) {
$this->error = "OTP has expired.";
return false;
}
// (D5) INCORRECT PASSWORD - ADD STRIKE
if ($pass != $otp['otp_pass']) {
$strikes = $otp['otp_tries'] + 1;
$this->stmt = $this->pdo->prepare(
"UPDATE `otp` SET `otp_tries`=? WHERE `user_email`=?"
);
$this->stmt->execute([$strikes, $email]);
// @TODO - TOO MANY STRIKES
// LOCK ACCOUNT? REQUIRE MANUAL VERIFICATION? SUSPEND FOR 24 HOURS?
// if ($strikes >= OTP_TRIES) { DO SOMETHING }
$this->error = "Incorrect OTP.";
return false;
}
// (D6) ALL OK - DELETE OTP
$this->stmt = $this->pdo->prepare(
"DELETE FROM `otp` WHERE `user_email`=?"
);
$this->stmt->execute([$email]);
return true;
}
}
// (E) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_CHARSET', 'utf8');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
// (F) ONE-TIME PASSWORD SETTINGS
define('OTP_VALID', "15"); // VALID FOR X MINUTES
define('OTP_TRIES', "3"); // MAX TRIES
define('OTP_LEN', "8"); // PASSWORD LENGTH
// (G) NEW OTP OBJECT
$_OTP = new OTP();
------------------------------------------------------------------------------------------------
otp yi yukarıda oluşturduk şimdi OTP yi talep edelim
3a-request.php oluşturalım
OTP REQUEST
// (B) PROCESS OTP REQUEST
if (isset($_POST['email'])) {
require "2-otp.php";
$pass = $_OTP->generate($_POST['email']);
echo $pass ? "
OTP SENT.
" : "".$_OTP->error."
" ;}
?>
---------------------------------------------
3b-challenge.php
OTP CHALLENGE
// (B) PROCESS OTP CHALLENGE
if (isset($_POST['email'])) {
require "2-otp.php";
$pass = $_OTP->challenge($_POST['email'], $_POST['otp']);
echo $pass ? "
OTP VERIFIED.
" : "".$_OTP->error."
" ;}
?>