Лаб. работа “Создание веб-приложений с использованием Slim”
Цель работы
Изучение основ разработки веб-приложений с использованием фреймворка Slim. Освоение навыков создания простых веб-приложений, маршрутизации запросов и работы с шаблонами.
Введение
Slim — это микрофреймворк для PHP, который предназначен для быстрого и простого создания веб-приложений и API. Он минималистичен и предоставляет основные функции, необходимые для разработки, такие как маршрутизация запросов, обработка HTTP-сообщений и внедрение зависимостей.
Оборудование и ПО
- Компьютер с установленной операционной системой (Windows, macOS, Linux).
- Веб-сервер (Apache, Nginx) или встроенный сервер PHP.
- PHP версии 7.2 или выше.
- Composer — менеджер зависимостей для PHP.
- Браузер для тестирования приложений.
Теоретическая часть
- Основы Slim: Slim Framework предоставляет базовую структуру для веб-приложений и API. Его простота делает его идеальным для небольших приложений, где важны производительность и гибкость.
- Маршрутизация: В Slim маршруты определяются с помощью методов GET, POST, PUT и DELETE. Каждый маршрут связан с определенным URI и анонимной функцией, которая обрабатывает запрос.
- Middleware: Middleware позволяет изменять запросы и ответы на этапе их обработки, что удобно для реализации функций аутентификации, логирования и обработки ошибок.
- Внедрение зависимостей: Slim поддерживает внедрение зависимостей через контейнеры, такие как PHP-DI или Pimple.
Практическая часть
1. Установка Slim Framework
Установите Composer, если он еще не установлен.
Создайте новый проект и установите Slim:
2. Создание простого маршрута
В файле
public/index.php
добавьте следующий код:<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $app->get('/hello/{name}', function (Request $request, Response $response, $args) { $name = $args['name']; $response->getBody()->write("Hello, $name"); return $response; }); $app->run();
Запустите встроенный сервер PHP:
Откройте браузер и перейдите по адресу
http://localhost:8080/hello/World
.
3. Добавление Middleware
Добавьте middleware для логирования времени выполнения запросов:
4. Работа с шаблонами:
Установите Twig для работы с шаблонами:
Настройте Twig в
index.php
:use Slim\Views\Twig; use Slim\Views\TwigMiddleware; $app = AppFactory::create(); $twig = Twig::create('../templates', ['cache' => false]); $app->add(TwigMiddleware::create($app, $twig)); $app->get('/greet/{name}', function (Request $request, Response $response, $args) use ($twig) { return $twig->render($response, 'greet.twig', ['name' => $args['name']]); }); $app->run();
Создайте шаблон
templates/greet.twig
:
5. Работа с базой данных
1. Установка и настройка базы данных
Для начала установим и настроим подключение к базе данных MySQL.
Установите MySQL на ваш компьютер, если он еще не установлен.
Создайте базу данных для вашего проекта. Например, назовем её
slim_app
.Создайте таблицу для пользователей в базе данных
slim_app
.Установите зависимости для работы с базой данных через Composer.
2. Настройка подключения к базе данных
Создайте файл .env
в корне вашего проекта и добавьте туда настройки подключения к базе данных.
Обновите файл index.php
, чтобы загрузить переменные окружения и настроить подключение к базе данных.
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use DI\Container;
use Dotenv\Dotenv;
require __DIR__ . '/../vendor/autoload.php';
// Загрузка переменных окружения
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$container = new Container();
AppFactory::setContainer($container);
$container->set('db', function() {
$host = $_ENV['DB_HOST'];
$db = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$pass = $_ENV['DB_PASS'];
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
return new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
});
$app = AppFactory::create();
$app->get('/users', function (Request $request, Response $response, $args) {
$db = $this->get('db');
$stmt = $db->query('SELECT * FROM users');
$users = $stmt->fetchAll();
$response->getBody()->write(json_encode($users));
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();
3. Создание маршрута для добавления нового пользователя
Создайте форму для добавления нового пользователя и маршрут для обработки этой формы.
Добавьте шаблон формы
add_user.twig
в папкуtemplates
.<!DOCTYPE html> <html> <head> <title>Add User</title> </head> <body> <h1>Add New User</h1> <form action="/add_user" method="post"> <label for="name">Name:</label> <input type="text" id="name" name="name"> <label for="email">Email:</label> <input type="email" id="email" name="email"> <button type="submit">Add User</button> </form> </body> </html>
Обновите файл
index.php
, чтобы добавить маршрут для отображения формы и обработки данных из формы.$app->get('/add_user', function (Request $request, Response $response, $args) use ($twig) { return $twig->render($response, 'add_user.twig'); }); $app->post('/add_user', function (Request $request, Response $response, $args) { $data = $request->getParsedBody(); $name = $data['name']; $email = $data['email']; $db = $this->get('db'); $stmt = $db->prepare('INSERT INTO users (name, email) VALUES (:name, :email)'); $stmt->execute(['name' => $name, 'email' => $email]); return $response->withHeader('Location', '/users')->withStatus(302); });
6. Реализация API для работы с данными
1. Подготовка базы данных
Для начала, убедитесь, что у вас уже создана таблица пользователей. Если нет, создайте её в базе данных slim_app
.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
2. Обновление конфигурации Slim
Внесите следующие изменения в index.php
, чтобы добавить маршруты для API:
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use DI\Container;
use Dotenv\Dotenv;
require __DIR__ . '/../vendor/autoload.php';
// Загрузка переменных окружения
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$container = new Container();
AppFactory::setContainer($container);
$container->set('db', function() {
$host = $_ENV['DB_HOST'];
$db = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$pass = $_ENV['DB_PASS'];
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
return new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
});
$app = AppFactory::create();
// Получение всех пользователей
$app->get('/api/users', function (Request $request, Response $response, $args) {
$db = $this->get('db');
$stmt = $db->query('SELECT * FROM users');
$users = $stmt->fetchAll();
$response->getBody()->write(json_encode($users));
return $response->withHeader('Content-Type', 'application/json');
});
// Получение пользователя по ID
$app->get('/api/users/{id}', function (Request $request, Response $response, $args) {
$id = $args['id'];
$db = $this->get('db');
$stmt = $db->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
$user = $stmt->fetch();
if ($user) {
$response->getBody()->write(json_encode($user));
return $response->withHeader('Content-Type', 'application/json');
} else {
$response->getBody()->write(json_encode(['message' => 'User not found']));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
}
});
// Создание нового пользователя
$app->post('/api/users', function (Request $request, Response $response, $args) {
$data = $request->getParsedBody();
$name = $data['name'];
$email = $data['email'];
$db = $this->get('db');
$stmt = $db->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute(['name' => $name, 'email' => $email]);
$user = [
'id' => $db->lastInsertId(),
'name' => $name,
'email' => $email
];
$response->getBody()->write(json_encode($user));
return $response->withStatus(201)->withHeader('Content-Type', 'application/json');
});
// Обновление пользователя по ID
$app->put('/api/users/{id}', function (Request $request, Response $response, $args) {
$id = $args['id'];
$data = $request->getParsedBody();
$name = $data['name'];
$email = $data['email'];
$db = $this->get('db');
$stmt = $db->prepare('UPDATE users SET name = :name, email = :email WHERE id = :id');
$stmt->execute(['name' => $name, 'email' => $email, 'id' => $id]);
$user = [
'id' => $id,
'name' => $name,
'email' => $email
];
$response->getBody()->write(json_encode($user));
return $response->withHeader('Content-Type', 'application/json');
});
// Удаление пользователя по ID
$app->delete('/api/users/{id}', function (Request $request, Response $response, $args) {
$id = $args['id'];
$db = $this->get('db');
$stmt = $db->prepare('DELETE FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
$response->getBody()->write(json_encode(['message' => 'User deleted']));
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();
3. Тестирование API
Теперь, когда все маршруты настроены, вы можете протестировать их с помощью инструмента Postman или curl. Вот несколько примеров запросов:
Получение всех пользователей:
Получение пользователя по ID:
Создание нового пользователя:
Обновление пользователя по ID:
Удаление пользователя по ID:
7. Реализация аутентификации
1. Подготовка базы данных
Для начала, добавим таблицу пользователей в базу данных slim_app
, которая будет включать поля для имени, электронной почты и пароля.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
2. Настройка конфигурации Slim
Убедитесь, что ваш файл index.php
настроен для подключения к базе данных и добавьте маршруты для регистрации и авторизации пользователей.
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use DI\Container;
use Dotenv\Dotenv;
use Slim\Middleware\SessionMiddleware;
require __DIR__ . '/../vendor/autoload.php';
// Загрузка переменных окружения
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$container = new Container();
AppFactory::setContainer($container);
$container->set('db', function() {
$host = $_ENV['DB_HOST'];
$db = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$pass = $_ENV['DB_PASS'];
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
return new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
});
$app = AppFactory::create();
// Middleware для работы с сессиями
$app->add(SessionMiddleware::class);
// Регистрация пользователя
$app->post('/register', function (Request $request, Response $response, $args) {
$data = $request->getParsedBody();
$name = $data['name'];
$email = $data['email'];
$password = password_hash($data['password'], PASSWORD_DEFAULT);
$db = $this->get('db');
$stmt = $db->prepare('INSERT INTO users (name, email, password) VALUES (:name, :email, :password)');
$stmt->execute(['name' => $name, 'email' => $email, 'password' => $password]);
$response->getBody()->write(json_encode(['message' => 'User registered successfully']));
return $response->withHeader('Content-Type', 'application/json');
});
// Авторизация пользователя
$app->post('/login', function (Request $request, Response $response, $args) {
$data = $request->getParsedBody();
$email = $data['email'];
$password = $data['password'];
$db = $this->get('db');
$stmt = $db->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
$response->getBody()->write(json_encode(['message' => 'Login successful']));
} else {
$response->getBody()->write(json_encode(['message' => 'Invalid email or password']));
return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
}
return $response->withHeader('Content-Type', 'application/json');
});
// Middleware для проверки аутентификации
$authenticate = function (Request $request, RequestHandler $handler) {
if (!isset($_SESSION['user_id'])) {
$response = new \Slim\Psr7\Response();
$response->getBody()->write(json_encode(['message' => 'Unauthorized']));
return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
}
return $handler->handle($request);
};
// Пример защищенного маршрута
$app->get('/profile', function (Request $request, Response $response, $args) {
$response->getBody()->write(json_encode([
'user_id' => $_SESSION['user_id'],
'user_name' => $_SESSION['user_name']
]));
return $response->withHeader('Content-Type', 'application/json');
})->add($authenticate);
$app->run();
3. Создание шаблонов для регистрации и авторизации
Добавьте следующие шаблоны в папку templates
для страниц регистрации и авторизации.
register.twig
:
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
</head>
<body>
<h1>Register</h1>
<form action="/register" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<label for="email">Email:</label>
<input type="email" id="email" name="email">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<button type="submit">Register</button>
</form>
</body>
</html>
login.twig
:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form action="/login" method="post">
<label for="email">Email:</label>
<input type="email" id="email" name="email">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<button type="submit">Login</button>
</form>
</body>
</html>
4. Настройка маршрутов для отображения страниц регистрации и авторизации
Обновите index.php
, чтобы добавить маршруты для отображения форм регистрации и авторизации.
$app->get('/register', function (Request $request, Response $response, $args) use ($twig) {
return $twig->render($response, 'register.twig');
});
$app->get('/login', function (Request $request, Response $response, $args) use ($twig) {
return $twig->render($response, 'login.twig');
});
5. Тестирование аутентификации
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать регистрацию и авторизацию пользователей.
- Откройте браузер и перейдите по адресу
http://localhost:8080/register
, чтобы зарегистрировать нового пользователя. - Перейдите по адресу
http://localhost:8080/login
, чтобы авторизоваться. - После успешной авторизации вы можете получить доступ к защищенному маршруту
http://localhost:8080/profile
.
8. Интеграция с внешним API OpenWeatherMap
1. Регистрация и получение API ключа
- Перейдите на сайт OpenWeatherMap и зарегистрируйтесь, чтобы получить API ключ.
- Сохраните свой API ключ, он понадобится для запросов к API.
2. Настройка конфигурации Slim
Добавьте ваш API ключ в файл .env
.
3. Установка GuzzleHTTP
GuzzleHTTP — это PHP HTTP-клиент, который мы будем использовать для отправки запросов к API OpenWeatherMap.
4. Создание шаблона для отображения данных о погоде
Добавьте следующий шаблон в папку templates
для отображения данных о погоде.
weather.twig
:
<!DOCTYPE html>
<html>
<head>
<title>Weather</title>
</head>
<body>
<h1>Weather in {{ city }}</h1>
{% if weather %}
<p>Temperature: {{ weather.main.temp }} °C</p>
<p>Weather: {{ weather.weather[0].description }}</p>
{% else %}
<p>{{ error }}</p>
{% endif %}
</body>
</html>
5. Настройка маршрута для отображения данных о погоде
Обновите index.php
, чтобы добавить маршрут для отображения данных о погоде на странице.
$app->get('/weather/{city}', function (Request $request, Response $response, $args) use ($twig) {
$city = $args['city'];
$apiKey = $_ENV['WEATHER_API_KEY'];
$url = "http://api.openweathermap.org/data/2.5/weather?q={$city}&appid={$apiKey}&units=metric";
$client = new \GuzzleHttp\Client();
try {
$apiResponse = $client->get($url);
$data = json_decode($apiResponse->getBody(), true);
return $twig->render($response, 'weather.twig', [
'city' => $city,
'weather' => $data
]);
} catch (\Exception $e) {
return $twig->render($response, 'weather.twig', [
'city' => $city,
'error' => 'Unable to fetch weather data'
]);
}
});
6. Тестирование интеграции с внешним API
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать интеграцию с внешним API.
- Откройте браузер и перейдите по адресу
http://localhost:8080/weather/London
, чтобы увидеть текущую погоду в Лондоне.
9. Интеграция с API Nominatim
1. Настройка конфигурации Slim
Обновите файл index.php
, чтобы добавить маршруты для получения координат города с использованием API Nominatim и получения данных о погоде с использованием API OpenWeatherMap.
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use DI\Container;
use Dotenv\Dotenv;
use Slim\Middleware\SessionMiddleware;
require __DIR__ . '/../vendor/autoload.php';
// Загрузка переменных окружения
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$container = new Container();
AppFactory::setContainer($container);
$container->set('db', function() {
$host = $_ENV['DB_HOST'];
$db = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$pass = $_ENV['DB_PASS'];
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
return new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
});
$app = AppFactory::create();
$app->add(SessionMiddleware::class);
// Маршруты регистрации и авторизации (как было описано ранее)
// Получение данных о погоде с использованием API Nominatim и OpenWeatherMap
$app->get('/weather/{city}', function (Request $request, Response $response, $args) {
$city = $args['city'];
$weatherApiKey = $_ENV['WEATHER_API_KEY'];
$nominatimUrl = "https://nominatim.openstreetmap.org/search?q={$city}&format=json&limit=1";
$client = new \GuzzleHttp\Client();
try {
// Запрос к Nominatim API для получения координат города
$nominatimResponse = $client->get($nominatimUrl);
$locationData = json_decode($nominatimResponse->getBody(), true);
if (empty($locationData)) {
$response->getBody()->write(json_encode(['error' => 'City not found']));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
}
$latitude = $locationData[0]['lat'];
$longitude = $locationData[0]['lon'];
// Запрос к OpenWeatherMap API для получения данных о погоде по координатам
$weatherUrl = "http://api.openweathermap.org/data/2.5/weather?lat={$latitude}&lon={$longitude}&appid={$weatherApiKey}&units=metric";
$weatherResponse = $client->get($weatherUrl);
$weatherData = json_decode($weatherResponse->getBody(), true);
$response->getBody()->write(json_encode($weatherData));
return $response->withHeader('Content-Type', 'application/json');
} catch (\Exception $e) {
$response->getBody()->write(json_encode(['error' => 'Unable to fetch weather data']));
return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
}
});
$app->run();
2. Тестирование интеграции с внешним API
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать интеграцию с внешним API.
- Откройте браузер и перейдите по адресу
http://localhost:8080/weather/London
, чтобы увидеть текущую погоду в Лондоне.