518 lines
19 KiB
PHP
518 lines
19 KiB
PHP
<?php
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', 1);
|
||
|
||
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/session_bootstrap.php';
|
||
|
||
if (empty($_SESSION['logged_in'])) {
|
||
header('Location: /login/');
|
||
exit();
|
||
}
|
||
|
||
$host = "localhost";
|
||
$db = "togethere_cloud";
|
||
$user = "root";
|
||
$pass = "HasloDoSQL";
|
||
|
||
try {
|
||
|
||
$pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
|
||
} catch (PDOException $e) {
|
||
die("Błąd połączenia z bazą danych: " . $e->getMessage());
|
||
}
|
||
|
||
$user_id = $_SESSION['user_id'];
|
||
$error = '';
|
||
$success = '';
|
||
$link_expired = false;
|
||
$code_verified = false;
|
||
|
||
// Pobranie danych użytkownika
|
||
try {
|
||
$stmt = $pdo->prepare("SELECT email, password, password_reset_code, password_reset_expires FROM users WHERE id = ?");
|
||
$stmt->execute([$user_id]);
|
||
$userData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$userData) {
|
||
die("Nie znaleziono użytkownika");
|
||
}
|
||
} catch (PDOException $e) {
|
||
die("Błąd bazy danych: " . $e->getMessage() . "<br><br>Czy dodałeś kolumny password_reset_code i password_reset_expires do tabeli users?<br><br>Wykonaj w phpMyAdmin:<br><pre>ALTER TABLE users\nADD COLUMN password_reset_code VARCHAR(6) NULL AFTER newsletter_enabled,\nADD COLUMN password_reset_expires DATETIME NULL AFTER password_reset_code;</pre>");
|
||
}
|
||
|
||
// Jeśli użytkownik nie ma kodu, przekieruj do żądania
|
||
if (empty($userData['password_reset_code'])) {
|
||
header('Location: /account/settings/?error=' . urlencode('Link do zmiany hasła jest nieważny lub został już użyty.'));
|
||
exit();
|
||
}
|
||
|
||
// Sprawdzenie czy kod wygasł
|
||
if (!empty($userData['password_reset_expires'])) {
|
||
if (strtotime($userData['password_reset_expires']) < time()) {
|
||
$link_expired = true;
|
||
}
|
||
}
|
||
|
||
// Obsługa resend
|
||
if (isset($_GET['resend']) && $_GET['resend'] == '1') {
|
||
$reset_code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
|
||
$reset_expires = date('Y-m-d H:i:s', strtotime('+15 minutes'));
|
||
|
||
$update = $pdo->prepare("UPDATE users SET password_reset_code = ?, password_reset_expires = ? WHERE id = ?");
|
||
$update->execute([$reset_code, $reset_expires, $user_id]);
|
||
|
||
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/smtp_helper.php';
|
||
|
||
$subject = "Nowy kod zmiany hasła - Wspólnie";
|
||
$message = "
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset='utf-8'>
|
||
<style>
|
||
body { font-family: 'Lato', Arial, sans-serif; background: #f0f8ff; padding: 20px; }
|
||
.container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 15px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
|
||
h1 { color: #ff9800; text-align: center; }
|
||
.code { font-size: 32px; font-weight: bold; color: #ff9800; text-align: center; letter-spacing: 5px; margin: 30px 0; padding: 20px; background: #fff3e0; border-radius: 10px; }
|
||
p { color: #2c3e50; line-height: 1.6; }
|
||
.footer { margin-top: 30px; padding-top: 20px; border-top: 2px solid #fff3e0; text-align: center; color: #7f8c8d; font-size: 14px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class='container'>
|
||
<h1>🔒 Nowy kod zmiany hasła</h1>
|
||
<p>Twój nowy kod weryfikacyjny to:</p>
|
||
<div class='code'>$reset_code</div>
|
||
<p>Kod jest ważny przez <strong>15 minut</strong>.</p>
|
||
<div class='footer'>
|
||
<p>© 2026 Wspólnie. Wszelkie prawa zastrzeżone.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
";
|
||
|
||
sendEmailSMTP($userData['email'], $subject, $message);
|
||
$success = "Nowy kod został wysłany na Twój email!";
|
||
$link_expired = false;
|
||
}
|
||
|
||
// Weryfikacja kodu
|
||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['action']) && $_POST['action'] === 'verify_code' && !$link_expired) {
|
||
$code = trim($_POST["code"] ?? "");
|
||
|
||
if (empty($code)) {
|
||
$error = "Kod weryfikacyjny jest wymagany.";
|
||
} else {
|
||
if (strtotime($userData['password_reset_expires']) < time()) {
|
||
$error = "Kod weryfikacyjny wygasł.";
|
||
$link_expired = true;
|
||
} elseif ($userData['password_reset_code'] != $code) {
|
||
$error = "Nieprawidłowy kod weryfikacyjny.";
|
||
} else {
|
||
$code_verified = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Walidacja i zmiana hasła
|
||
function validatePassword($password) {
|
||
$errors = [];
|
||
|
||
if (strlen($password) < 8) {
|
||
$errors[] = "Hasło musi mieć minimum 8 znaków";
|
||
}
|
||
if (!preg_match('/[A-Z]/', $password)) {
|
||
$errors[] = "Hasło musi zawierać wielką literę";
|
||
}
|
||
if (!preg_match('/[a-z]/', $password)) {
|
||
$errors[] = "Hasło musi zawierać małą literę";
|
||
}
|
||
if (!preg_match('/[0-9]/', $password)) {
|
||
$errors[] = "Hasło musi zawierać cyfrę";
|
||
}
|
||
|
||
return $errors;
|
||
}
|
||
|
||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['action']) && $_POST['action'] === 'change_password') {
|
||
$code = trim($_POST["code"] ?? "");
|
||
$new_password = $_POST["new_password"] ?? "";
|
||
$confirm_password = $_POST["confirm_password"] ?? "";
|
||
|
||
// Pobierz aktualne hasło użytkownika
|
||
$stmt = $pdo->prepare("SELECT password, password_reset_code, password_reset_expires FROM users WHERE id = ?");
|
||
$stmt->execute([$user_id]);
|
||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (strtotime($user['password_reset_expires']) < time()) {
|
||
$error = "Kod weryfikacyjny wygasł.";
|
||
$link_expired = true;
|
||
} elseif ($user['password_reset_code'] != $code) {
|
||
$error = "Nieprawidłowy kod weryfikacyjny.";
|
||
} elseif (empty($new_password) || empty($confirm_password)) {
|
||
$error = "Wszystkie pola są wymagane.";
|
||
$code_verified = true;
|
||
} elseif ($new_password !== $confirm_password) {
|
||
$error = "Hasła nie są identyczne.";
|
||
$code_verified = true;
|
||
} else {
|
||
// Walidacja siły hasła
|
||
$validation_errors = validatePassword($new_password);
|
||
|
||
if (!empty($validation_errors)) {
|
||
$error = implode(", ", $validation_errors);
|
||
$code_verified = true;
|
||
} elseif (password_verify($new_password, $user['password'])) {
|
||
$error = "Nowe hasło nie może być takie samo jak obecne hasło.";
|
||
$code_verified = true;
|
||
} else {
|
||
// Wszystko OK - zmień hasło
|
||
$new_hash = password_hash($new_password, PASSWORD_DEFAULT);
|
||
$update = $pdo->prepare("UPDATE users SET password = ?, password_reset_code = NULL, password_reset_expires = NULL WHERE id = ?");
|
||
$update->execute([$new_hash, $user_id]);
|
||
|
||
header('Location: /account/settings/?success=password_changed');
|
||
exit();
|
||
}
|
||
}
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Zmiana hasła | Wspólnie</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta charset="utf-8">
|
||
<link rel="stylesheet" href="/css/header.css" type="text/css" media="all"/>
|
||
<link rel="stylesheet" href="/css/footer.css" type="text/css" media="all"/>
|
||
<link href="/css/font-awesome.min.css" rel="stylesheet" type="text/css" media="all">
|
||
<link href="/css/style.css" rel="stylesheet" type="text/css" media="all">
|
||
<link href="//fonts.googleapis.com/css?family=Lato:400,500,600,700,800,900" rel="stylesheet">
|
||
<style>
|
||
body {
|
||
background: linear-gradient(135deg, #e3f2fd 0%, #ffffff 100%);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.verify-container {
|
||
max-width: 500px;
|
||
margin: 80px auto;
|
||
padding: 40px;
|
||
background: white;
|
||
border-radius: 15px;
|
||
box-shadow: 0 10px 30px rgba(100, 181, 246, 0.2);
|
||
flex: 1;
|
||
}
|
||
|
||
.verify-container * {
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
form {
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
align-items: center !important;
|
||
width: 100% !important;
|
||
}
|
||
|
||
h1 {
|
||
color: #1976d2;
|
||
font-size: 2em;
|
||
margin-bottom: 10px;
|
||
text-align: center;
|
||
}
|
||
|
||
.subtitle {
|
||
text-align: center;
|
||
color: #7f8c8d;
|
||
margin-bottom: 30px;
|
||
font-size: 0.95em;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 25px !important;
|
||
text-align: center !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
align-items: center !important;
|
||
width: 100% !important;
|
||
}
|
||
|
||
input[type="text"],
|
||
input[type="password"] {
|
||
width: 300px !important;
|
||
max-width: 300px !important;
|
||
padding: 15px !important;
|
||
border: 2px solid #e3f2fd !important;
|
||
border-radius: 8px !important;
|
||
font-size: 18px !important;
|
||
text-align: center !important;
|
||
transition: all 0.3s ease !important;
|
||
margin: 0 auto !important;
|
||
box-sizing: border-box !important;
|
||
font-family: 'Lato', Arial, sans-serif !important;
|
||
}
|
||
|
||
input[type="text"] {
|
||
font-size: 24px !important;
|
||
letter-spacing: 8px !important;
|
||
font-weight: bold !important;
|
||
color: #007BFF !important;
|
||
}
|
||
|
||
input:focus {
|
||
outline: none !important;
|
||
border-color: #007BFF !important;
|
||
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1) !important;
|
||
}
|
||
|
||
button {
|
||
width: 100% !important;
|
||
max-width: 300px !important;
|
||
padding: 15px !important;
|
||
background: linear-gradient(135deg, #007BFF 0%, #0056b3 100%) !important;
|
||
color: white !important;
|
||
border: none !important;
|
||
border-radius: 8px !important;
|
||
font-size: 1.1em !important;
|
||
font-weight: 600 !important;
|
||
cursor: pointer !important;
|
||
transition: all 0.3s ease !important;
|
||
display: block !important;
|
||
margin: 0 auto !important;
|
||
font-family: 'Lato', Arial, sans-serif !important;
|
||
}
|
||
|
||
button:hover {
|
||
transform: translateY(-2px) !important;
|
||
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.3) !important;
|
||
background: linear-gradient(135deg, #0056b3 0%, #004085 100%) !important;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%) !important;
|
||
margin-top: 0 !important;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: linear-gradient(135deg, #5a6268 0%, #3d4349 100%) !important;
|
||
}
|
||
|
||
.success {
|
||
background: #d4edda !important;
|
||
color: #155724 !important;
|
||
padding: 15px !important;
|
||
border-radius: 8px !important;
|
||
margin-bottom: 20px !important;
|
||
text-align: center !important;
|
||
border-left: 4px solid #28a745 !important;
|
||
}
|
||
|
||
.error {
|
||
background: #ffebee !important;
|
||
color: #c62828 !important;
|
||
padding: 15px !important;
|
||
border-radius: 8px !important;
|
||
margin-bottom: 20px !important;
|
||
text-align: center !important;
|
||
border-left: 4px solid #c62828 !important;
|
||
}
|
||
|
||
.info-box {
|
||
background: #e3f2fd !important;
|
||
border-left: 4px solid #42a5f5 !important;
|
||
padding: 15px !important;
|
||
margin-bottom: 25px !important;
|
||
border-radius: 5px !important;
|
||
font-size: 0.95em !important;
|
||
color: #2c3e50 !important;
|
||
}
|
||
|
||
label {
|
||
display: block !important;
|
||
text-align: left !important;
|
||
width: 300px !important;
|
||
margin: 0 auto 10px !important;
|
||
font-weight: 600 !important;
|
||
color: #2c3e50 !important;
|
||
font-family: 'Lato', Arial, sans-serif !important;
|
||
}
|
||
|
||
a {
|
||
color: #007BFF !important;
|
||
text-decoration: none !important;
|
||
font-weight: 600 !important;
|
||
}
|
||
|
||
a:hover {
|
||
text-decoration: underline !important;
|
||
}
|
||
|
||
.button-container {
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
align-items: center !important;
|
||
gap: 15px !important;
|
||
margin-top: 20px !important;
|
||
width: 100% !important;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%) !important;
|
||
margin-top: 0 !important;
|
||
}
|
||
</style>
|
||
<script>
|
||
// Delay 60s na przycisk resend
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const resendBtn = document.getElementById('resend-btn');
|
||
if (!resendBtn) return;
|
||
|
||
const lastResend = localStorage.getItem('lastResendTime_password');
|
||
if (lastResend) {
|
||
const elapsed = Math.floor((Date.now() - parseInt(lastResend)) / 1000);
|
||
if (elapsed < 60) {
|
||
startCountdown(60 - elapsed);
|
||
}
|
||
}
|
||
|
||
resendBtn.addEventListener('click', function(e) {
|
||
if (resendBtn.disabled) {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
localStorage.setItem('lastResendTime_password', Date.now());
|
||
});
|
||
|
||
function startCountdown(seconds) {
|
||
resendBtn.disabled = true;
|
||
resendBtn.style.opacity = '0.5';
|
||
resendBtn.style.cursor = 'not-allowed';
|
||
|
||
const originalText = resendBtn.textContent;
|
||
|
||
const interval = setInterval(function() {
|
||
resendBtn.textContent = `Wysyłanie ponownie za ${seconds}s`;
|
||
seconds--;
|
||
|
||
if (seconds < 0) {
|
||
clearInterval(interval);
|
||
resendBtn.disabled = false;
|
||
resendBtn.style.opacity = '1';
|
||
resendBtn.style.cursor = 'pointer';
|
||
resendBtn.textContent = originalText;
|
||
localStorage.removeItem('lastResendTime_password');
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
if (urlParams.get('resend') === '1') {
|
||
startCountdown(60);
|
||
}
|
||
});
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<?php
|
||
if (!empty($_SESSION['logged_in'])) {
|
||
include $_SERVER['DOCUMENT_ROOT'].'/global/navLogined.php';
|
||
} else {
|
||
include $_SERVER['DOCUMENT_ROOT'].'/global/navNoLogined.php';
|
||
}
|
||
?>
|
||
|
||
<div class="verify-container">
|
||
<h1>🔒 Zmiana hasła</h1>
|
||
<p class="subtitle">Wpisz 6-cyfrowy kod wysłany na Twój email</p>
|
||
|
||
<?php if ($error): ?>
|
||
<div class="error"><?= htmlspecialchars($error) ?></div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($success): ?>
|
||
<div class="success"><?= htmlspecialchars($success) ?></div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($link_expired): ?>
|
||
<div class="error">
|
||
<strong>⏰ Kod wygasł!</strong><br>
|
||
Twój kod weryfikacyjny stracił ważność po 15 minutach.<br>
|
||
Kliknij przycisk poniżej aby otrzymać nowy kod.
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="info-box">
|
||
<strong>📧 Email:</strong> <?= htmlspecialchars($userData['email']) ?><br>
|
||
<strong>⏱️ Kod ważny:</strong> 15 minut od wysłania
|
||
</div>
|
||
|
||
<?php if (!$link_expired && !$code_verified): ?>
|
||
<form method="POST">
|
||
<input type="hidden" name="action" value="verify_code">
|
||
|
||
<div class="form-group">
|
||
<input type="text" name="code" maxlength="6" pattern="[0-9]{6}"
|
||
placeholder="000000" required autofocus>
|
||
</div>
|
||
|
||
<div class="button-container">
|
||
<button type="submit">Weryfikuj kod</button>
|
||
</div>
|
||
</form>
|
||
<?php elseif ($code_verified): ?>
|
||
<div class="info-box">
|
||
ℹ️ Hasło musi zawierać co najmniej 8 znaków, w tym wielką literę, małą literę i cyfrę.
|
||
</div>
|
||
<form method="POST">
|
||
<input type="hidden" name="action" value="change_password">
|
||
<input type="hidden" name="code" value="<?= htmlspecialchars($_POST['code'] ?? '') ?>">
|
||
|
||
<div class="form-group">
|
||
<label for="new_password">Nowe hasło</label>
|
||
<input type="password" id="new_password" name="new_password" placeholder="Nowe hasło" required>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="confirm_password">Potwierdź hasło</label>
|
||
<input type="password" id="confirm_password" name="confirm_password" placeholder="Powtórz hasło" required>
|
||
</div>
|
||
|
||
<div class="button-container">
|
||
<button type="submit">Zmień hasło</button>
|
||
</div>
|
||
</form>
|
||
<?php else: ?>
|
||
<p style="text-align: center; color: #7f8c8d; margin: 20px 0;">
|
||
Formularz jest zablokowany. Kliknij "Wyślij kod ponownie" aby otrzymać nowy kod.
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<div class="button-container">
|
||
<button type="button" id="resend-btn" class="btn-secondary"
|
||
onclick="if(!this.disabled) window.location.href='?resend=1'">
|
||
Wyślij kod ponownie
|
||
</button>
|
||
</div>
|
||
|
||
<div style="text-align: center; margin-top: 20px;">
|
||
<a href="/account/settings/" style="color: #007BFF; text-decoration: none; font-weight: 600;">
|
||
← Powrót do ustawień
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<?php
|
||
if (!empty($_SESSION['logged_in'])) {
|
||
include $_SERVER['DOCUMENT_ROOT'].'/global/footerLogined.php';
|
||
} else {
|
||
include $_SERVER['DOCUMENT_ROOT'].'/global/footerNoLogined.php';
|
||
}
|
||
?>
|
||
</body>
|
||
</html>
|
||
|