Лабораторная работа №5

Ознакомиться с главой 12 в Никсон Р. – Создаем динамические сайты с помощью PHP, MySQL, JavaScript, CDD и HTML5, 6-е изд. Ознакомиться с главой 5 в Люк Веллинг, Лора Томсон – Разработка web-приложений с помощью PHP и MySQL (4 издание).

Задание 1

Сделать два php-скрипта. Первый выводит форму для ввода входных данных, а второй обрабатывает эти данные и форматирует результат. Объединить скрипты в один, который в случае получения данных занимается обработкой, без них выводит начальную форму, а при неправильных данных выводит начальную форму с этими данными и указанием на ошибку.

Пример выполнения задания 1

Сделать два php-скрипта. Первый выводит форму для ввода входных данных, а второй обрабатывает эти данные и форматирует результат. (Объединить скрипты в один – самостоятельно).

Табулирование таблицы умножения от двух целочисленных аргументов с цветовым выделением ячеек, подходящих под условие:

Входные данные:

  • число строк и столбцов: n, m (не считая наименования строк и столбцов);
  • применяемые условия для выделения накладываются установкой флажков:
    • фон для четных чисел,
    • фон для нечетных чисел,
    • цвет текста для чисел равных k, вводимому в форме,
    • полужирное выделение для чисел, больших n*m/2.

Шаг 1. Создание формы

Создайте страницу с формой для ввода всех необходимых данных.

form

В атрибуте action тега <form> укажите имя скрипта, который будет обрабатывать данные формы, а в атрибуте method – метод передачи данных. Для упрощения разработки можно выбрать метод GET, но предпочтительнее POST.

<form action="task1.php" method="POST">

</form>

Каждую пару тегов <label> и <input> можно поместить в отдельный <div>. Для тегов <input> задайте атрибуты id и name: первый позволит идентифицировать их в рамках html страницы, а второй будет служить для получения значения в php-скрипте. У тега <label> используйте атрибут for, указав в нём id соответствующего ему <input>, чтобы можно было активировать этот <input> по нажатию на <label>.

<div>
    <label for="n">Число строк n</label>
    <input type="number" value="10" id="n" name="n" />
</div>

Для отправки формы применяется <input type="submit" /> или <button>Отправить</button>.

Шаг 2. Получение данных в php-скрипте

Напишите скрипт для проверки того, какие данные приходят из формы. Для начала можно вывести содержимое массива $_POST с помощью функции print_r() или var_dump().

<?php
var_dump($_POST); 
?>

var_damp

Далее удобно скопировать значения из массива $_POST в отдельные переменные. Одновременно с этим можно выполнить преобразования в нужные типы данных, что можно сделать различными способами. Примеры представлены в следующем коде.

<?php

$n = (int)$_POST["n"];
$m = (int)$_POST["m"];
$option1 = isset($_POST["option1"]) ? (bool)$_POST["option1"] : false;
$option2 = isset($_POST["option2"]) ? true : false;
$option3 = isset($_POST["option3"]) ? 1 : 0;
$option4 = isset($_POST["option4"]);

echo $n * $m . "<br>";
if ($option1) echo "Выбрана опция 1<br>";
if ($option2) echo "Выбрана опция 2<br>";
if ($option3)
{
    $k = (int)$_POST["option3_k"];
    echo "Выбрана опция 3, k=$k<br>";
}
if ($option4) echo "Выбрана опция 4<br>";

?>

echo_post

Замечание. Для значений n и m здесь следует добавить проверки с помощью функции isset(). Если их значения не установлены, то нужно вывести сообщение об этом. Если значения установлены, но преобразование в нужный тип данных не получается выполнить, то нужно вывести сообщение и об этом.

Шаг 3. Обработка данных

Далее, пользуясь вложенными циклами, можно произвести нужные вычисления.

for ($row = 1; $row <= $n; $row++)
{
    for ($column = 1; $column <= $m; $column++)
    {
        $result = $row * $column;
    }
}

И сразу же оформить полученные результаты в виде таблицы.

