Сообщение от Безнадежный программист
|
в дальнейшем я уже не буду пользоваться только своим ПК, и на ПК, где будут рассматривать и проверять эти задания, просто нету OpenServer-а - только Денвер
|
Ознакомтесь с описанием этого сервера - вы его можете установить на свою флешку и запускать с нее. Этот сервер может работать и при запущенном Денвер. Если при запуске он попросит что-либо, то только одно - установку нужных "приблуд" от MVC. Также может потребоваться добавить папку сервера в доверенные в антивирус установленный. Если это затруднительно будет сделать, ну тогда сидите на Денвере. Хотя хозяина этого другого ПК не мешало бы со знанием дела убедить - пора забывать о старье, с ним далеко не уедешь.
То что выше запустить, отправить форму, а затем нажать F5. Если на запрос браузера "Повторить" ответить утвердительно, то в базе появится дубликат предыдущей записи. Это и есть "неприятность", которая может возникнуть при отправлении формы естественным путем, при асинхронном обмене данными между сервером и клиентом такой проблемы не возникает. Не пытайтесь защитится очищением массива $_POST, ибо это браузер повторную отправку производит, а не сервер сам себе шлет данные. Один из способов избежать дубликатов, это сделать перенаправление после приема формы. Здесь перенаправление производится "на саму себя", то есть на ту же самую страницу.
Если при приеме формы были обнаружены ошибки заполнения, то нужно сохранить пришедшие данные, чтобы заполнить ими форму, негоже заставлять пользователя вводить все заново. Хранить эти данные, а также информацию какие поля с ошибками заполнены, можно в сессии. Старт/обновление сессии, а также перенаправление, это передача в браузер заголовков, а вывод заголовков должен производиться до любого вывода в браузер. По этой причине прием и обработка формы определена в самом начале кода страницы (работая с UTF, имея кодировку эту же и на странице, нужно сохранять и код страницы в UTF, и
обязательно без BOM, так как он станет причиной ошибки, ибо будет выводится до заголовков). Хотя можно буферизировать вывод данных до поры до времени, но в данном случае представленная структура проще.
<?
//стартуем/продолжаем сессию
session_start();
$db = new mysqli('localhost', 'root', '', 'test');
$db->set_charset("utf8");
//опции фильтра проверки полей формы
//объявление массивов под версию PHP >= 5.4
//если будет ниже, будут "маты"
$args = [
'surname' => [
'filter' => FILTER_VALIDATE_REGEXP,
'options' => ['regexp' => "/^[а-яё-]{5,32}$/iu"]
],
'name' => [
'filter' => FILTER_VALIDATE_REGEXP,
'options' => ['regexp' => "/^[а-яё]{4,12}$/iu"]
],
'post' => [
'filter' => FILTER_VALIDATE_REGEXP,
'options' => ['regexp' => "/^[а-яё]{5,24}$/iu"]
]
];
//параметры полей формы
$fields = [
'surname' => ['label' => 'Фамилия', 'reg' => '^[а-яёА-ЯЁ-]{5,32}$'],
'name' => ['label' => 'Имя', 'reg' => '^[а-яёА-ЯЁ]{4,12}$'],
'post' => ['label' => 'Должность', 'reg' => '^[а-яёА-ЯЁ]{5,24}$']
];
//если запрос формы, массив $_POST не пуст
if($_POST) {
if(isset($_POST['add'])) { //добавление сотрудника?
//получаем данные формы, удаляя крайние пробелы у значений
$post = array_map('trim', array_slice($_POST, 0, -1));
//фильтруем данные формы
if(!$error = array_filter(filter_var_array($post, $args), function($v) {return !$v;})) {
//если проверка фильтрами не вернула пустых значений, все Ок, то пишем в базу
//подготавливаем запрос, экранированием займется драйвер
$q = $db->prepare("INSERT INTO `employees` (`surname`, `name`, `post`) VALUES (?, ?, ?)");
//привязываем переменные (метки) к данным формы
$q->bind_param("sss", $post['surname'], $post['name'], $post['post']);
//выполняем запрос
$q->execute();
} else $_SESSION['error'] = ['key' => $error, 'post' => array_map('htmlspecialchars', $post)]; //есть ошибки заполнения формы, сохраняем ключи полей с ошибками и данные формы
}
//запрос на удаление?
if(isset($_POST['del']) && $id = (int)$_POST['del']) $db->query("DELETE FROM `employees` WHERE id=$id"); //если id не 0, выполняем запрос
$db->close();
//защита от F5 - сброс POST
header('Location: ' . $_SERVER["PHP_SELF"]);
exit;
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<?
//выборка из таблицы
if($q = $db->query("SELECT * FROM `employees`")) {
if($q->num_rows) { //есть записи, выводим в таблице с возможностью их удаления
?>
<h4>Содержание таблицы Сотрудники</h4>
<form method="post">
<table>
<tr><th>Фамилия</th><th>Имя</th><th>Должность</th><th>Удаление</th></tr>
<?
while($row = $q->fetch_row()) echo '<tr><td>' . implode('</td><td>',array_map('htmlspecialchars', array_slice($row, 1))) .
"</td><td><button type=\"submit\" name=\"del\" value=\"$row[0]\">Удалить</button></td></tr>";
?>
</table>
</form>
<?
} else echo '<p>Таблица Сотрудники не имеет записей</p>';
?>
<h4>Добавление сотрудников</h4>
<!-- Если были ошибки заполнения полей формы, выводим имена этих полей
Версия РНР должна быть не ниже 5.5.0, иначе будет ругаться на функцию array_column -->
<p><?=$_SESSION['error'] ? 'Ошибки заполнения полей: ' . implode(', ', array_column(array_intersect_key($fields, $_SESSION['error']['key']), 'label')) . '!' : null?></p>
<form method="post">
<?
//выводим форму добавления сотрудников, если были ошибки при приеме формы, заполняем поля пришедшими значениями
foreach($fields as $k=>$v):
?>
<input name="<?=$k?>" required="" pattern="<?=$v['reg']?>" placeholder="<?=$v['label']?>" value="<?=$_SESSION['error']['post'][$k]?>" />
<?
endforeach
?>
<button name="add">Добавить</button>
</form>
<?
} else echo 'Ошибка';
//удаляем сохраненные в сессии ошибки
unset($_SESSION['error']);
$db->close();
?>
</body>
</html>
При выводе в браузер (
и только при нем), данные формы возвращаемые клиенту, а также данные из базы обрабатываются функцией htmlspecialchars(), дабы избежать XSS атак на клиенте, и прочих неприятностей. При записи в базу этого делать не стоит.