Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПР / Хакова Ю. М. Отчет ПР8.docx
Скачиваний:
0
Добавлен:
07.06.2026
Размер:
442 Кб
Скачать

Style.Css – таблица стилей. Файл assets/style.Css содержит описания внешнего вида всех элементов интерфейса: карточек, кнопок, форм и полей ввода.

Рисунок 2 – Панель Владельца магазина

Рисунок 3 – Контрольная сумма

Листинг register.php

<?php

session_start();

error_reporting(E_ALL); ini_set('display_errors', 1);

$dsn = 'pgsql:host=127.0.0.1;port=5432;dbname=interslavic_db';

$user = 'webapp';

$pass = 'PASSWORD';

try {

$pdo = new PDO($dsn, $user, $pass, [

PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

]);

} catch (PDOException $e) {

echo '<!doctype html><meta charset="utf-8"><link rel="stylesheet" href="assets/style.css">';

echo '<body class="auth-page"><div class="auth-card alert err">'

. 'Не удалось подключиться: ' . htmlspecialchars($e->getMessage()) . '</div></body>';

exit;

}

$msg=''; $ok=false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

$fullname = trim($_POST['fullname'] ?? '');

$email = trim($_POST['email'] ?? '');

$login = trim($_POST['login'] ?? '');

$password = $_POST['password'] ?? '';

if ($fullname==='' || $email==='' || $login==='' || $password==='') {

$msg='Заполните все поля.';

} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {

$msg='Некорректный e-mail.';

} else {

$chk=$pdo->prepare('SELECT 1 FROM public.users WHERE email=:e OR login=:l');

$chk->execute([':e'=>$email, ':l'=>$login]);

if ($chk->fetch()) {

$msg='Пользователь с таким e-mail или логином уже существует.';

} else {

try{

$pdo->prepare('INSERT INTO public.users (fullname,email,login,password) VALUES (:f,:e,:l,:p)')

->execute([':f'=>$fullname, ':e'=>$email, ':l'=>$login, ':p'=>password_hash($password, PASSWORD_DEFAULT)]);

$ok=true; $msg='Регистрация прошла успешно! Теперь можно войти.';

}catch(PDOException $ex){

$msg = ($ex->getCode()==='23505') ? 'Такой e-mail или логин уже зарегистрирован.'

: 'Ошибка БД: '.htmlspecialchars($ex->getMessage(), ENT_QUOTES, 'UTF-8');

}

}

}

}

?>

<!doctype html>

<html lang="ru">

<head>

<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">

<title>Регистрация — Interslavic</title>

<link rel="stylesheet" href="assets/style.css">

</head>

<body class="auth-page">

<div class="auth-card">

<div class="auth-brand">

<div class="auth-logo">IS</div>

<strong>Interslavic</strong>

</div>

<h2 class="auth-title">Создание аккаунта</h2>

<?php if ($msg): ?>

<div class="alert <?= $ok ? 'ok' : 'err' ?>" style="margin-bottom:10px;">

<?= htmlspecialchars($msg, ENT_QUOTES, 'UTF-8') ?>

</div>

<?php endif; ?>

<form class="auth-form" method="post" autocomplete="off">

<div class="auth-input">

<label>ФИО</label>

<input name="fullname" required value="<?= htmlspecialchars($_POST['fullname'] ?? '', ENT_QUOTES, 'UTF-8') ?>">

</div>

<div class="auth-input">

<label>Email</label>

<input name="email" type="email" required value="<?= htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>">

</div>

<div class="auth-input">

<label>Логин</label>

<input name="login" required value="<?= htmlspecialchars($_POST['login'] ?? '', ENT_QUOTES, 'UTF-8') ?>">

</div>

<div class="auth-input">

<label>Пароль</label>

<input name="password" type="password" required>

</div>

<div class="auth-actions">

<button class="btn" type="submit">Зарегистрироваться</button>

<button class="btn secondary" type="button" onclick="location.href='login.php'">У меня есть аккаунт</button>

</div>

</form>

</div>

</body>

</html>

Листинг login.php

<?php

session_start();

require __DIR__ . '/partials/ui.php';

error_reporting(E_ALL); ini_set('display_errors', 1);