echo "<table>";
for ($row = 1; $row <= $n; $row++)
{
    echo "<tr>";
    for ($column = 1; $column <= $m; $column++)
    {
        $result = $row * $column;
        echo "<td>" . $result . "</td>";
    }
    echo "</tr>";
}
echo "</table>";

Используйте стили и теги <th>, <tbody>, чтобы оформить таблицу.

table

Шаг 4. Проверка условий и применение классов

Для условий нужно реализовать css-классы. Так как предполагается применять их только к ячейкам таблицы, можно использовать составной селектор, состоящий из названия тега и названия класса.

td.odd {
    background-color: lightblue;
}

td.even {
    background-color: lightcoral;
}

td.equal_k {
    color: darkgreen;
}

td.big {
    font-weight: bold;
}

Для каждой ячейки нужно добавить проверки: включена ли определённая опция и выполняются ли соответствующие условия для рассчитанного значения. Таким образом определяются css-классы, назначаемые ячейке. Классы можно добавлять в массив (в данном случае, работающий как List<string> в C#), для этого используется непривычный синтаксис. Для формирования из массива общей строки с классами можно применить функцию implode (по сути, аналог метода Join() в C#).

        for ($column = 1; $column <= $m; $column++) {
            $result = $row * $column;

            $classes = array();
            if ($option1 && ($result % 2 == 0))          $classes[] = 'even';
            if ($option2 && ($result % 2 == 1))          $classes[] = 'odd';
            if ($option3 && isset($k) && $result == $k)  $classes[] = 'equal_k';
            if ($option4 && ($result > $n*$m/2))         $classes[] = 'big';

            echo "<td class='" . implode(" ", $classes) . "'>" . $result . "</td>";
        }

table_color

Самостоятельно

Объединить скрипты в один, который в случае получения данных занимается обработкой, без них выводит начальную форму, а при неправильных данных выводит начальную форму с этими данными и указанием на ошибку.

Варианты для задания 1

Варианты 1-4. Табулирование функции от двух целочисленных аргументов с цветовым выделением ячеек, подходящих под выбранное условие.

Входные данные:

  • число строк и столбцов: n, m (не считая наименования строк и столбцов);
  • условие в виде: v, k, где v – операция сравнения (<, ≤, =, >, ≥), k – число для сравнения.

Вариант 1. Функция f(x, y) = (2 * x + y) mod 10.

Вариант 2. Функция f(x, y) = (x * x + 5 * y) mod 16.

Вариант 3. Функция f(x, y) = (5 * x + y * y * y) mod 24.

Вариант 4. Функция f(x, y) = (x + 2 * y + 3) mod 12.

Варианты 5-8. Табулирование функции от двух целочисленных аргументов с цветовым выделением категорий ячеек.

Входные данные:

  • диапазоны изменения аргументов: x1, x2, y1, y2;
  • цвета для категорий: c1, c2, c3, c4.

Вариант 5. Функция f(x, y) = (2 * x) mod 5 + (y * y) mod 4, категории: f=0, 1≤f≤3, 4≤f≤6, f=7.

Вариант 6. Функция f(x, y) = (x * x + y) mod 10, категории: 0≤f≤2, 3≤f≤5, 6≤f≤8, 9≤f≤10.

Вариант 7. Функция f(x, y) = (x + 3 * y), для получения категорий найти разность между максимальным и минимальным значением f (на заданных интервалах) и разбить его на 4 равные части.

Вариант 8. Функция f(x, y) = (x - y + 3), категории: f – четное отрицательное; f – нечетное положительное; f – ноль; остальные значения f.

Задание 2

Выбрать для сайта макет (с верхней частью, двумя или тремя колонками с адаптивной шириной и с нижней частью). Реализовать его для одной из страниц сайта первой лабораторной работы. Далее разбить на части, из которых будут формироваться страницы в едином стиле (используя функции и операторы вроде require()).

makets

Суть в том, чтобы при необходимости внести изменение в меню или верхний/нижний колонтитул, было достаточно изменить код в одном месте.

Для каждой страницы сайта из первой лабораторной работы сделать php-скрипт, генерирующий её с использованием реализованных функций, отвечающих за отдельные части страниц.

В скриптах, генерирующих страницу с набором однотипных объектов и страницу с таблицей, создавать однотипные конструкции (карточка объекта или строка в таблице) следует с помощью цикла, который перебирает элементы некоторого заготовленного многомерного массива с данными тех объектов (возможно объекты даже будут представлены php-объектами).

Пример выполнения задания 2

Возьмём код резинового двухколоночного макета с сайте htmlbook.ru. Выделим в нём стили в отдельный файл и удалим свойства, ограничивающие ширину основного блока.

.header,
.sidebar,
.content,
.footer {
    padding: 10px; /* Поля */
    border: solid 1px #000; /* Параметры рамки */
    background: #e3e8cc; /* Цвет фона */
}
.header {
    /* Верхняя часть с заголовком */
    background: #e3e8cc; /* Цвет фона */
    font-size: 24px; /* Размер шрифта */
}
.layout {
    margin: 15px 0; /* Отступы сверху и снизу */
    overflow: hidden; /* Отменяем действие float */
    /*min-width: 800px; /* Минимальная ширина */
    /*max-width: 1200px; /* Максимальная ширина */
}
.sidebar {
    /* Навигация по сайту */
    width: 100px; /* Ширина меню */
    float: left; /* Состыковка с другим слоем по горизонтали */
}
.sidebar ul {
    list-style: none; /* Убираем маркеры */
    padding: 0; /* Убираем отступы */
}
.content {
    /* Основное содержание страницы */
    margin-left: 135px; /* Отступ слева */
}

Код основной страницы поместим php файл.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Лабораторная работа №4</title>
    <link href="task2.css" rel="stylesheet">
</head>

<body>
    <div class="header">Заголовок сайта</div>
    <div class="layout">
        <div class="sidebar">
            <h2>Меню</h2>
            <ul>
                <li><a href="link1.html">Ссылка 1</a></li>
                <li><a href="link2.html">Ссылка 2</a></li>
                <li><a href="link3.html">Ссылка 3</a></li>
                <li><a href="link4.html">Ссылка 4</a></li>
            </ul>
        </div>
        <div class="content">
            <h1>Название страницы</h1>
            <p>Бла-бла.</p>
            <p>Бла-бла.</p>
            <p>Бла-бла.</p>
        </div>
    </div>
    <div class="footer">Подвал</div>
</body>

</html>

Проверим как будет выглядеть страница в браузере. Можно добавить в неё больше содержимого (в Visual Studio Code для генерации случайного текста можно написать "Lorem100", где число – это количество слов в этом тексте, и нажать Enter).

maket_with_2_column

Не лучший макет, недостаточно адаптивный, но для изучения темы подойдет.

Далее нужно разделить код страницы на несколько частей, для генерации каждой из которых будет использоваться отдельная php-функция или даже отдельный php-файл. Выполним разбиение так, как предлагается в книге Люк Веллинг, Лора Томсон – Разработка web-приложений с помощью PHP и MySQL в главе 5. То есть выделим основное содержимое и то, что идет перед/после него.

<!DOCTYPE html>
<html lang="en">

<!— Здесь сократим код, так как он есть выше -->

                <li><a href="link4.html">Ссылка 4</a></li>
            </ul>
        </div>
        <div class="content">
            <h1>Название страницы</h1>
            <p>Бла-бла.</p>
            <p>Бла-бла.</p>
            <p>Бла-бла.</p>
        </div>
    </div>
    <div class="footer">Подвал</div>
</body>

</html>

Создадим файл functions.php и создадим в нём функции, которые будут формировать верхнюю часть сайта и нижнюю часть сайта, причем рассмотрим два способа сделать это.

<?php

function makeHeader()
{
?>
    <!DOCTYPE html>
    <html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Лабораторная работа №4</title>
        <link href="task2.css" rel="stylesheet">
    </head>

    <body>
        <div class="header">Заголовок сайта</div>
        <div class="layout">
            <div class="sidebar">
                <h2>Меню</h2>
                <ul>
                    <li><a href="link1.html">Ссылка 1</a></li>
                    <li><a href="link2.html">Ссылка 2</a></li>
                    <li><a href="link3.html">Ссылка 3</a></li>
                    <li><a href="link4.html">Ссылка 4</a></li>
                </ul>
            </div>
            <div class="content">

<?php
}

function makeFooter()
{
    echo <<< END
        </div>
    </div>
    <div class="footer">Подвал</div>
</body>

</html>
END;
}

?>

Здесь в функции makeHeader() закрывается тег php и далее следует обычный html-код, который в таком виде и попадёт в результирующую страницу. То есть он всё ещё находится внутри функции. А в функции makeFooter() используется специальный синтаксис, позволяющий передать в оператор echo многострочный текст. Вместо слова END можно использовать что-нибудь другое, причем закрывающее слово должно располагаться в начале строки.

В основном коде мы подключаем описанный выше файл с помощью функции require_once(), а затем вызываем методы в нужных местах. Таким образом нужно оформить все страницы своего сайта, чтобы они генерировали верхнюю и нижнюю часть с помощью функций, а основной контент был бы в каждом сайте своим собственным.

<?php
require_once("functions.php");
makeHeader();
?>

<h1>Название страницы</h1>
<p>Lorem ipsum dolor sit amet.</p>
<p>Lorem ipsum dolor sit.</p>
<p>Lorem ipsum dolor sit amet consectetur.</p>

<?php
makeFooter();
?> 

Помимо этого, хотелось бы, чтобы у каждой страницы был свой заголовок (который в теге <title>). Можно передавать его в функцию makeHeader() в виде параметра.

Ещё можно сделать так, чтобы один из пунктов меню (соответствующий открытой странице) становился бы неактивным – это поможет пользователю сайта ориентироваться, на какой он странице находится. Это тоже можно сделать путём передачи параметра.

Задание 3

Для формы обратной связи сделать скрипт, который будет сохранять присланное сообщение в файл (добавлять в него). Добавить страницу, которая будет выводить все присланные сообщения.

Задание 4

Переместить описания объектов в файл (csv, json или xml), чтобы скрипты получали их оттуда.

Задание 5

Для формы добавления объектов сделать скрипт, с помощью которого можно будет добавлять новые объекты в файл с объектами.

Проверочные вопросы

Приведенный ниже скрипт выводит некоторую информацию из файла config.json и позволяет изменять её. Объясните, почему этот код не будет работать так, как от него ожидается?

<?php // скрипт config.php
$configFile = 'config.json';

// Загрузка конфигурации
$config = json_decode(file_get_contents($configFile), true);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Обновление конфигурации
    if (isset($_POST['width']) && isset($_POST['height']) && isset($_POST['napkins'])) {
        $config['screen_resolution']['width'] = (int)$_POST['width'];
        $config['screen_resolution']['height'] = (int)$_POST['height'];
        $config['napkins'] = isset($_POST['napkins']) ? true : false;

        file_put_contents($configFile, json_encode($config, JSON_PRETTY_PRINT));
        header('Location: config.php'); // Перенаправляем обратно после обновления
        exit;
    }
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>Настройки</title>
</head>
<body>
    <h1>Редактирование настроек</h1>
    <form method="POST">
        <label>Ширина экрана:</label>
        <input type="number" name="width" value="<?php echo $config['screen_resolution']['width']; ?>" required>
        <br>
        <label>Высота экрана:</label>
        <input type="number" name="height" value="<?php echo $config['screen_resolution']['height']; ?>" required>
        <br>
        <label>Кувертки:</label>
        <input type="checkbox" name="napkins" <?php echo $config['napkins'] ? 'checked' : ''; ?>>
        <br>
        <button type="submit">Сохранить настройки</button>
    </form>

    <p><a href="index.php">Вернуться на главную</a></p>
</body>
</html>