-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathforgot_password.php
More file actions
265 lines (239 loc) · 12.2 KB
/
Copy pathforgot_password.php
File metadata and controls
265 lines (239 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
<?php
session_start();
require 'configs/dbconnection.php';
use PHPMailer\PHPMailer\PHPMailer;
use Dotenv\Dotenv;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
$error = '';
$success = '';
// Load environment variables with error handling
try {
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
} catch (Exception $e) {
error_log("Dotenv Error: " . $e->getMessage());
$error = 'Configuration error. Please contact administrator.';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($error)) {
$email = $conn->real_escape_string($_POST['email']);
// Check if email exists in students table
try {
$stmt = $conn->prepare("SELECT studentID, email FROM students WHERE email = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$result = $stmt->get_result();
$student = $result->fetch_assoc();
if ($student) {
// Generate token
$token = bin2hex(random_bytes(32));
$expires = date('Y-m-d H:i:s', time() + 3600); // 1 hour expiration
// Store token in password_resets table
$stmt = $conn->prepare("INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE token = VALUES(token), expires_at = VALUES(expires_at)");
$stmt->bind_param("sss", $email, $token, $expires);
$stmt->execute();
// Create reset link
$resetLink = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]/Election/reset-password.php?token=$token";
// Send email using PHPMailer
$mail = new PHPMailer(true);
try {
// Check if environment variables exist
$smtpEmail = $_ENV['SMTP_EMAIL'] ?? '';
$smtpPassword = $_ENV['SMTP_PASSWORD'] ?? '';
if (empty($smtpEmail) || empty($smtpPassword)) {
throw new Exception('SMTP credentials not configured');
}
// Server settings
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = $smtpEmail;
$mail->Password = $smtpPassword;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = 465;
// Recipients
$mail->setFrom('no-reply@smartvote.com', $_ENV['APP_NAME'] ?? 'SmartVote');
$mail->addAddress($email);
// Content
$mail->isHTML(true);
$mail->Subject = 'Password Reset Request - SmartVote';
$mail->Body = "
<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;'>
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); padding: 20px; text-align: center;'>
<h1 style='color: white; margin: 0;'>SmartVote</h1>
</div>
<div style='padding: 30px; background: #f8f9fa;'>
<h2 style='color: #333;'>Password Reset Request</h2>
<p>Hello,</p>
<p>You requested a password reset for your SmartVote account.</p>
<div style='text-align: center; margin: 30px 0;'>
<a href='$resetLink' style='background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 15px 30px; text-decoration: none; border-radius: 8px; display: inline-block; font-weight: bold;'>Reset Password</a>
</div>
<p><strong>Or copy this link:</strong><br>
<code style='background: #e9ecef; padding: 5px; border-radius: 4px; word-break: break-all;'>$resetLink</code></p>
<p style='color: #666;'><em>This link will expire in 1 hour.</em></p>
<p>If you didn't request this, please ignore this email.</p>
<hr style='margin: 30px 0; border: none; border-top: 1px solid #dee2e6;'>
<p style='color: #666; font-size: 14px;'>Best regards,<br>SmartVote Team</p>
</div>
</div>
";
$mail->AltBody = "Password Reset Link: $resetLink";
$mail->send();
$success = 'Password reset link has been sent to your email. Check your inbox (and spam folder).';
} catch (Exception $e) {
error_log("Email Error: " . $e->getMessage());
$error = "Email could not be sent. Please try again later.";
}
} else {
$error = 'Email not found in our system.';
}
} catch (mysqli_sql_exception $e) {
error_log("Database Error: " . $e->getMessage());
$error = 'An error occurred. Please try again later.';
}
}
?>
<!doctype html>
<html lang="en" class="layout-wide customizer-hide" dir="ltr" data-skin="default" data-assets-path="assets/" data-template="vertical-menu-template" data-bs-theme="light">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
<title>Forgot Password - SmartVote</title>
<meta name="description" content="" />
<link rel="icon" type="image/x-icon" href="assets/img/favicon/favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="assets/vendor/fonts/iconify-icons.css" />
<link rel="stylesheet" href="assets/vendor/libs/pickr/pickr-themes.css" />
<link rel="stylesheet" href="assets/vendor/css/core.css" />
<link rel="stylesheet" href="assets/css/demo.css" />
<link rel="stylesheet" href="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
<link rel="stylesheet" href="assets/vendor/libs/@form-validation/form-validation.css" />
<link rel="stylesheet" href="assets/vendor/css/pages/page-auth.css" />
<script src="assets/vendor/js/helpers.js"></script>
<script src="assets/vendor/js/template-customizer.js"></script>
<script src="assets/js/config.js"></script>
<style>
.invalid-feedback { display: block; color: #ff3e1d; font-size: 0.875em; margin-top: 0.25rem; }
.is-invalid { border-color: #ff3e1d !important; }
.btn-reset { background: #7367f0; color: white; padding: 10px 15px; text-decoration: none; border-radius: 5px; display: inline-block; margin: 10px 0; }
.btn-loading {
position: relative;
pointer-events: none;
}
.btn-loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 3px solid transparent;
border-top-color: #ffffff;
border-radius: 50%;
animation: button-loading-spinner 1s ease infinite;
}
@keyframes button-loading-spinner {
from {
transform: rotate(0turn);
}
to {
transform: rotate(1turn);
}
}
</style>
</head>
<body>
<div class="container-xxl">
<div class="authentication-wrapper authentication-basic container-p-y">
<div class="authentication-inner">
<div class="card px-sm-6 px-0">
<div class="card-body">
<div class="app-brand justify-content-center">
<a href="index.php" class="app-brand-link gap-2">
<span class="app-brand-text demo text-heading fw-bold">SmartVote</span>
</a>
</div>
<h4 class="mb-1">Forgot Password? 🔒</h4>
<p class="mb-6">Enter your email and we'll send you instructions to reset your password</p>
<?php if ($error): ?>
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success"><?= htmlspecialchars($success) ?></div>
<?php endif; ?>
<form id="formAuthentication" class="mb-6" method="POST">
<div class="mb-6 form-control-validation">
<label for="email" class="form-label">Email</label>
<input type="text" class="form-control" id="email" name="email" placeholder="Enter your email" autofocus />
</div>
<button type="submit" id="submitBtn" class="btn btn-primary d-grid w-100">
<span id="buttonText">Send Reset Link</span>
</button>
</form>
<div class="text-center">
<a href="login.php" class="d-flex justify-content-center">
<i class="icon-base bx bx-chevron-left scaleX-n1-rtl me-1"></i>
Back to login
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="assets/vendor/libs/jquery/jquery.js"></script>
<script src="assets/vendor/libs/popper/popper.js"></script>
<script src="assets/vendor/js/bootstrap.js"></script>
<script src="assets/vendor/libs/@algolia/autocomplete-js.js"></script>
<script src="assets/vendor/libs/pickr/pickr.js"></script>
<script src="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js"></script>
<script src="assets/vendor/libs/hammer/hammer.js"></script>
<script src="assets/vendor/libs/i18n/i18n.js"></script>
<script src="assets/vendor/js/menu.js"></script>
<script src="assets/vendor/libs/@form-validation/popular.js"></script>
<script src="assets/vendor/libs/@form-validation/bootstrap5.js"></script>
<script src="assets/vendor/libs/@form-validation/auto-focus.js"></script>
<script src="assets/js/main.js"></script>
<script>
document.getElementById('formAuthentication').addEventListener('submit', function(e) {
e.preventDefault();
const email = document.getElementById('email').value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
document.getElementById('email').classList.remove('is-invalid');
const existingError = document.querySelector('.invalid-feedback');
if (existingError) existingError.remove();
if (!email) {
showError('email', 'Email is required');
return;
}
if (!emailRegex.test(email)) {
showError('email', 'Please enter a valid email address');
return;
}
// Show loading state
const submitBtn = document.getElementById('submitBtn');
const buttonText = document.getElementById('buttonText');
submitBtn.classList.add('btn-loading');
buttonText.style.visibility = 'hidden';
submitBtn.disabled = true;
// Submit the form
this.submit();
});
function showError(fieldId, message) {
const field = document.getElementById(fieldId);
field.classList.add('is-invalid');
const errorDiv = document.createElement('div');
errorDiv.className = 'invalid-feedback';
errorDiv.textContent = message;
field.parentNode.insertBefore(errorDiv, field.nextSibling);
}
</script>
</body>
</html>