$dsn = 'pgsql:host=127.0.0.1;port=5432;dbname=interslavic_db';

$user = 'webapp';

$pass = 'PASSWORD';

try {

$pdo = new PDO($dsn, $user, $pass, [

PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

]);

} catch (PDOException $e) {

ui_header('Вход');

echo '<div class="container"><div class="card alert err">Не удалось подключиться: '

. htmlspecialchars($e->getMessage()) . '</div></div>';

ui_footer(); exit;

}

$message = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

$login = trim($_POST['login'] ?? '');

$password = $_POST['password'] ?? '';

if ($login === '' || $password === '') {

$message = 'Введите логин и пароль.';

} else {

$st = $pdo->prepare('SELECT user_id, fullname, password FROM public.users WHERE login = :l');

$st->execute([':l' => $login]);

$u = $st->fetch();

if ($u && password_verify($password, $u['password'])) {

session_regenerate_id(true);

$_SESSION['user_id'] = $u['user_id'];

$_SESSION['fullname'] = $u['fullname'];

$pdo->prepare('UPDATE public.users SET last_login = now() WHERE user_id = :id')

->execute([':id' => $u['user_id']]);

header('Location: profile.php'); exit;

} else {

$message = 'Неверный логин или пароль.';

}

}

}

?>

<!doctype html>

<html lang="ru">

<head>

<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">

<title>Вход — Interslavic</title>

<link rel="stylesheet" href="assets/style.css">

</head>

<body class="auth-page">

<div class="auth-card">

<div class="auth-brand">

<div class="auth-logo">IS</div>

<strong>Interslavic</strong>

</div>

<h2 class="auth-title">Вход в систему</h2>

<?php if ($message): ?>

<div class="alert err" style="margin-bottom:10px;">

<?= htmlspecialchars($message, ENT_QUOTES, 'UTF-8') ?>

</div>

<?php endif; ?>

<form class="auth-form" method="post" autocomplete="off">

<div class="auth-input">

<label>Логин</label>

<input name="login" required>

</div>

<div class="auth-input">

<label>Пароль</label>

<input name="password" type="password" required>

</div>

<div class="auth-actions">

<button class="btn" type="submit">Войти</button>

<button class="btn secondary" type="button" onclick="location.href='register.php'">Создать аккаунт</button>

</div>

</form>

<div class="auth-note">

Забыли пароль? <span class="link">пока не реализовано</span>

</div>

</div>

</body>

</html>

Листинг profile.php

<?php

session_start(); require __DIR__.'/partials/ui.php';

if(!isset($_SESSION['user_id'])){ header('Location: login.php'); exit; }

ui_header('Профиль');

?>

<div class="card">

<div style="display:flex; gap:18px; align-items:center;">

<div class="logo" style="width:64px;height:64px; font-size:22px;">

<?= strtoupper(substr($_SESSION['fullname'],0,1)).strtoupper(substr(strstr($_SESSION['fullname'],' '),1,1)) ?>

</div>

<div>

<h2 style="margin:0"><?= htmlspecialchars($_SESSION['fullname']) ?></h2>

<div style="color:#7a7a7a">Статус: обучающийся</div>

</div>

<div style="margin-left:auto">

<a class="btn secondary" href="logout.php">Выйти</a>

</div>

</div>

</div>

<div class="hero">

<div class="card progress">

<h3>Прогресс</h3>

<div class="pill"><span>Местоимения</span><b>2%</b></div>

<div class="pill"><span>Прилагательные</span><b>54%</b></div>

<div class="pill"><span>Существительные</span><b>100%</b></div>

</div>

<div class="card">

<h3>Продолжить обучение</h3>

<div style="display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; margin-top:12px">

<a class="pill" style="text-decoration:none;color:inherit" href="#"><span>Учебные материалы</span><b>▶</b></a>

<a class="pill" style="text-decoration:none;color:inherit" href="#"><span>Тестирование</span><b>▶</b></a>

<a class="pill" style="text-decoration:none;color:inherit" href="#"><span>Практика</span><b>▶</b></a>

<a class="pill" style="text-decoration:none;color:inherit" href="#"><span>Карточки</span><b>▶</b></a>

</div>

</div>

</div>

<?php ui_footer(); ?>

Листинг logout.php

<?php

session_start();

session_unset();

session_destroy();

header("Location: login.php");

exit;

Листинг cart.php

<?php

session_start();

require __DIR__ . '/partials/ui.php';

require __DIR__ . '/db.php';

if (empty($_SESSION['user_id'])) {

header('Location: login.php');

exit;

}

$userId = (int)$_SESSION['user_id'];

ui_header('Корзина');

$st = $pdo->prepare("

SELECT ci.id as cart_id,

p.id as product_id,

p.title,

p.price,

ci.qty

FROM public.cart_items ci

JOIN public.products p ON p.id = ci.product_id

WHERE ci.user_id = :u

ORDER BY ci.id

");

$st->execute([':u' => $userId]);

$items = $st->fetchAll();

$total = 0;

foreach ($items as $it) {

$lineSum = (float)$it['price'] * (int)$it['qty'];

$total += $lineSum;

}

?>

<section class="card">

<h2>Корзина</h2>

<?php if (!$items): ?>

<p>Ваша корзина пуста.</p>

<?php else: ?>

<table style="width:100%; border-collapse:collapse; margin-top:10px;">

<thead>

<tr style="border-bottom:1px solid #E6E0D9;">

<th style="text-align:left;padding:8px 4px;">Курс</th>

<th style="text-align:left;padding:8px 4px;">Цена</th>

<th style="text-align:left;padding:8px 4px;">Кол-во</th>

<th style="text-align:left;padding:8px 4px;">Сумма</th>

<th style="text-align:left;padding:8px 4px;">Действия</th>

</tr>

</thead>

<tbody>

<?php foreach ($items as $it):

$lineSum = (float)$it['price'] * (int)$it['qty']; ?>

<tr style="border-bottom:1px solid #F0EAE2;">

<td style="padding:6px 4px;"><?= htmlspecialchars($it['title'], ENT_QUOTES, 'UTF-8') ?></td>

<td style="padding:6px 4px;"><?= $it['price'] > 0 ? $it['price'].' ₽' : 'Бесплатно' ?></td>

<td style="padding:6px 4px;"><?= (int)$it['qty'] ?></td>

<td style="padding:6px 4px;"><?= $lineSum > 0 ? $lineSum.' ₽' : '—' ?></td>

<td style="padding:6px 4px;">

<a class="btn secondary small"

href="cart_remove.php?id=<?= (int)$it['cart_id'] ?>"

onclick="return confirm('Удалить курс из корзины?');">

Удалить

</a>

</td>

</tr>

<?php endforeach; ?>

</tbody>

</table>

<p style="margin-top:16px;font-weight:600;">

Итоговая стоимость: <?= $total > 0 ? $total.' ₽' : 'Бесплатно' ?>

</p>

<form action="order_create.php" method="post">

<button type="submit" class="btn">Сформировать заказ</button>

</form>

<?php endif; ?>

</section>

<?php ui_footer(); ?>

Листинг cart_add.php

<?php

session_start();

require __DIR__ . '/db.php';

if (empty($_SESSION['user_id'])) {

header('Location: login.php');

exit;

}

$userId = (int)$_SESSION['user_id'];

$productId = isset($_POST['product_id']) ? (int)$_POST['product_id'] : 0;

if ($productId <= 0) {

header('Location: catalog.php');

exit;

}

$st = $pdo->prepare('SELECT id, price FROM public.products WHERE id = :id');

$st->execute([':id' => $productId]);

$product = $st->fetch();

if (!$product) {

header('Location: catalog.php');

exit;

}

$st = $pdo->prepare('SELECT id, qty FROM public.cart_items

WHERE user_id = :u AND product_id = :p');

$st->execute([':u' => $userId, ':p' => $productId]);

$row = $st->fetch();

if ($row) {

$upd = $pdo->prepare('UPDATE public.cart_items

SET qty = qty + 1

WHERE id = :id');

$upd->execute([':id' => $row['id']]);

} else {

$ins = $pdo->prepare('INSERT INTO public.cart_items (user_id, product_id, qty)

VALUES (:u, :p, 1)');

$ins->execute([':u' => $userId, ':p' => $productId]);

}

header('Location: cart.php');

exit;

Листинг cart_remove.php

<?php

session_start();

require __DIR__ . '/db.php';

if (empty($_SESSION['user_id'])) {

header('Location: login.php');

exit;

}

$userId = (int)$_SESSION['user_id'];

$cartId = isset($_GET['id']) ? (int)$_GET['id'] : 0;

if ($cartId > 0) {

$st = $pdo->prepare('DELETE FROM public.cart_items WHERE id = :id AND user_id = :u');

$st->execute([':id' => $cartId, ':u' => $userId]);

}

header('Location: cart.php');

exit;

Листинг order_create.php

<?php

session_start();

require __DIR__ . '/partials/ui.php';

require __DIR__ . '/db.php';

if (empty($_SESSION['user_id'])) {

header('Location: login.php');

exit;

}

$userId = (int)$_SESSION['user_id'];

$st = $pdo->prepare("

SELECT ci.id as cart_id,

p.id as product_id,

p.title,

p.price,

ci.qty

FROM public.cart_items ci

JOIN public.products p ON p.id = ci.product_id

WHERE ci.user_id = :u

");

$st->execute([':u' => $userId]);

$items = $st->fetchAll();

if (!$items) {

header('Location: cart.php');

exit;

}

$total = 0;

foreach ($items as $it) {

$total += (float)$it['price'] * (int)$it['qty'];

}

try {

$pdo->beginTransaction();

$insOrder = $pdo->prepare("

INSERT INTO public.orders (user_id, total_sum, status)

VALUES (:u, :total, 'new')

RETURNING id

");

$insOrder->execute([':u' => $userId, ':total' => $total]);

$orderId = (int)$insOrder->fetchColumn();

$insItem = $pdo->prepare("

INSERT INTO public.order_items (order_id, product_id, qty, price)

VALUES (:o, :p, :q, :price)

");

foreach ($items as $it) {

$insItem->execute([

':o' => $orderId,

':p' => (int)$it['product_id'],

':q' => (int)$it['qty'],

':price'=> (float)$it['price'],

]);

}

$del = $pdo->prepare('DELETE FROM public.cart_items WHERE user_id = :u');

$del->execute([':u' => $userId]);

$pdo->commit();

} catch (Exception $e) {

$pdo->rollBack();

ui_header('Ошибка заказа');

echo "<section class='card'><p>Не удалось сформировать заказ: "

. htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')

. "</p></section>";

ui_footer();

exit;

}

ui_header('Заказ сформирован');

?>

<section class="card">

<h2>Заказ №<?= $orderId ?> успешно сформирован</h2>

<p>В ваш заказ входят следующие курсы:</p>

<ul>

<?php foreach ($items as $it): ?>

<li>

<?= htmlspecialchars($it['title'], ENT_QUOTES, 'UTF-8') ?>

— <?= (int)$it['qty'] ?> шт.

(<?= $it['price'] > 0 ? $it['price'].' ₽' : 'Бесплатно' ?>)

</li>

<?php endforeach; ?>

</ul>

<p style="margin-top:10px;font-weight:600;">

Итоговая сумма: <?= $total > 0 ? $total.' ₽' : 'Бесплатно' ?>

</p>

<a href="profile.php" class="btn secondary">Вернуться в профиль</a>

</section>

<?php ui_footer(); ?>

Листинг change_password.php

<?php

require __DIR__ . '/partials/ui.php';

require __DIR__ . '/db.php';

ui_header('Смена пароля');

if (empty($_SESSION['user_id'])) {

header('Location: login.php?next=' . urlencode($_SERVER['REQUEST_URI']));

exit;

}

$userId = (int)$_SESSION['user_id'];

$message = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {

$message = 'Неверный CSRF-токен.';

} else {

$old = $_POST['old_password'] ?? '';

$new = $_POST['new_password'] ?? '';

$new2= $_POST['new_password2'] ?? '';

if ($new === '' || strlen($new) < 6) {

$message = 'Новый пароль должен содержать не менее 6 символов.';

} elseif ($new !== $new2) {

$message = 'Пароли не совпадают.';

} else {

$st = $pdo->prepare("SELECT password FROM public.users WHERE user_id = :u");

$st->execute([':u' => $userId]);

$row = $st->fetch();

if (!$row || !password_verify($old, $row['password'])) {

$message = 'Старый пароль неверен.';

} else {

$hash = password_hash($new, PASSWORD_DEFAULT);

$upd = $pdo->prepare("UPDATE public.users SET password = :p WHERE user_id = :u");

$upd->execute([':p' => $hash, ':u' => $userId]);

$message = 'Пароль успешно изменён.';

}

}

}

}

if (empty($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(24));

?>

<section class="card">

<h2>Смена пароля</h2>

<?php if ($message): ?>

<div class="alert err" style="margin-bottom:12px;"><?= htmlspecialchars($message) ?></div>

<?php endif; ?>

<form method="post" class="form">

<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">

<div class="input">

<label>Старый пароль</label>

<input name="old_password" type="password" required>

</div>

<div class="input">

<label>Новый пароль</label>

<input name="new_password" type="password" required>

</div>

<div class="input">

<label>Повторите новый пароль</label>

<input name="new_password2" type="password" required>

</div>

<button class="btn" type="submit">Сменить пароль</button>

</form>

</section>

<?php ui_footer(); ?>

Листинг profile_edit.php

<?php

session_start();

require __DIR__ . '/partials/ui.php';

if (empty($_SESSION['user_id'])) {

header('Location: login.php');

exit;

}

require __DIR__ . '/db.php';

$user_id = $_SESSION['user_id'];

$message = '';

$stmt = $pdo->prepare("SELECT fullname, email, login FROM public.users WHERE user_id = :id");

$stmt->execute([':id' => $user_id]);

$user = $stmt->fetch();

if (!$user) {

ui_header('Ошибка');

echo '<div class="container"><div class="card alert err">Пользователь не найден.</div></div>';

ui_footer();

exit;

}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

$fullname = trim($_POST['fullname'] ?? '');

$email = trim($_POST['email'] ?? '');

$login = trim($_POST['login'] ?? '');

if ($fullname === '' || $email === '' || $login === '') {

$message = 'Все поля обязательны.';

} else {

$upd = $pdo->prepare("

UPDATE public.users

SET fullname = :fn, email = :em, login = :lg

WHERE user_id = :id

");

$upd->execute([

':fn' => $fullname,

':em' => $email,

':lg' => $login,

':id' => $user_id,

]);

$_SESSION['fullname'] = $fullname;

$message = 'Данные успешно обновлены.';

}

}

ui_header('Редактирование профиля');

?>

<div class="container">

<div class="card" style="max-width:480px;margin:auto;">

<h2>Редактирование профиля</h2>

<?php if ($message): ?>

<div class="alert ok" style="margin-bottom:10px;">

<?= htmlspecialchars($message) ?>

</div>

<?php endif; ?>

<form method="post">

<label>ФИО</label>

<input name="fullname" value="<?= htmlspecialchars($user['fullname']) ?>" required>

<label>Email</label>

<input name="email" type="email" value="<?= htmlspecialchars($user['email']) ?>" required>

<label>Логин</label>

<input name="login" value="<?= htmlspecialchars($user['login']) ?>" required>

<div style="margin-top:14px; display:flex; gap:12px;">

<button class="btn" type="submit">Сохранить</button>

<a class="btn secondary" href="profile.php">Отмена</a>

</div>

</form>

</div>

</div>

<?php ui_footer(); ?>

Листинг owner_dashboard.php

<?php

session_start();

if (empty($_SESSION['user_id']) || ($_SESSION['role'] ?? '') !== 'owner') {

header('Location: login.php');

exit;

}

require __DIR__ . '/partials/ui.php';

require __DIR__ . '/db.php';

require __DIR__ . '/checksum_verify.php';

ui_header('Панель владельца');

$usersCount = (int)$pdo->query("SELECT COUNT(*) FROM public.users")->fetchColumn();

$ordersCount = (int)$pdo->query("SELECT COUNT(*) FROM public.orders")->fetchColumn();

$grossProfit = (float)$pdo->query("SELECT COALESCE(SUM(total_sum), 0) FROM public.orders")->fetchColumn();

SELECT COALESCE(SUM(total_sum - cost_sum),0) FROM public.orders

$netProfit = $grossProfit;

$st = $pdo->query("

SELECT id, user_id, total_sum, status, checksum

FROM public.orders

ORDER BY id DESC

LIMIT 20

");

$orders = $st->fetchAll();

?>

<section class="card">

<h2>Панель владельца магазина</h2>

<p style="color:#777; margin-top:6px;">

Доступно только роли <b>owner</b>. Текущая роль: <b><?= htmlspecialchars($_SESSION['role'], ENT_QUOTES, 'UTF-8') ?></b>

</p>

<div style="display:flex; gap:16px; flex-wrap:wrap; margin-top:14px;">

<div class="card" style="min-width:220px;">

<h3 style="margin-top:0;">Пользователи</h3>

<div style="font-size:28px; font-weight:700;"><?= $usersCount ?></div>

</div>

<div class="card" style="min-width:220px;">

<h3 style="margin-top:0;">Заказы</h3>

<div style="font-size:28px; font-weight:700;"><?= $ordersCount ?></div>

</div>

<div class="card" style="min-width:260px;">

<h3 style="margin-top:0;">Балансовая прибыль</h3>

<div style="font-size:22px; font-weight:700;">

<?= number_format($grossProfit, 2, ',', ' ') ?> ₽

</div>

<div style="color:#777; font-size:12px;">Сумма total_sum по заказам</div>

</div>

<div class="card" style="min-width:260px;">

<h3 style="margin-top:0;">Чистая прибыль</h3>

<div style="font-size:22px; font-weight:700;">

<?= number_format($netProfit, 2, ',', ' ') ?> ₽

</div>

<div style="color:#777; font-size:12px;">(Если нет себестоимости — расчёт упрощён)</div>

</div>

</div>

</section>

<section class="card" style="margin-top:16px;">

<h3 style="margin-top:0;">Контроль целостности заказов (контрольная сумма)</h3>

<?php if (!$orders): ?>

<p>Заказов пока нет.</p>

<?php else: ?>

<table style="width:100%; border-collapse:collapse; margin-top:10px;">

<thead>

<tr style="border-bottom:1px solid #E6E0D9;">

<th style="text-align:left;padding:8px 4px;">№</th>

<th style="text-align:left;padding:8px 4px;">User</th>

<th style="text-align:left;padding:8px 4px;">Сумма</th>

<th style="text-align:left;padding:8px 4px;">Статус</th>

<th style="text-align:left;padding:8px 4px;">Контрольная сумма</th>

</tr>

</thead>

<tbody>

<?php foreach ($orders as $o): ?>

<?php $isValid = verify_order_checksum($o); ?>

<tr style="border-bottom:1px solid #F0EAE2; <?= $isValid ? '' : 'background:#ffe1e1;' ?>">

<td style="padding:6px 4px;"><?= (int)$o['id'] ?></td>

<td style="padding:6px 4px;"><?= (int)$o['user_id'] ?></td>

<td style="padding:6px 4px;"><?= number_format((float)$o['total_sum'], 2, ',', ' ') ?> ₽</td>

<td style="padding:6px 4px;"><?= htmlspecialchars($o['status'], ENT_QUOTES, 'UTF-8') ?></td>

<td style="padding:6px 4px;">

<?= $isValid ? 'OK' : 'Ошибка' ?>

</td>

</tr>

<?php endforeach; ?>

</tbody>

</table>

<p style="margin-top:10px;color:#777;">

</p>

<?php endif; ?>

</section>

<?php ui_footer(); ?>

Листинг checksum.php

<?php

const CHECKSUM_SECRET = 'my_super_secret_key_123';

function build_order_checksum_string(array $orderRow): string

{

$parts = [

$orderRow['id'] ?? '',

$orderRow['user_id'] ?? '',

$orderRow['total_sum'] ?? '',

$orderRow['status'] ?? '',

];

return implode('|', $parts);

}

function calc_checksum(string $data): string

{

return hash('sha256', $data . CHECKSUM_SECRET);

}

function calc_order_checksum(array $orderRow): string

{

return calc_checksum(build_order_checksum_string($orderRow));

}

Листинг checksum_verify.php

<?php

require __DIR__ . '/checksum.php';

function verify_order_checksum(array $orderRow): bool

{

if (empty($orderRow['checksum'])) {

return false;

}

$actual = calc_order_checksum($orderRow);

return hash_equals($actual, (string)$orderRow['checksum']);

}