Flight - быстрый, простой, расширяемый фреймворк для PHP. Он очень универсален и может использоваться для создания любого веб-приложения. Он создан с учетом простоты в использовании и написан так, что легко понять и использовать.
Вот небольшая статья о том, почему вам следует использовать фреймворк. Это хорошая идея понимать преимущества использования фреймворка перед тем, как начать его использовать.
Кроме того, отличное руководство было создано пользователем @lubiana. Хотя в нем не подробно рассматривается Flight, это руководство поможет вам понять некоторые основные концепции, касающиеся фреймворка и почему их полезно использовать. Вы можете найти учебник здесь.
Если вы переходите с другого фреймворка, такого как Laravel, Slim, Fat-Free или Symfony на Flight, эта страница поможет вам понять различия между ними.
Научитесь автоматически загружать ваши собственные классы в вашем приложении.
Научитесь управлять маршрутами для вашего веб-приложения. Это также включает группировку маршрутов, параметры маршрута и промежуточное ПО.
Научитесь использовать промежуточное ПО для фильтрации запросов и ответов в вашем приложении.
Научитесь обрабатывать запросы и ответы в вашем приложении.
Научитесь отправлять ответы вашим пользователям.
Научитесь использовать встроенный движок для отображения ваших HTML шаблонов.
Научитесь обезопасить ваше приложение от распространенных угроз безопасности.
Научитесь настраивать фреймворк для вашего приложения.
Научитесь расширять фреймворк, добавляя собственные методы и классы.
Научитесь использовать систему событий для добавления хуков к вашим методам и внутренним методам фреймворка.
Научитесь использовать контейнеры внедрения зависимостей (DIC), чтобы управлять зависимостями вашего приложения.
Узнайте о основных методах фреймворка.
Совместимость с предыдущими версиями в целом сохранена, но есть некоторые изменения, о которых вам следует знать, переходя с v2 на v3.
Есть некоторые общие проблемы, с которыми вы можете столкнуться при использовании Flight. Эта страница поможет вам устранить эти проблемы.
Вы можете остановить фреймворк в любой момент, вызвав метод halt:
halt
Flight::halt();
Вы также можете указать необязательный HTTP код состояния и сообщение:
HTTP
Flight::halt(200, 'Сейчас вернусь...');
Вызов halt приведет к отмене любого содержимого ответа до этого момента. Если вы хотите остановить фреймворк и вывести текущий ответ, используйте метод stop:
stop
Flight::stop();
Все ошибки и исключения перехватываются Flight и передаются методу error. Поведение по умолчанию - отправлять общий ответ HTTP 500 Внутренняя Ошибка Сервера с некоторой информацией об ошибке.
error
HTTP 500 Внутренняя Ошибка Сервера
Вы можете переопределить это поведение для ваших собственных потребностей:
Flight::map('error', function (Throwable $error) { // Обработать ошибку echo $error->getTraceAsString(); });
По умолчанию ошибки не записываются в журнал веб-сервера. Вы можете включить это, изменив конфигурацию:
Flight::set('flight.log_errors', true);
Когда URL не может быть найден, Flight вызывает метод notFound. Поведение по умолчанию - отправить ответ HTTP 404 Не Найдено с простым сообщением.
notFound
HTTP 404 Не Найдено
Flight::map('notFound', function () { // Обработать не найдено });
Laravel - это полнофункциональный фреймворк с множеством функций и удивительной экосистемой, но это отражается на производительности и сложности. Цель Laravel - обеспечить разработчику наивысший уровень продуктивности и упростить выполнение общих задач. Laravel отличный выбор для разработчиков, которые стремятся создать полнофункциональное корпоративное веб-приложение. Однако это связано с определенными компромиссами, особенно в плане производительности и сложности. Начать работу с Laravel легко, но для освоения фреймворка потребуется некоторое время.
Часто разработчики чувствуют, что единственный способ решить проблемы в Laravel - использовать модули, в то время как на самом деле можно просто использовать другую библиотеку или написать свой собственный код.
Обратная совместимость в целом была сохранена, но есть некоторые изменения, о которых вам следует знать при переходе с v2 на v3.
Буферизация вывода - это процесс, при котором вывод, сгенерированный сценарием PHP, хранится в буфере (внутри PHP) перед отправкой клиенту. Это позволяет вам изменять вывод перед его отправкой клиенту.
В приложении MVC Контроллер является "менеджером" и управляет тем, что делает представление. Генерация вывода за пределами контроллера (или в случае Flight иногда анонимной функции) нарушает шаблон MVC. Это изменение призвано больше соответствовать шаблону MVC и сделать фреймворк более предсказуемым и легким в использовании.
В v2 буферизация вывода обрабатывалась таким образом, что не всегда закрывался собственный буфер вывода, что затрудняло unit тестирование и потоковую передачу. Для большинства пользователей это изменение на самом деле может вас не затронуть. Однако, если вы выводите содержимое вне вызываемых функций и контроллеров (например, в хуке), вам, скорее всего, придется столкнуться с проблемами. Вывод содержимого в хуках и до фактического выполнения фреймворка мог работать в прошлом, но это не сработает в будущем.
// index.php require 'vendor/autoload.php'; // просто пример define('START_TIME', microtime(true)); function hello() { echo 'Привет, мир'; } Flight::map('hello', 'hello'); Flight::after('hello', function(){ // это на самом деле будет хорошо echo '<p>Эта фраза Привет, мир была предоставлена буквой "П"</p>'; }); Flight::before('start', function(){ // такие вещи вызовут ошибку echo '<html><head><title>Моя страница</title></head><body>'; }); Flight::route('/', function(){ // это на самом деле в порядке echo 'Привет, мир'; // Это тоже должно быть в порядке Flight::hello(); }); Flight::after('start', function(){ // это вызовет ошибку echo '<div>Ваша страница загрузилась за '.(microtime(true) - START_TIME).' секунд</div></body></html>'; });
Можно ли сохранить ваш старый код без переписывания, чтобы он работал с v3? Да, вы можете! Вы можете включить поведение рендеринга v2, установив параметр конфигурации flight.v2.output_buffering в значение true. Это позволит вам продолжать использовать старое поведение рендеринга, но рекомендуется исправить его на будущее. В v4 фреймворка это будет удалено.
flight.v2.output_buffering
true
// index.php require 'vendor/autoload.php'; Flight::set('flight.v2.output_buffering', true); Flight::before('start', function(){ // Теперь это будет в порядке echo '<html><head><title>Моя страница</title></head><body>'; }); // еще код
Если вы напрямую вызывали статические методы для Dispatcher, такие как Dispatcher::invokeMethod(), Dispatcher::execute(), и т.д., вам потребуется обновить ваш код, чтобы не вызывать эти методы напрямую. Dispatcher был преобразован в более объектно-ориентированный для удобства использования контейнеров внедрения зависимостей. Если вам нужно вызвать метод аналогично тому, как делал Диспетчер, вы можете вручную использовать что-то вроде $result = $class->$method(...$params); или call_user_func_array() вместо этого.
Dispatcher
Dispatcher::invokeMethod()
Dispatcher::execute()
$result = $class->$method(...$params);
call_user_func_array()
halt()
stop()
redirect()
error()
Поведение по умолчанию до версии 3.10.0 заключалось в очистке как заголовков, так и тела ответа. Это было изменено на очистку только тела ответа. Если вам нужно очистить также заголовки, вы можете использовать Flight::response()->clear().
Flight::response()->clear()
Вы можете настроить определенные поведения Flight, установив значения конфигурации через метод set.
set
Ниже приведен список всех доступных параметров конфигурации:
?string
bool
string
Content-Length
Существует еще один параметр конфигурации для загрузчика. Это позволит вам автоматически загружать классы с _ в имени класса.
_
// Включить загрузку классов с подчеркиваниями // Установлено по умолчанию в true Loader::$v2ClassLoading = false;
Flight позволяет вам сохранять переменные, чтобы их можно было использовать в любом месте вашего приложения.
// Сохраните вашу переменную Flight::set('id', 123); // В другом месте в вашем приложении $id = Flight::get('id');
Чтобы проверить, была ли установлена переменная, вы можете сделать следующее:
if (Flight::has('id')) { // Сделайте что-то }
Вы можете очистить переменную, сделав следующее:
// Очищает переменную id Flight::clear('id'); // Очистить все переменные Flight::clear();
Flight также использует переменные в целях конфигурации.
Все ошибки и исключения перехватываются Flight и передаются методу error. По умолчанию выполняется отправка общего ответа HTTP 500 Internal Server Error с некоторой информацией об ошибке.
HTTP 500 Internal Server Error
Вы можете изменить это поведение под свои нужды:
По умолчанию ошибки не регистрируются на веб-сервере. Вы можете включить это, изменив конфигурацию:
Когда URL не найден, Flight вызывает метод notFound. По умолчанию выполняется отправка ответа HTTP 404 Not Found с простым сообщением.
HTTP 404 Not Found
Flight::map('notFound', function () { // Обработать не найденный });
Безопасность - это серьезное дело, когда речь идет о веб-приложениях. Вы хотите быть уверены, что ваше приложение безопасно и данные ваших пользователей защищены. Flight предоставляет ряд функций, чтобы помочь вам обеспечить безопасность ваших веб-приложений.
HTTP заголовки - один из самых простых способов защитить ваши веб-приложения. Вы можете использовать заголовки, чтобы предотвратить clickjacking, XSS и другие атаки. Есть несколько способов, как можно добавить эти заголовки к вашему приложению.
Два отличных сайта, на которых можно проверить безопасность ваших заголовков, это securityheaders.com и observatory.mozilla.org.
Вы можете вручную добавить эти заголовки, используя метод 'header' объекта Flight\Response.
Flight\Response
// Установить заголовок X-Frame-Options для предотвращения clickjacking Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); // Установить заголовок Content-Security-Policy для предотвращения XSS // Примечание: этот заголовок может быть очень сложным, так что вам понадобится // обращаться к примерам в интернете для вашего приложения Flight::response()->header("Content-Security-Policy", "default-src 'self'"); // Установить заголовок X-XSS-Protection для предотвращения XSS Flight::response()->header('X-XSS-Protection', '1; mode=block'); // Установить заголовок X-Content-Type-Options для предотвращения MIME sniffing Flight::response()->header('X-Content-Type-Options', 'nosniff'); // Установить заголовок Referrer-Policy для управления количеством отправляемой информации обратного адреса Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); // Установить заголовок Strict-Transport-Security для принудительного использования HTTPS Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); // Установить заголовок Permissions-Policy для управления используемыми функциями и API Flight::response()->header('Permissions-Policy', 'geolocation=()');
Эти заголовки могут быть добавлены в начало ваших файлов bootstrap.php или index.php.
bootstrap.php
index.php
Вы также можете добавить их в фильтр/хук, как показано ниже:
// Добавить заголовки в фильтр Flight::before('start', function() { Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); Flight::response()->header("Content-Security-Policy", "default-src 'self'"); Flight::response()->header('X-XSS-Protection', '1; mode=block'); Flight::response()->header('X-Content-Type-Options', 'nosniff'); Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); Flight::response()->header('Permissions-Policy', 'geolocation=()'); });
Вы также можете добавить их как класс Middleware. Это хороший способ держать свой код чистым и организованным.
// app/middleware/SecurityHeadersMiddleware.php namespace app\middleware; class SecurityHeadersMiddleware { public function before(array $params): void { Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); Flight::response()->header("Content-Security-Policy", "default-src 'self'"); Flight::response()->header('X-XSS-Protection', '1; mode=block'); Flight::response()->header('X-Content-Type-Options', 'nosniff'); Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); Flight::response()->header('Permissions-Policy', 'geolocation=()'); } } // index.php или где у вас находятся ваши маршруты //FYI, эта группа пустых строк действует как глобальное промежуточное ПО для всех маршрутов. Конечно же, вы могли бы сделать то же самое и просто добавить это только к определенным маршрутам. Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers']); // более маршрутов }, [ new SecurityHeadersMiddleware() ]);
Межсайтовая подделка запроса (CSRF) - это тип атаки, при которой злоумышленный сайт может заставить браузер пользователя отправить запрос на ваш сайт. Это может использоваться для выполнения действий на вашем сайте без ведома пользователя. Flight не предоставляет встроенного механизма защиты от CSRF, но вы легко можете реализовать свой собственный, используя промежуточное программное обеспечение.
Сначала вам необходимо сгенерировать токен CSRF и сохранить его в сессии пользователя. Затем вы можете использовать этот токен в ваших формах и проверять его при отправке формы.
// Сгенерировать токен CSRF и сохранить его в сессии пользователя // (предполагая, что вы создали объект сеанса и присоединили его к Flight) // см. документацию по сессиям для получения дополнительной информации Flight::register('session', \Ghostff\Session\Session::class); // Вам нужно сгенерировать только один токен на сеанс (чтобы он работал // в нескольких вкладках и запросах для одного и того же пользователя) if(Flight::session()->get('csrf_token') === null) { Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) ); }
<!-- Используйте токен CSRF в вашей форме --> <form method="post"> <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>"> <!-- другие поля формы --> </form>
Вы также можете установить пользовательскую функцию для вывода токена CSRF в ваших шаблонах Latte.
// Установить пользовательскую функцию для вывода токена CSRF // Примечание: Вид был настроен с движком представления Latte Flight::view()->addFunction('csrf', function() { $csrfToken = Flight::session()->get('csrf_token'); return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">'); });
И теперь в ваших шаблонах Latte вы можете использовать функцию csrf() для вывода токена CSRF.
csrf()
<form method="post"> {csrf()} <!-- другие поля формы --> </form>
Коротко и просто, верно?
Вы можете проверить токен CSRF, используя фильтры событий:
// Это промежуточное программное обеспечение проверяет, является ли запрос запросом POST, и если да, проверяет, является ли токен CSRF допустимым Flight::before('start', function() { if(Flight::request()->method == 'POST') { // получаем токен CSRF из значений формы $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Недопустимый токен CSRF'); // или для JSON-ответа Flight::jsonHalt(['error' => 'Недопустимый токен CSRF'], 403); } } });
Или вы можете использовать класс промежуточного программного обеспечения:
// app/middleware/CsrfMiddleware.php namespace app\middleware; class CsrfMiddleware { public function before(array $params): void { if(Flight::request()->method == 'POST') { $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Недопустимый токен CSRF'); } } } } // index.php или где у вас находятся ваши маршруты Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers' ]); // более маршрутов }, [ new CsrfMiddleware() ]);
Межсайтовая вставка скриптов (XSS) - это тип атаки, при которой злоумышленный сайт может внедрить код на вашем сайте. Большинство таких возможностей происходят из значений форм, которые вводят ваши конечные пользователи. Никогда не доверяйте выводу от ваших пользователей! Всегда предполагайте, что все они - лучшие хакеры в мире. Они могут внедрить вредоносный JavaScript или HTML на вашу страницу. Этот код может использоваться для кражи информации от ваших пользователей или выполнения действий на вашем сайте. Используя класс представлений Flight, вы легко можете экранировать вывод для предотвращения атак XSS.
// Допустим, пользователь умный и пытается использовать это в качестве своего имени $name = '<script>alert("XSS")</script>'; // Это экранирует вывод Flight::view()->set('name', $name); // Это выведет: <script>alert("XSS")</script> // Если вы используете что-то вроде Latte, зарегистрированного как ваш класс представлений, он также автоматически будет экранировать это. Flight::view()->render('template', ['name' => $name]);
SQL инъекция - это тип атаки, при которой злоумышленный пользователь может внедрить SQL-код в вашу базу данных. Это может быть использовано для кражи информации из вашей базы данных или выполнения действий над вашей базой данных. Опять же, никогда не доверяйте вводу от ваших пользователей! Всегда предполагайте, что они настроены враждебно. Вы можете использовать подготовленные операторы в ваших объектах PDO, чтобы предотвратить SQL инъекцию.
PDO
// Предполагая, что у вас зарегистрирован Flight::db() как ваш объект PDO $statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username'); $statement->execute([':username' => $username]); $users = $statement->fetchAll(); // Если вы используете класс PdoWrapper, это можно сделать легко в одной строке $users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]); // Вы можете сделать то же самое с объектом PDO с использованием плейсхолдеров ? $statement = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]); // Просто пообещайте, что вы никогда, никогда НИКОГДА не сделаете что-то подобное... $users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5"); // потому что что, если $username = "' OR 1=1; -- "; // После построения запроса он выглядит следующим образом // SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5 // Это выглядит странно, но это действующий запрос, который будет работать. Фактически, // это очень распространенная атака методом SQL инъекции, которая вернет все пользователей.
Обмен ресурсами между разными источниками (CORS) - это механизм, который позволяет запросить множество ресурсов (например, шрифты, JavaScript и т. д.) на веб-странице из другого домена, отличного от домена, из которого ресурс был запрошен. У Flight нет встроенной функциональности, но это легко можно обработать с помощью хука, который запускается перед вызовом метода Flight::start().
Flight::start()
// app/utils/CorsUtil.php namespace app\utils; class CorsUtil { public function set(array $params): void { $request = Flight::request(); $response = Flight::response(); if ($request->getVar('HTTP_ORIGIN') !== '') { $this->allowOrigins(); $response->header('Access-Control-Allow-Credentials', 'true'); $response->header('Access-Control-Max-Age', '86400'); } if ($request->method === 'OPTIONS') { if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') { $response->header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD' ); } if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') { $response->header( "Access-Control-Allow-Headers", $request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') ); } $response->status(200); $response->send(); exit; } } private function allowOrigins(): void { // настройте разрешенные хосты здесь $allowed = [ 'capacitor://localhost', 'ionic://localhost', 'http://localhost', 'http://localhost:4200', 'http://localhost:8080', 'http://localhost:8100', ]; $request = Flight::request(); if (in_array($request->getVar('HTTP_ORIGIN'), $allowed, true) === true) { $response = Flight::response(); $response->header("Access-Control-Allow-Origin", $request->getVar('HTTP_ORIGIN')); } } } // index.php или где у вас находятся ваши маршруты $CorsUtil = new CorsUtil(); // Это должно быть выполнено до вызова start. Flight::before('start', [ $CorsUtil, 'setupCors' ]);
Безопасность - это серьезное дело, и важно, чтобы ваши веб-приложения были безопасны. Flight предоставляет ряд функций, чтобы помочь вам обеспечить безопасность ваших веб-приложений, но важно всегда быть бдительным и удостовериться, что вы делаете все возможное, чтобы сохранить безопасность данных ваших пользователей. Всегда предполагайте худшее и никогда не доверяйте вводу от ваши# Безопасность
// app/middleware/CsrfMiddleware.php namespace app\middleware; class CsrfMiddleware { public function before(array $params): void { if(Flight::request()->method == 'POST') { $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Недопустимый токен CSRF'); } } } } // index.php или где у вас находятся ваши маршруты Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers']); // более маршрутов }, [ new CsrfMiddleware() ]);
Межсайтовая вставка скриптов (XSS) - это тип атаки, при которой злоумышленный сайт может внедрить код на вашем сайте. Большинство таких возможностей происходят из значений форм, которые вводят ваши конечные пользователи. Никогда не доверяйте выводу от ваших пользователей! Всегда предполагайте, что все они - лучшие хакеры в мире. Они могут внедрить вредоносный JavaScript или HTML на вашу страницу. Этот код может быть использован для кражи информации от ваших пользователей или выполнения действий на вашем сайте. Используя класс представлений Flight, вы легко можете экранировать вывод для предотвращения атак XSS.
SQL инъекция - это тип атаки, при которой злоумышленный пользователь может внедрить SQL-код в вашу базу данных. Это может быть использовано для кражи информации из вашей базы данных или выполнения действий над вашей базой данных. Опять же, никогда не доверяйте вводу от ваших пользователей! Всегда предполагайте они нацелены на вас. Вы можете использовать подготовленные операторы в ваших объектах PDO, чтобы предотвратить SQL инъекцию.
Безопасность - это серьезное дело, и важно, чтобы ваши веб-приложения были безопасны. Flight предоставляет ряд функций, чтобы помочь вам обеспечить безопасность ваших веб-приложений, но важно всегда быть бдительным и удостовериться, что вы делаете все возможное, чтобы сохранить безопасность данных ваших пользователей. Всегда предполагайте худшее и никогда не доверяйте вводу от ваши
Flight позволяет вам переопределять его стандартную функциональность под свои собственные потребности, не изменяя какой-либо код.
Например, когда Flight не может сопоставить URL с маршрутом, он вызывает метод notFound, который отправляет общий ответ HTTP 404. Вы можете переопределить это поведение используя метод map:
HTTP 404
map
Flight::map('notFound', function() { // Показать пользовательскую страницу 404 include 'errors/404.html'; });
Flight также позволяет заменять основные компоненты фреймворка. Например, вы можете заменить стандартный класс Router на свой собственный класс:
// Зарегистрируйте свой собственный класс Flight::register('router', MyRouter::class); // Когда Flight загружает экземпляр Router, он загрузит ваш класс $myrouter = Flight::router();
Однако методы фреймворка, такие как map и register, не могут быть переопределены. Если вы попытаетесь это сделать, вы получите ошибку.
register
Примечание: Хотите узнать больше о маршрутизации? Посмотрите страницу "почему фреймворк?" для более подробного объяснения.
Основная маршрутизация в Flight выполняется путем сопоставления шаблона URL с функцией обратного вызова или массивом класса и метода.
Flight::route('/', function(){ echo 'привет, мир!'; });
Маршруты сопоставляются в том порядке, в котором они определены. Первый сопоставленный маршрут будет вызван.
Обратный вызов может быть любым объектом, который можно вызывать. Так что вы можете использовать обычную функцию:
function hello() { echo 'привет, мир!'; } Flight::route('/', 'hello');
Вы также можете использовать статический метод класса:
class Greeting { public static function hello() { echo 'привет, мир!'; } } Flight::route('/', [ 'Greeting','hello' ]);
Или создав объект сначала, а затем вызвать метод:
// Greeting.php class Greeting { public function __construct() { $this->name = 'Иванов Иван'; } public function hello() { echo "Привет, {$this->name}!"; } } // index.php $greeting = new Greeting(); Flight::route('/', [ $greeting, 'hello' ]); // Вы также можете сделать это без предварительного создания объекта // Примечание: В конструктор не будут переданы аргументы Flight::route('/', [ 'Greeting', 'hello' ]); // Кроме того, вы можете использовать эту более короткую синтаксис Flight::route('/', 'Greeting->hello'); // или Flight::route('/', Greeting::class.'->hello');
Если вы хотите использовать внедрение зависимостей через контейнер (PSR-11, PHP-DI, Dice и т. д.), единственный тип маршрутов, где это доступно - это либо непосредственное создание объекта самостоятельно и использование контейнера для создания вашего объекта, или вы можете использовать строки для определения класса и метода для вызова. Загляните на страницу [Внедрение зависимостей] (/learn/extending) для более подробной информации.
Вот быстрый пример:
use flight\database\PdoWrapper; // Greeting.php class Greeting { protected PdoWrapper $pdoWrapper; public function __construct(PdoWrapper $pdoWrapper) { $this->pdoWrapper = $pdoWrapper; } public function hello(int $id) { // делаем что-то с $this->pdoWrapper $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]); echo "Привет, мир! Меня зовут {$name}!"; } } // index.php // Настройте контейнер в соответствии с вашими потребностями // Смотрите страницу Внедрение зависимостей для более подробной информации о PSR-11 $dice = new \Dice\Dice(); // Не забудьте заново присвоить переменную '$dice = '!!!!! $dice = $dice->addRule('flight\database\PdoWrapper', [ 'shared' => true, 'constructParams' => [ 'mysql:host=localhost;dbname=test', 'root', 'password' ] ]); // Зарегистрируйте обработчик контейнера Flight::registerContainerHandler(function($class, $params) use ($dice) { return $dice->create($class, $params); }); // Маршруты как обычно Flight::route('/hello/@id', [ 'Greeting', 'hello' ]); // или Flight::route('/hello/@id', 'Greeting->hello'); // или Flight::route('/hello/@id', 'Greeting::hello'); Flight::start();
По умолчанию шаблоны маршрутов сопоставляются с каждым методом запроса. Вы можете отвечать на конкретные методы, поместив идентификатор перед URL.
Flight::route('GET /', function () { echo 'Получен запрос GET.'; }); Flight::route('POST /', function () { echo 'Получен запрос POST.'; }); // Невозможно использовать Flight::get() для маршрутов, так как это метод // для получения переменных, а не для создания маршрута. // Flight::post('/', function() { /* код */ }); // Flight::patch('/', function() { /* код */ }); // Flight::put('/', function() { /* код */ }); // Flight::delete('/', function() { /* код */ });
Вы также можете сопоставить несколько методов с одним обратным вызовом, используя разделитель |:
|
Flight::route('GET|POST /', function () { echo 'Получен запрос GET или POST.'; });
Кроме того, можно получить объект Router, который содержит некоторые вспомогательные методы для использования:
$router = Flight::router(); // картировка всех методов $router->map('/', function() { echo 'привет, мир!'; }); // GET запрос $router->get('/users', function() { echo 'пользователи'; }); // $router->post(); // $router->put(); // $router->delete(); // $router->patch();
Вы можете использовать регулярные выражения в ваших маршрутах:
Flight::route('/user/[0-9]+', function () { // Это соответствует /user/1234 });
Хотя это метод доступен, рекомендуется использовать именованные параметры или именованные параметры с регулярными выражениями, так как они более читаемы и легче поддерживать.
Вы можете указать именованные параметры в ваших маршрутах, которые будут переданы в вашу функцию обратного вызова.
Flight::route('/@name/@id', function (string $name, string $id) { echo "привет, $name ($id)!"; });
Вы также можете включать регулярные выражения с именованными параметрами, используя разделитель ::
:
Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) { // Это соответствует /bob/123 // Но не соответствует /bob/12345 });
Примечание: Сопоставление групп regex () с именованными параметрами не поддерживается. :'(
()
Вы можете указать именованные параметры, которые являются необязательными для сопоставления путем обертывания сегментов в скобки.
Flight::route( '/blog(/@year(/@month(/@day)))', function(?string $year, ?string $month, ?string $day) { // Это соответствует следующим URL: // /blog/2012/12/10 // /blog/2012/12 // /blog/2012 // /blog } );
Любые несопоставленные необязательные параметры будут переданы как NULL.
NULL
Сопоставление выполняется только на отдельных сегментах URL. Если вы хотите сопоставить несколько сегментов, вы можете использовать спецсимвол *.
*
Flight::route('/blog/*', function () { // Это будет соответствовать /blog/2000/02/01 });
Для направления всех запросов на один обратный вызов, вы можете сделать следующее:
Flight::route('*', function () { // Что-то делаем });
Вы можете передать выполнение следующему сопоставленному маршруту, вернув true из вашей функции обратного вызова.
Flight::route('/user/@name', function (string $name) { // Проверяем некоторое условие if ($name !== "Боб") { // Продолжить к следующему маршруту return true; } }); Flight::route('/user/*', function () { // Это будет вызвано });
Вы можете назначить псевдоним маршруту, так чтобы URL можно было динамически генерировать позже в вашем коде (например, в шаблоне).
Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view'); // позже в коде Flight::getUrl('user_view', [ 'id' => 5 ]); // вернет '/users/5'
Это особенно полезно, если ваш URL случайно изменится. В предыдущем примере предположим, что пользователи были перемещены в /admin/users/@id вместо этого. С использованием псевдонима вам не нужно изменять места, где вы ссылаетесь на псевдоним, потому что псевдоним теперь вернет /admin/users/5, как в приведенном выше примере.
/admin/users/@id
/admin/users/5
Псевдоним маршрутизации по-прежнему работает в группах также:
Flight::group('/users', function() { Flight::route('/@id', function($id) { echo 'user:'.$id; }, false, 'user_view'); }); // позже в коде Flight::getUrl('user_view', [ 'id' => 5 ]); // вернет '/users/5'
Если вы хотите проверить информацию о сопоставленном маршруте, вы можете запросить объект маршрута, передав true в качестве третьего параметра в метод маршрута. Объект маршрута всегда будет последним параметром, переданным в вашу функцию обратного вызова.
Flight::route('/', function(\flight\net\Route $route) { // Массив сопоставленных методов HTTP $route->methods; // Массив именованных параметров $route->params; // Соответствующее регулярное выражение $route->regex; // Содержит содержимое любого '*', используемого в шаблоне URL $route->splat; // Показывает путь URL.... если вам действительно нужно $route->pattern; // Показывает, какое промежуточное ПО назначено этому $route->middleware; // Показывает псевдоним, назначенный этому маршруту $route->alias; }, true);
Иногда вам может потребоваться группировать связанные маршруты вместе (например, /api/v1). Вы можете сделать это, используя метод group:
/api/v1
group
Flight::group('/api/v1', function () { Flight::route('/users', function () { // Соответствует /api/v1/users }); Flight::route('/posts', function () { // Соответствует /api/v1/posts }); });
Вы можете даже вкладывать группы из групп:
Flight::group('/api', function () { Flight::group('/v1', function () { // Flight::get() получает переменные, он не устанавливает маршрут! Смотрите ниже контекст объекта Flight::route('GET /users', function () { // Соответствует GET /api/v1/users }); Flight::post('/posts', function () { // Соответствует POST /api/v1/posts }); Flight::put('/posts/1', function () { // Соответствует PUT /api/v1/posts }); }); Flight::group('/v2', function () { // Flight::get() получает переменные, он не устанавливает маршрут! Смотрите ниже контекст объекта Flight::route('GET /users', function () { // Соответствует GET /api/v2/users }); }); });
Вы все еще можете использовать группировку маршрутов с объектом Engine следующим образом:
Engine
$app = new \flight\Engine(); $app->group('/api/v1', function (Router $router) { // используйте переменную $router $router->get('/users', function () { // Соответствует GET /api/v1/users }); $router->post('/posts', function () { // Соответствует POST /api/v1/posts }); });
Теперь вы можете потоково отправлять ответы клиенту, используя метод streamWithHeaders(). Это полезно для отправки больших файлов, длительных процессов или генерации больших ответов. Потоковая передача маршрута обрабатывается немного по-другому, чем обычный маршрут.
streamWithHeaders()
Примечание: Передача ответов доступна только если у вас установлен параметр flight.v2.output_buffering в значение false.
Вы можете передавать ответ клиенту, используя метод stream() на маршруте. Если вы делаете так, вам необходимо установить все методы вручную перед тем, как что-то выводить в клиент. Это делается с помощью функции header() php или метода Flight::response()->setRealHeader().
stream()
header()
Flight::response()->setRealHeader()
Flight::route('/@filename', function($filename) { // очевидно, вы также будете очищать путь и прочее. $fileNameSafe = basename($filename); // Если у вас есть дополнительные заголовки для установки после выполнения маршрута // вы должны определить их, прежде чем что-то будет выведено. // Все они должны быть прямым вызовом функции header() или // вызовом метода Flight::response()->setRealHeader() header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"'); // или Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"'); $fileData = file_get_contents('/some/path/to/files/'.$fileNameSafe); // Обработка ошибок и прочее if(empty($fileData)) { Flight::halt(404, 'Файл не найден'); } // вручную установить длину контента, если хотите header# Маршрутизация > **Примечание:** Хотите узнать больше о маршрутизации? Посмотрите страницу ["почему фреймворк?"](/learn/why-frameworks) для более подробного объяснения. Основная маршрутизация в Flight выполняется путем сопоставления шаблона URL с функцией обратного вызова или массивом класса и метода. ```php Flight::route('/', function(){ echo 'привет, мир!'; });
Symfony - набор многоразовых компонентов PHP и фреймворк PHP для веб-проектов.
Стандартный фундамент, на котором строятся лучшие приложения на PHP. Выберите любые из 50 доступных автономных компонентов для ваших собственных приложений.
Ускорьте создание и поддержку ваших веб-приложений на PHP. Заканчивайте повторяющиеся задачи по кодированию и наслаждайтесь возможностью контролировать ваш код.
Если вы переходите с другого фреймворка, такого как Laravel, Slim, Fat-Free или Symfony, на Flight, эта страница поможет вам понять различия между ними.
Laravel - это полнофункциональный фреймворк со всеми плюшками и удивительной экосистемой, сосредоточенной на разработчике, но за счет производительности и сложности.
Сравните Laravel и Flight.
Slim - это микро-фреймворк, похожий на Flight. Он разработан с упором на легкость использования, но может быть немного сложнее, чем Flight.
Сравните Slim и Flight.
Fat-Free - это полностековый фреймворк в намного меньшем объеме. Хотя в нем есть все необходимые инструменты, его архитектура данных может усложнить некоторые проекты более, чем это необходимо.
Сравните Fat-Free и Flight.
Symfony - модульный фреймворк корпоративного уровня, разработанный для гибкости и масштабируемости. Для меньших проектов или новых разработчиков Symfony может быть немного подавляющим.
Сравните Symfony и Flight.
Flight позволяет вам сохранять переменные, чтобы они могли быть использованы в любом месте вашего приложения.
// Сохраняет вашу переменную Flight::set('id', 123); // В другом месте вашего приложения $id = Flight::get('id');
Для проверки установленной переменной вы можете сделать следующее:
if (Flight::has('id')) { // Сделать что-то }
Вы можете очистить переменную, выполнив:
// Очищает переменную id Flight::clear('id'); // Очищает все переменные Flight::clear();
Flight также использует переменные для целей конфигурации.
Контейнер внедрения зависимостей (DIC) является мощным инструментом, который позволяет управлять зависимостями вашего приложения. Это ключевая концепция в современных PHP фреймворках и используется для управления созданием и настройкой объектов. Некоторые примеры DIC библиотек: Dice, Pimple, PHP-DI, и league/container.
DIC - это удобный способ сказать, что он позволяет создавать и управлять вашими классами в централизованном месте. Это полезно, когда вам нужно передавать один и тот же объект в несколько классов (например, в ваши контроллеры). Простой пример может помочь лучше понять это.
В старом подходе это могло выглядеть примерно так:
require 'vendor/autoload.php'; // класс для управления пользователями в базе данных class UserController { protected PDO $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function view(int $id) { $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->execute(['id' => $id]); print_r($stmt->fetch()); } } $User = new UserController(new PDO('mysql:host=localhost;dbname=test', 'user', 'pass')); Flight::route('/user/@id', [ $UserController, 'view' ]); Flight::start();
Вы видите из приведенного выше кода, что мы создаем новый объект PDO и передаем его в наш класс UserController. Это нормально для небольших приложений, но по мере роста вашего приложения вы обнаружите, что создаете тот же объект PDO в нескольких местах. Вот где пригодится DIC.
UserController
Вот тот же пример с использованием DIC (используя Dice):
require 'vendor/autoload.php'; // тот же класс, что и выше. Ничего не изменилось class UserController { protected PDO $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function view(int $id) { $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->execute(['id' => $id]); print_r($stmt->fetch()); } } // создаем новый контейнер $container = new \Dice\Dice; // не забудьте переприсвоить его самому себе, как показано ниже! $container = $container->addRule('PDO', [ // shared означает, что каждый раз будет возвращаться один и тот же объект 'shared' => true, 'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ] ]); // Это регистрирует обработчик контейнера, чтобы Flight знал, что его использовать. Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // теперь мы можем использовать контейнер для создания нашего UserController Flight::route('/user/@id', [ 'UserController', 'view' ]); // или, альтернативно, вы можете определить маршрут так Flight::route('/user/@id', 'UserController->view'); // или Flight::route('/user/@id', 'UserController::view'); Flight::start();
Возможно, вы подумаете, что в пример было добавлено много лишнего кода. Магия заключается в том, что когда у вас есть другой контроллер, который нуждается в объекте PDO.
// Если все ваши контроллеры имеют конструктор, который нуждается в объекте PDO // каждый из нижеуказанных маршрутов автоматически будет его использовать!!! Flight::route('/company/@id', 'CompanyController->view'); Flight::route('/organization/@id', 'OrganizationController->view'); Flight::route('/category/@id', 'CategoryController->view'); Flight::route('/settings', 'SettingsController->view');
Дополнительный бонус использования DIC заключается в том, что тестирование модулей становится намного проще. Вы можете создать имитационный объект и передать его в ваш класс. Это огромное преимущество при написании тестов для вашего приложения!
Flight также может использовать любой совместимый с PSR-11 контейнер. Это означает, что вы можете использовать любой контейнер, который реализует интерфейс PSR-11. Вот пример использования контейнера PSR-11 от League:
require 'vendor/autoload.php'; // тот же класс UserController, что и выше $container = new \League\Container\Container(); $container->add(UserController::class)->addArgument(PdoWrapper::class); $container->add(PdoWrapper::class) ->addArgument('mysql:host=localhost;dbname=test') ->addArgument('user') ->addArgument('pass'); Flight::registerContainerHandler($container); Flight::route('/user', [ 'UserController', 'view' ]); Flight::start();
Хотя это может быть немного более многословным, чем предыдущий пример с Dice, все равно делает свою работу с теми же преимуществами!
Вы также можете создать свой собственный обработчик DIC. Это полезно, если у вас есть пользовательский контейнер, который вы хотите использовать и который не является PSR-11 (Dice). См. основной пример для того, как это сделать.
Кроме того, имеются некоторые полезные значения по умолчанию, которые сделают вашу жизнь проще при использовании Flight.
Если вы используете экземпляр Engine в своих контроллерах/промежуточных уровнях, вот как вы можете его настроить:
// Где-то в вашем файле инициализации $engine = Flight::app(); $container = new \Dice\Dice; $container = $container->addRule('*', [ 'substitutions' => [ // Здесь передается экземпляр Engine::class => $engine ] ]); $engine->registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // Теперь вы можете использовать экземпляр Engine в ваших контроллерах/промежуточных уровнях class MyController { public function __construct(Engine $app) { $this->app = $app; } public function index() { $this->app->render('index'); } }
Если у вас есть другие классы, которые вы хотите добавить в контейнер, с Dice это легко, так как они будут автоматически разрешены контейнером. Вот пример:
$container = new \Dice\Dice; // Если вам не нужно внедрять что-либо в ваш класс // вам не нужно ничего определять! Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); class MyCustomClass { public function parseThing() { return 'thing'; } } class UserController { protected MyCustomClass $MyCustomClass; public function __construct(MyCustomClass $MyCustomClass) { $this->MyCustomClass = $MyCustomClass; } public function index() { echo $this->MyCustomClass->parseThing(); } } Flight::route('/user', 'UserController->index');
Flight поддерживает промежуточное программное обеспечение маршрута и группы маршрутов. Промежуточное программное обеспечение - это функция, которая выполняется до (или после) обратного вызова маршрута. Это отличный способ добавить проверки аутентификации API в ваш код или проверить, имеет ли пользователь разрешение на доступ к маршруту.
Вот простой пример:
// Если вы предоставляете только безымянную функцию, она будет выполнена перед обратным вызовом маршрута. // нет "после" промежуточных функций, за исключением классов (см. ниже) Flight::route('/path', function() { echo ' Вот я!'; })->addMiddleware(function() { echo 'Сначала промежуточное программное обеспечение!'; }); Flight::start(); // Это выведет "Сначала промежуточное программное обеспечение! Вот я!"
Существуют некоторые очень важные заметки о промежуточном программном обеспечении, о которых вам следует знать перед тем, как использовать их:
Flight::redirect()
function($params) { ... }
public function before($params) {}
__construct()
flight\Engine
Промежуточное программное обеспечение можно зарегистрировать также как класс. Если вам нужна функциональность "после", вы должны использовать класс.
class MyMiddleware { public function before($params) { echo 'Сначала промежуточное программное обеспечение!'; } public function after($params) { echo 'Последнее промежуточное программное обеспечение!'; } } $MyMiddleware = new MyMiddleware(); Flight::route('/path', function() { echo ' Вот я! '; })->addMiddleware($MyMiddleware); // также ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]); Flight::start(); // Это выведет "Сначала промежуточное программное обеспечение! Вот я! Последнее промежуточное программное обеспечение!"
Предположим, у вас есть промежуточное программное обеспечение аутентификации и вы хотите перенаправить пользователя на страницу входа, если он не аутентифицирован. У вас есть несколько вариантов действий:
Вот простой пример с возвратом false:
class MyMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { return false; } // поскольку это верно, всё продолжает идти } }
Вот пример перенаправления пользователя на страницу входа:
class MyMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { Flight::redirect('/login'); exit; } } }
Предположим, вам нужно сгенерировать JSON-ошибку, потому что вы создаете API. Вы можете сделать это следующим образом:
class MyMiddleware { public function before($params) { $authorization = Flight::request()->headers['Authorization']; if(empty($authorization)) { Flight::jsonHalt(['error' => 'Необходимо войти в систему, чтобы получить доступ к этой странице.'], 403); // или Flight::json(['error' => 'Необходимо войти в систему, чтобы получить доступ к этой странице.'], 403); exit; // или Flight::halt(403, json_encode(['error' => 'Необходимо войти в систему, чтобы получить доступ к этой странице.']); } } }
Вы можете добавить группу маршрутов, и затем у каждого маршрута в этой группе будет также применяться то же промежуточное программное обеспечение. Это полезно, если вам нужно сгруппировать несколько маршрутов, например при помощи промежуточного программного обеспечения аутентификации для проверки ключа API в заголовке.
// добавлено в конце метода группы Flight::group('/api', function() { // Этот "пустой" маршрут на самом деле совпадет с /api Flight::route('', function() { echo 'api'; }, false, 'api'); // Это совпадет с /api/users Flight::route('/users', function() { echo 'users'; }, false, 'users'); // Это совпадет с /api/users/1234 Flight::route('/users/@id', function($id) { echo 'пользователь:'.$id; }, false, 'user_view'); }, [ new ApiAuthMiddleware() ]);
Если вы хотите применить глобальное промежуточное программное обеспечение ко всем вашим маршрутам, вы можете добавить "пустую" группу:
// добавлено в конце метода группы Flight::group('', function() { // Это все еще /users Flight::route('/users', function() { echo 'users'; }, false, 'users'); // А это все еще /users/1234 Flight::route('/users/@id', function($id) { echo 'пользователь:'.$id; }, false, 'user_view'); }, [ new ApiAuthMiddleware() ]);
Flight позволяет вам фильтровать методы до и после их вызова. Нет заранее определенных хуков, которые нужно запоминать. Вы можете фильтровать любые из методов фреймворка по умолчанию а также любые пользовательские методы, которые вы объявили.
Функция фильтра выглядит следующим образом:
function (array &$params, string &$output): bool { // Код фильтрации }
Используя передаваемые переменные, вы можете изменять входные параметры и/или вывод.
Вы можете запустить фильтр перед вызовом метода следующим образом:
Flight::before('start', function (array &$params, string &$output): bool { // Сделать что-то });
Вы можете запустить фильтр после вызова метода следующим образом:
Flight::after('start', function (array &$params, string &$output): bool { // Сделать что-то });
Вы можете добавлять столько фильтров, сколько захотите, к любому методу. Они будут вызваны в порядке объявления.
Вот пример процесса фильтрации:
// Объявляем пользовательский метод Flight::map('hello', function (string $name) { return "Hello, $name!"; }); // Добавляем фильтр до Flight::before('hello', function (array &$params, string &$output): bool { // Изменяем параметр $params[0] = 'Fred'; return true; }); // Добавляем фильтр после Flight::after('hello', function (array &$params, string &$output): bool { // Изменяем вывод $output .= " Have a nice day!"; return true; }); // Вызываем пользовательский метод echo Flight::hello('Bob');
Это должно вывести:
Hello Fred! Have a nice day!
Если у вас определено несколько фильтров, вы можете прервать цепочку, вернув false в любой из ваших фильтров:
false
Flight::before('start', function (array &$params, string &$output): bool { echo 'one'; return true; }); Flight::before('start', function (array &$params, string &$output): bool { echo 'two'; // Это прервет цепочку return false; }); // Этот фильтр не будет вызван Flight::before('start', function (array &$params, string &$output): bool { echo 'three'; return true; });
Обратите внимание, что основные методы, такие как map и register, не могут быть фильтрованы, потому что они вызываются непосредственно и не динамически вызываются.
Flight инкапсулирует HTTP-запрос в единый объект, к которому можно получить доступ следующим образом:
$request = Flight::request();
Когда вы работаете с запросом в веб-приложении, обычно вы хотите извлечь заголовок или параметр $_GET или $_POST, или, возможно, даже сырое тело запроса. Flight предоставляет простой интерфейс для выполнения всех этих действий.
$_GET
$_POST
Вот пример получения параметра строки запроса:
Flight::route('/search', function(){ $keyword = Flight::request()->query['keyword']; echo "Вы ищете: $keyword"; // запрашиваем базу данных или что-то еще с $keyword });
Вот пример формы с методом POST:
Flight::route('POST /submit', function(){ $name = Flight::request()->data['name']; $email = Flight::request()->data['email']; echo "Вы отправили: $name, $email"; // сохранить в базе данных или что-то еще с $name и $email });
Объект запроса предоставляет следующие свойства:
$_SERVER
HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
Вы можете получить доступ к свойствам query, data, cookies и files как к массивам или объектам.
query
data
cookies
files
Итак, чтобы получить параметр строки запроса, вы можете сделать:
$id = Flight::request()->query['id'];
Или вы можете сделать:
$id = Flight::request()->query->id;
Чтобы получить сырое тело HTTP-запроса, например, при работе с запросами PUT, вы можете сделать:
$body = Flight::request()->getBody();
Если вы отправляете запрос с типом application/json и данными {"id": 123}, они будут доступны через свойство data:
application/json
{"id": 123}
$id = Flight::request()->data->id;
Вы можете получить доступ к массиву $_GET через свойство query:
Вы можете получить доступ к массиву $_POST через свойство data:
$id = Flight::request()->data['id'];
$_COOKIE
Вы можете получить доступ к массиву $_COOKIE через свойство cookies:
$myCookieValue = Flight::request()->cookies['myCookieName'];
Существует удобный способ доступа к массиву $_SERVER через метод getVar():
getVar()
$host = Flight::request()->getVar['HTTP_HOST'];
$_FILES
Вы можете получить доступ к загруженным файлам через свойство files:
$uploadedFile = Flight::request()->files['myFile'];
Вы можете обрабатывать загрузку файлов с помощью фреймворка с помощью некоторых вспомогательных методов. В основном это сводится к извлечению данных файла из запроса и перемещению их в новое местоположение.
Flight::route('POST /upload', function(){ // Если у вас было поле ввода, такое как <input type="file" name="myFile"> $uploadedFileData = Flight::request()->getUploadedFiles(); $uploadedFile = $uploadedFileData['myFile']; $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename()); });
Если вы загрузили несколько файлов, вы можете пройтись по ним в цикле:
Flight::route('POST /upload', function(){ // Если у вас было поле ввода, такое как <input type="file" name="myFiles[]"> $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles']; foreach ($uploadedFiles as $uploadedFile) { $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename()); } });
Заметка по Безопасности: Всегда валидируйте и очищайте ввод пользователя, особенно при работе с загрузками файлов. Всегда валидируйте типы расширений, которые вы разрешите загружать, но вы также должны валидировать "магические байты" файла, чтобы убедиться, что это действительно тот тип файла, который пользователь заявляет, что это. Существуют статьи и библиотеки для помощи в этом.
Вы можете получить доступ к заголовкам запроса с помощью метода getHeader() или getHeaders():
getHeader()
getHeaders()
// Возможно, вам нужен заголовок авторизации $host = Flight::request()->getHeader('Authorization'); // или $host = Flight::request()->header('Authorization'); // Если вам нужно получить все заголовки $headers = Flight::request()->getHeaders(); // или $headers = Flight::request()->headers();
Вы можете получить доступ к сырому телу запроса, используя метод getBody():
getBody()
Вы можете получить доступ к методу запроса, используя свойство method или метод getMethod():
method
getMethod()
$method = Flight::request()->method; // фактически вызывает getMethod() $method = Flight::request()->getMethod();
Примечание: Метод getMethod() сначала извлекает метод из $_SERVER['REQUEST_METHOD'], затем он может быть переопределен с помощью $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'], если он существует, или $_REQUEST['_method'], если он существует.
$_SERVER['REQUEST_METHOD']
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']
$_REQUEST['_method']
Существуют несколько вспомогательных методов для сборки частей URL для вашего удобства.
Вы можете получить доступ к полному URL запроса, используя метод getFullUrl():
getFullUrl()
$url = Flight::request()->getFullUrl(); // https://example.com/some/path?foo=bar
Вы можете получить доступ к базовому URL, используя метод getBaseUrl():
getBaseUrl()
$url = Flight::request()->getBaseUrl(); // Обратите внимание, нет конечного слэша. // https://example.com
Вы можете передать URL в метод parseQuery(), чтобы разобрать строку запроса в ассоциативный массив:
parseQuery()
$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar'); // ['foo' => 'bar']
Flight разработан для удобства использования и понимания. Ниже приведен полный набор методов для фреймворка. Он состоит из основных методов, которые являются обычными статическими методами, и расширяемых методов, которые являются отображенными методами, которые могут быть отфильтрованы или переопределены.
Flight::map(строка $name, callable $callback, bool $pass_route = false) // Создает пользовательский метод фреймворка. Flight::register(строка $name, строка $class, массив $params = [], ?callable $callback = null) // Регистрирует класс для метода фреймворка. Flight::before(строка $name, callable $callback) // Добавляет фильтр перед методом фреймворка. Flight::after(строка $name, callable $callback) // Добавляет фильтр после метода фреймворка. Flight::path(строка $path) // Добавляет путь для автозагрузки классов. Flight::get(строка $key) // Получает переменную. Flight::set(строка $key, смешанный $value) // Устанавливает переменную. Flight::has(строка $key) // Проверяет, установлена ли переменная. Flight::clear(массив|строка $key = []) // Очищает переменную. Flight::init() // Инициализирует фреймворк к его настройкам по умолчанию. Flight::app() // Получает экземпляр объекта приложения.
Flight::start() // Запускает фреймворк. Flight::stop() // Останавливает фреймворк и отправляет ответ. Flight::halt(int $code = 200, строка $message = '') // Останавливает фреймворк с необязательным кодом состояния и сообщением. Flight::route(строка $pattern, callable $callback, bool $pass_route = false) // Сопоставляет шаблон URL с обратным вызовом. Flight::group(строка $pattern, callable $callback) // Создает группировку для URL, шаблон должен быть строкой. Flight::redirect(строка $url, int $code) // Перенаправляет на другой URL. Flight::render(строка $file, массив $data, ?строка $key = null) // Рендерит файл шаблона. Flight::error(Throwable $error) // Отправляет ответ HTTP 500. Flight::notFound() // Отправляет ответ HTTP 404. Flight::etag(строка $id, строка $type = 'string') // Выполняет кэширование HTTP ETag. Flight::lastModified(int $time) // Выполняет кэширование HTTP Last-Modified. Flight::json(смешанный $data, int $code = 200, bool $encode = true, строка $charset = 'utf8', int $option) // Отправляет ответ JSON. Flight::jsonp(смешанный $data, строка $param = 'jsonp', int $code = 200, bool $encode = true, строка $charset = 'utf8', int $option) // Отправляет ответ JSONP.
Любые пользовательские методы, добавленные с помощью map и register, также могут быть отфильтрованы.
Flight разработан для простоты использования и понимания. Ниже приведен полный набор методов для фреймворка. Он состоит из базовых методов, которые являются обычными статическими методами, и расширяемых методов, которые являются отображенными методами, которые могут быть отфильтрованы или переопределены.
Эти методы являются базовыми для фреймворка и не могут быть переопределены.
Flight::map(строка $name, callable $callback, bool $pass_route = false) // Создает пользовательский метод фреймворка. Flight::register(строка $name, строка $class, массив $params = [], ?callable $callback = null) // Регистрирует класс в метод фреймворка. Flight::unregister(строка $name) // Отменяет регистрацию класса в методе фреймворка. Flight::before(строка $name, callable $callback) // Добавляет фильтр до метода фреймворка. Flight::after(строка $name, callable $callback) // Добавляет фильтр после метода фреймворка. Flight::path(строка $path) // Добавляет путь для автозагрузки классов. Flight::get(строка $key) // Получает переменную, установленную через Flight::set(). Flight::set(строка $key, смешанный $value) // Устанавливает переменную внутри движка Flight. Flight::has(строка $key) // Проверяет, установлена ли переменная. Flight::clear(массив|строка $key = []) // Очищает переменную. Flight::init() // Инициализирует фреймворк к его настройкам по умолчанию. Flight::app() // Получает экземпляр объекта приложения Flight::request() // Получает экземпляр объекта запроса Flight::response() // Получает экземпляр объекта ответа Flight::router() // Получает экземпляр объекта маршрутизатора Flight::view() // Получает экземпляр объекта представления
Flight::start() // Запускает фреймворк. Flight::stop() // Останавливает фреймворк и отправляет ответ. Flight::halt(int $code = 200, строка $message = '') // Останавливает фреймворк с необязательным кодом состояния и сообщением. Flight::route(строка $pattern, callable $callback, bool $pass_route = false, строка $alias = '') // Сопоставляет шаблон URL с обратным вызовом. Flight::post(строка $pattern, callable $callback, bool $pass_route = false, строка $alias = '') // Сопоставляет шаблон URL для POST-запроса с обратным вызовом. Flight::put(строка $pattern, callable $callback, bool $pass_route = false, строка $alias = '') // Сопоставляет шаблон URL для PUT-запроса с обратным вызовом. Flight::patch(строка $pattern, callable $callback, bool $pass_route = false, строка $alias = '') // Сопоставляет шаблон URL для запроса PATCH с обратным вызовом. Flight::delete(строка $pattern, callable $callback, bool $pass_route = false, строка $alias = '') // Сопоставляет шаблон URL для запроса DELETE с обратным вызовом. Flight::group(строка $pattern, callable $callback) // Создает группировку для URL, шаблон должен быть строкой. Flight::getUrl(строка $name, массив $params = []) // Генерирует URL на основе псевдонима маршрута. Flight::redirect(строка $url, int $code) // Перенаправляет на другой URL. Flight::download(строка $filePath) // Загружает файл. Flight::render(строка $file, массив $data, ?строка $key = null) // Рендерит файл шаблона. Flight::error(Throwable $error) // Отправляет ответ HTTP 500. Flight::notFound() // Отправляет ответ HTTP 404. Flight::etag(строка $id, строка $type = 'string') // Выполняет кэширование HTTP ETag. Flight::lastModified(int $time) // Выполняет кэширование последней модификации HTTP. Flight::json(смешанный $data, int $code = 200, bool $encode = true, строка $charset = 'utf8', int $option) // Отправляет ответ JSON. Flight::jsonp(смешанный $data, строка $param = 'jsonp', int $code = 200, bool $encode = true, строка $charset = 'utf8', int $option) // Отправляет ответ JSONP. Flight::jsonHalt(смешанный $data, int $code = 200, bool $encode = true, строка $charset = 'utf8', int $option) // Отправляет ответ JSON и останавливает фреймворк.
Любые пользовательские методы, добавленные с помощью map и register, также могут быть отфильтрованы. Примеры того, как сопоставить эти методы, см. в руководстве Расширение Flight.
Некоторые программисты решительно против использования фреймворков. Они утверждают, что фреймворки избыточны, медленны и сложны в изучении. Они говорят, что фреймворки не нужны, и что можно писать лучший код без них. Конечно, есть несколько обоснованных аргументов против использования фреймворков. Однако, есть также много преимуществ в использовании фреймворков.
Вот несколько причин, почему вам может захотеться рассмотреть использование фреймворка:
Flight - это микрофреймворк. Это означает, что он небольшой и легкий. Он не предоставляет так много функциональности, как более крупные фреймворки, такие как Laravel или Symfony. Однако он предоставляет много функциональности, которая вам нужна для создания веб-приложений. Его также легко изучить и использовать. Это делает его хорошим выбором для быстрого и простого создания веб-приложений. Если вы новичок в фреймворках, Flight - отличный фреймворк для начала. Он поможет вам узнать о преимуществах использования фреймворков, не перегружая вас слишком сложностью. После того как у вас будет опыт работы с Flight, будет легче перейти на более сложные фреймворки, такие как Laravel или Symfony, однако Flight все равно может создать успешное надежное приложение.
Маршрутизация является основой фреймворка Flight, но что это такое? Маршрутизация - это процесс принятия URL и сопоставления его с определенной функцией в вашем коде. Таким образом вы можете заставить ваш веб-сайт делать разные вещи в зависимости от запрошенного URL. Например, вы могли бы показать профиль пользователя, когда они посещают /user/1234, но показать список всех пользователей, когда они посещают /users. Все это делается через маршрутизацию.
/user/1234
/users
Это может работать так:
http://example.com/user/1234
Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]);
viewUserProfile($id)
1234
$id
viewUserProfile()
Иметь правильный централизованный маршрутизатор может действительно сильно облегчить вашу жизнь! Просто сначала это может быть трудно увидеть. Вот несколько причин:
user_view
id
/admin/user/1234
Я уверен, что вы знакомы со способом создания веб-сайта, описанным скрипт за скриптом. Может быть у вас есть файл под названием index.php, который содержит множество условных операторов if для проверки URL, а затем запуска определенной функции на основе URL. Это форма маршрутизации, но она не очень организована и может быстро выйти из-под контроля. Система маршрутизации Flight - это гораздо более организованный и мощный способ управления маршрутами.
if
Это?
// /user/view_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; viewUserProfile($id); } // /user/edit_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; editUserProfile($id); } // и так далее...
или это?
// index.php Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]); Flight::route('/user/@id/edit', [ 'UserController', 'editUserProfile' ]); // Возможно, в вашем app/controllers/UserController.php class UserController { public function viewUserProfile($id) { // сделать что-то } public function editUserProfile($id) { // сделать что-то } }
Надеюсь, теперь вы начинаете видеть преимущества использования централизованной системы маршрутизации. Это намного проще управлять и понимать в долгосрочной перспективе!
Flight предоставляет простой и легкий способ обработки запросов и ответов. Это ядро функционала веб-фреймворка. Он принимает запрос от браузера пользователя, обрабатывает его, а затем отправляет ответ. Именно так вы можете создавать веб-приложения, которые показывают профиль пользователя, позволяют пользователю войти в систему или опубликовать новый блог.
Запрос - это то, что браузер пользователя отправляет на ваш сервер при посещении вашего веб-сайта. Этот запрос содержит информацию о том, что хочет сделать пользователь. Например, он может содержать информацию о том, какой URL пользователь хочет посетить, какие данные пользователь хочет отправить на ваш сервер, или какие данные пользователь хочет получить от вашего сервера. Важно знать, что запрос только для чтения. Вы не можете изменить запрос, но можете читать его.
Flight предоставляет простой способ получить доступ к информации о запросе. Вы можете получить доступ к информации о запросе, используя метод Flight::request() Метод возвращает объект Request, который содержит информацию о запросе. Вы можете использовать этот объект для доступа к информации о запросе, такой как URL, метод или данные, которые пользователь отправил на ваш сервер.
Flight::request()
Request
Ответ - это то, что ваш сервер отправляет обратно на браузер пользователя при посещении вашего веб-сайта. Этот ответ содержит информацию о том, что ваш сервер хочет сделать. Например, он может содержать информацию о том, какие данные ваш сервер хочет отправить пользователю, какие данные ваш сервер хочет получить от пользователя, или какие данные ваш сервер хочет сохранить на компьютере пользователя.
Flight предоставляет простой способ отправить ответ браузеру пользователя. Вы можете отправить ответ, используя метод Flight::response() Метод принимает объект Response в качестве аргумента и отправляет ответ браузеру пользователя. Вы можете использовать этот объект, чтобы отправить ответ браузеру пользователя, такой как HTML, JSON или файл. Flight помогает автоматически генерировать некоторые части ответа, чтобы сделать вещи легкими, но в конечном итоге у вас есть контроль над тем, что вы отправляете обратно пользователю.
Flight::response()
Response
Flight обеспечивает встроенную поддержку кэширования на уровне HTTP. Если условие кэширования выполнено, Flight вернет ответ HTTP 304 Not Modified. В следующий раз когда клиент запросит тот же ресурс, их попросят использовать локально кэшированную версию.
304 Not Modified
Вы можете использовать метод lastModified и передать временную метку UNIX для установки даты и времени последнего изменения страницы. Клиент будет продолжать использовать свой кэш до тех пор, пока значение последнего изменения не изменится.
lastModified
Flight::route('/news', function () { Flight::lastModified(1234567890); echo 'Этот контент будет кэширован.'; });
Кэширование ETag аналогично Last-Modified, за исключением того, что вы можете указать любой идентификатор для ресурса:
ETag
Last-Modified
Flight::route('/news', function () { Flight::etag('my-unique-id'); echo 'Этот контент будет кэширован.'; });
Имейте в виду, что вызов методов lastModified или etag устанавливает и проверяет значение кэша. Если значение кэша совпадает между запросами, Flight немедленно отправит ответ HTTP 304 и прекратит обработку.
etag
HTTP 304
Flight помогает генерировать часть заголовков ответа для вас, но большую часть управления тем, что вы отправляете пользователю, вы удерживаете. Иногда вы можете получить доступ к объекту Responseнепосредственно, но большую часть времени вы будете использовать экземпляр Flight для отправки ответа.
Flight
Flight использует ob_start() для буферизации вывода. Это означает, что вы можете использовать echo или print для отправки ответа пользователю, и Flight захватит его и отправит обратно пользователю с соответствующими заголовками.
echo
print
// Это отправит "Привет, Мир!" в браузер пользователя Flight::route('/', function() { echo "Привет, Мир!"; }); // HTTP/1.1 200 OK // Content-Type: text/html // // Привет, Мир!
В качестве альтернативы вы можете вызвать метод write() для добавления к телу также.
write()
// Это отправит "Привет, Мир!" в браузер пользователя Flight::route('/', function() { // многословно, но удобно, когда вам это нужно Flight::response()->write("Привет, Мир!"); // если вы хотите извлечь тело, которое вы установили на этом этапе // вы можете сделать это так $body = Flight::response()->getBody(); });
Вы можете установить код статуса ответа, используя метод status:
status
Flight::route('/@id', function($id) { if($id == 123) { Flight::response()->status(200); echo "Привет, Мир!"; } else { Flight::response()->status(403); echo "Forbidden"; } });
Если вы хотите получить текущий код статуса, вы можете использовать метод status без аргументов:
Flight::response()->status(); // 200
Вы можете установить тело ответа, используя метод write, однако, если вы используете echo или print что-либо, это будет захвачено и отправлено как тело ответа через буферизацию вывода.
write
Flight::route('/', function() { Flight::response()->write("Привет, Мир!"); }); // то же самое, что и Flight::route('/', function() { echo "Привет, Мир!"; });
Если вы хотите очистить тело ответа, вы можете использовать метод clearBody:
clearBody
Flight::route('/', function() { if($someCondition) { Flight::response()->write("Привет, Мир!"); } else { Flight::response()->clearBody(); } });
Вы можете запустить обратный вызов на теле ответа, используя метод addResponseBodyCallback:
addResponseBodyCallback
Flight::route('/users', function() { $db = Flight::db(); $users = $db->fetchAll("SELECT * FROM users"); Flight::render('users_table', ['users' => $users]); }); // Это сжимает все ответы для любого маршрута Flight::response()->addResponseBodyCallback(function($body) { return gzencode($body, 9); });
Вы можете добавлять несколько обратных вызовов, и они будут запускаться в том порядке, в котором они были добавлены. Поскольку это может принимать любой вызываемый объект, он может принимать массив класса [ $class, 'method' ], замыкание $strReplace = function($body) { str_replace('hi', 'there', $body); };, или имя функции 'minify', если у вас есть функция для минификации вашего html-кода, например.
[ $class, 'method' ]
$strReplace = function($body) { str_replace('hi', 'there', $body); };
'minify'
Примечание: Обратные вызовы маршрута не будут работать, если вы используете параметр конфигурации flight.v2.output_buffering.
Если вы хотите, чтобы это применялось только к определенному маршруту, вы можете добавить обратный вызов в сам маршрут:
Flight::route('/users', function() { $db = Flight::db(); $users = $db->fetchAll("SELECT * FROM users"); Flight::render('users_table', ['users' => $users]); // Это сжимает только ответ для этого маршрута Flight::response()->addResponseBodyCallback(function($body) { return gzencode($body, 9); }); });
Вы также можете использовать промежуточное программное обеспечение для применения обратного вызова ко всем маршрутам через промежуточное программное обеспечение:
// MinifyMiddleware.php class MinifyMiddleware { public function before() { // Применить обратный вызов здесь на объект response(). Flight::response()->addResponseBodyCallback(function($body) { return $this->minify($body); }); } protected function minify(string $body): string { // минифицировать тело как-то return $body; } } // index.php Flight::group('/users', function() { Flight::route('', function() { /* ... */ }); Flight::route('/@id', function($id) { /* ... */ }); }, [ new MinifyMiddleware() ]);
Вы можете установить заголовок, такой как тип содержимого ответа, с помощью метода header:
header
// Это отправит "Привет, Мир!" в браузер пользователя в виде простого текста Flight::route('/', function() { Flight::response()->header('Content-Type', 'text/plain'); // или Flight::response()->setHeader('Content-Type', 'text/plain'); echo "Привет, Мир!"; });
Flight предоставляет поддержку для отправки JSON и JSONP ответов. Чтобы отправить JSON-ответ, вы передаете некоторые данные для кодирования JSON:
Flight::json(['id' => 123]);
Вы также можете передать код статуса в качестве второго аргумента:
Flight::json(['id' => 123], 201);
Вы также можете передать аргумент в последнюю позицию для включения красивой печати:
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Если вы изменяете передаваемые в Flight::json() параметры и хотите более простый синтаксис, вы можете просто переопределить метод JSON:
Flight::json()
Flight::map('json', function($data, $code = 200, $options = 0) { Flight::_json($data, $code, true, 'utf-8', $options); } // И теперь его можно использовать так Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);
Если вы хотите отправить JSON-ответ и остановить выполнение, вы можете использовать метод jsonHalt. Это полезно для случаев, когда вы проверяете, возможно, какой-то тип авторизации и если пользователь не авторизован, вы можете немедленно отправить JSON-ответ, очистить текущее тело содержимого и остановить выполнение.
jsonHalt
Flight::route('/users', function() { $authorized = someAuthorizationCheck(); // Проверьте, авторизован ли пользователь if($authorized === false) { Flight::jsonHalt(['error' => 'Unauthorized'], 401); } // Продолжайте с оставшейся частью маршрута });
До v3.10.0 вам пришлось бы сделать что-то вроде этого:
Flight::route('/users', function() { $authorized = someAuthorizationCheck(); // Проверьте, авторизован ли пользователь if($authorized === false) { Flight::halt(401, json_encode(['error' => 'Unauthorized'])); } // Продолжайте с оставшейся частью маршрута });
Для запросов JSONP вы можете необязательно передать имя параметра запроса, которое вы используете для определения вашей функции обратного вызова:
Flight::jsonp(['id' => 123], 'q');
Таким образом, при выполнении GET-запроса с использованием ?q=my_func, вы должны получить вывод:
?q=my_func
my_func({"id":123});
Если вы не передадите имя параметра запроса, он по умолчанию будет jsonp.
jsonp
Вы можете перенаправить текущий запрос, используя метод redirect() и передавая новый URL:
Flight::redirect('/new/location');
По умолчанию Flight отправляет код состояния HTTP 303 ("Смотри другой"). Вы можете указать пользовательский код:
Flight::redirect('/new/location', 401);
Также вы можете указать необязательный HTTP код состояния и сообщение:
Flight::halt(200, 'Скоро вернусь...');
Вызов halt будет отбрасывать любое содержимое ответа до этого момента. Если вы хотите остановить фреймворк и вывести текущий ответ, используйте метод stop:
Вы можете очистить тело ответа и заголовки, используя метод clear(). Это очистит любые заголовки, присвоенные ответу, очистит тело ответа и установит код статуса на 200.
clear()
200
Flight::response()->clear();
Если вы хотите очистить только тело ответа, вы можете использовать метод clearBody():
clearBody()
// Это все еще сохранит все заголовки установленные на объекте response(). Flight::response()->clearBody();
Flight предоставляет встроенную поддержку кэширования на уровне HTTP. Если условие кэширования соблюдается, Flight вернет HTTP 304 Not Modified ответ. При следующем запросе клиента к тому же ресурсу, их попросят использовать локально кэшированную версию.
Если вы хотите кешировать весь ваш ответ, вы можете использовать метод cache() и передать время кэширования.
cache()
// Это закеширует ответ на 5 минут Flight::route('/news', function () { Flight::response()->cache(time() + 300); echo 'Этот контент будет закеширован.'; }); // Кроме того, вы можете использовать строку, которую вы передадите // в метод strtotime() Flight::route('/news', function () { Flight::response()->cache('+5 minutes'); echo 'Этот контент будет закеширован.'; });
Вы можете использовать метод lastModified и передать временную метку UNIX для установки даты и времени последнего изменения страницы. Клиент продолжит использовать свой кэш до тех пор, пока значение последнего изменения не изменится.
Flight::route('/news', function () { Flight::lastModified(1234567890); echo 'Этот контент будет закеширован.'; });
Кэширование ETag аналогично кэшированию Last-Modified, за исключением того, что вы можете указать любой идентификатор, который вы хотите для ресурса:
Flight::route('/news', function () { Flight::etag('my-unique-id'); echo 'Этот контент будет закеширован.'; });
Имейте в виду, что вызов lastModified или etag установит и проверит значение кеша. Если значение кеша одинаково между запросами, Flight немедленно отправит ответ HTTP 304 и прекратит обработку.
Есть вспомогательный метод для загрузки файла. Вы можете использовать метод download и передать путь.
download
Flight::route('/download', function () { Flight::download('/path/to/file.txt'); });
Вместо того чтобы запускать Flight как глобальный статический класс, вы можете опционально запустить его как экземпляр объекта.
require 'flight/autoload.php'; $app = Flight::app(); $app->route('/', function () { echo 'hello world!'; }); $app->start();
Таким образом, вместо вызова статического метода, вы вызывали бы метод экземпляра с тем же именем на объекте Engine.
Можно перенаправить текущий запрос, используя метод redirect и передав новый URL:
redirect
Flight::redirect('/новое/местоположение');
По умолчанию Flight отправляет статусный код HTTP 303. Можно дополнительно установить пользовательский код:
Flight::redirect('/новое/местоположение', 401);
Flight по умолчанию предоставляет некоторые базовые функции шаблонизации. Чтобы отобразить вид шаблона, вызовите метод render с именем файла шаблона и необязательными данными шаблона:
render
Flight::render('hello.php', ['name' => 'Bob']);
Данные шаблона, которые вы передаете, автоматически встраиваются в шаблон и могут быть обращены как локальная переменная. Файлы шаблонов - это просто файлы PHP. Если содержимое файла шаблона hello.php выглядит так:
hello.php
Привет, <?= $name ?>!
То вывод будет:
Привет, Bob!
Вы также можете вручную устанавливать переменные представления с помощью метода set:
Flight::view()->set('name', 'Bob');
Переменная name теперь доступна во всех ваших представлениях. Поэтому вы просто можете сделать:
name
Flight::render('hello');
Обратите внимание, что при указании имени шаблона в методе render вы можете пропустить расширение .php.
.php
По умолчанию Flight будет искать каталог views для файлов шаблонов. Вы можете задать альтернативный путь для ваших шаблонов, установив следующую конфигурацию:
views
Flight::set('flight.views.path', '/путь/к/views');
Часто веб-сайты имеют один файл шаблона макета с переменным содержимым. Чтобы отобразить содержимое для использования в макете, вы можете передать необязательный параметр в метод render.
Flight::render('header', ['heading' => 'Привет'], 'headerContent'); Flight::render('body', ['body' => 'Мир'], 'bodyContent');
Ваше представление затем будет иметь сохраненные переменные с именами headerContent и bodyContent. Затем вы можете отобразить ваш макет так:
headerContent
bodyContent
Flight::render('layout', ['title' => 'Домашняя страница']);
Если файлы шаблонов выглядят так:
header.php:
header.php
<h1><?= $heading ?></h1>
body.php:
body.php
<div><?= $body ?></div>
layout.php:
layout.php
<html> <head> <title><?= $title ?></title> </head> <body> <?= $headerContent ?> <?= $bodyContent ?> </body> </html>
Вывод будет:
<html> <head> <title>Домашняя страница</title> </head> <body> <h1>Привет</h1> <div>Мир</div> </body> </html>
Flight позволяет заменить стандартный движок представлений просто зарегистрировав свой собственный класс представлений. Вот как вы можете использовать Smarty шаблонный движок для ваших представлений:
// Загрузка библиотеки Smarty require './Smarty/libs/Smarty.class.php'; // Регистрация Smarty как класса представления // Также передайте функцию обратного вызова для настройки Smarty при загрузке Flight::register('view', Smarty::class, [], function (Smarty $smarty) { $smarty->setTemplateDir('./templates/'); $smarty->setCompileDir('./templates_c/'); $smarty->setConfigDir('./config/'); $smarty->setCacheDir('./cache/'); }); // Назначение данных шаблона Flight::view()->assign('name', 'Bob'); // Отображение шаблона Flight::view()->display('hello.tpl');
Для полноты вы также должны переопределить стандартный метод render Flight:
Flight::map('render', function(string $template, array $data): void { Flight::view()->assign($data); Flight::view()->display($template); });
Flight предоставляет некоторые базовые возможности шаблонизации по умолчанию.
Если вам нужны более сложные потребности в шаблонизации, обратитесь к примерам Smarty и Latte в разделе Пользовательские Виды.
Чтобы отобразить представление шаблона, вызовите метод render с именем файла шаблона и необязательными данными шаблона:
Данные шаблона, которые вы передаете, автоматически вставляются в шаблон и могут быть использованы как локальная переменная. Файлы шаблонов представляют собой просто файлы PHP. Если содержимое файла шаблона hello.php таково:
Вы также можете вручную устанавливать переменные представления, используя метод set:
Переменная name теперь доступна во всех ваших представлениях. Поэтому вы можете просто сделать:
Обратите внимание, что при указании имени шаблона в методе render вы можете опустить расширение .php.
По умолчанию Flight будет искать каталог views для файлов шаблонов. Вы можете указать альтернативный путь для ваших шаблонов, установив следующую конфигурацию:
Flight::set('flight.views.path', '/путь/к/шаблонам');
Часто в веб-сайтах есть единственный файл шаблона макета с изменяющимися содержимым. Чтобы отобразить содержимое, которое будет использоваться в макете, вы можете передать необязательный параметр в метод render.
У вас в представлении будут сохранены переменные с именами headerContent и bodyContent. Затем вы можете отобразить свой макет, сделав так:
Flight позволяет заменить используемый по умолчанию движок представления просто зарегистрировав свой собственный класс представления.
Вот как вы будете использовать Smarty шаблонный движок для ваших представлений:
// Загрузка библиотеки Smarty require './Smarty/libs/Smarty.class.php'; // Регистрация Smarty как класса представления // Также передайте функцию обратного вызова для настройки Smarty при загрузке Flight::register('view', Smarty::class, [], function (Smarty $smarty) { $smarty->setTemplateDir('./templates/'); $smarty->setCompileDir('./templates_c/'); $smarty->setConfigDir('./config/'); $smarty->setCacheDir('./cache/'); }); // Назначение данных шаблона Flight::view()->assign('name', 'Bob'); // Отобразить шаблон Flight::view()->display('hello.tpl');
Для полноты вы должны также переопределить метод render по умолчанию Flight:
Вот как вы будете использовать Latte шаблонный движок для ваших представлений:
// Регистрация Latte как класса представления // Также передайте функцию обратного вызова для настройки Latte при загрузке Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) { // Здесь Latte будет кешировать ваши шаблоны для ускорения работы // Одна из удобных особенностей Latte заключается в том, что она автоматически обновляет // кеш при внесении изменений в ваши шаблоны! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Скажите Latte, где будет находиться корневой каталог для ваших представлений. $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/')); }); // И завершите так, чтобы вы могли правильно использовать Flight::render() Flight::map('render', function(string $template, array $data): void { // Это похоже на $latte_engine->render($template, $data); echo Flight::view()->render($template, $data); });
Fat-Free (ласково известный как F3) - это мощный, но простой в использовании микро-фреймворк на PHP, разработанный для помощи в создании динамичных и надежных веб-приложений - быстро!
Flight сравнивается с Fat-Free во многих аспектах и, вероятно, ближе всего по функциональности и простоте. У Fat-Free есть много функций, которых нет у Flight, но у него также есть много функций, которые есть у Flight. Fat-Free начинает устаревать и уже не так популярен, как раньше.
Обновления становятся менее частыми, и сообщество не так активно, как раньше. Код достаточно прост, но иногда отсутствие дисциплины в синтаксисе может затруднить его чтение и понимание. Он работает для PHP 8.3, но сам код все еще выглядит так, будто он создан для PHP 5.3.
GET
DB\SQL
active-record
Cache
beforeroute
afterroute
HIVE
Flight спроектирован для того, чтобы быть расширяемым фреймворком. Фреймворк поставляется с набором стандартных методов и компонентов, но позволяет вам создавать свои собственные методы, регистрировать свои классы или даже переопределять существующие классы и методы.
Если вам нужен Контейнер внедрения зависимостей (DIC - Dependency Injection Container), перейдите на страницу Контейнер внедрения зависимостей.
Чтобы сопоставить свой собственный простой пользовательский метод, используйте функцию map:
// Сопоставить свой метод Flight::map('hello', function (string $name) { echo "привет $name!"; }); // Вызов вашего пользовательского метода Flight::hello('Боб');
Хотя возможно создавать простые пользовательские методы, рекомендуется просто создавать стандартные функции на PHP. Это обеспечивает автозаполнение в среде разработки и упрощает чтение. Эквивалент приведенного выше кода будет:
function hello(string $name) { echo "привет $name!"; } hello('Боб');
Это используется более часто, когда вам нужно передать переменные в ваш метод, чтобы получить ожидаемое значение. Использование метода register() вроде приведенного ниже больше подходит для передачи конфигурации, а затем вызова вашего предварительно настроенного класса.
register()
Чтобы зарегистрировать свой собственный класс и настроить его, используйте функцию register:
// Зарегистрировать ваш класс Flight::register('user', User::class); // Получить экземпляр вашего класса $user = Flight::user();
Метод регистрации также позволяет передавать параметры в конструктор вашего класса. Таким образом, при загрузке вашего пользовательского класса он будет предварительно инициализирован. Вы можете определить параметры конструктора, передавая дополнительный массив. Вот пример загрузки подключения к базе данных:
// Зарегистрировать класс с параметрами конструктора Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']); // Получить экземпляр вашего класса // Это создаст объект с определенными параметрами // // new PDO('mysql:host=localhost;dbname=test','user','pass'); // $db = Flight::db(); // и если вам понадобится он позже в вашем коде, просто вызовите тот же метод снова class SomeController { public function __construct() { $this->db = Flight::db(); } }
Если вы передадите дополнительный параметр обратного вызова, он будет выполнен сразу после создания объекта класса. Это позволяет вам выполнить любые процедуры настройки для вашего нового объекта. Функция обратного вызова принимает один параметр, экземпляр нового объекта.
// Объект, который был создан, будет передан обратному вызову Flight::register( 'db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass'], function (PDO $db) { $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } );
По умолчанию каждый раз, когда вы загружаете ваш класс, вы получите общий экземпляр. Чтобы получить новый экземпляр класса, просто передайте false в качестве параметра:
// Общий экземпляр класса $shared = Flight::db(); // Новый экземпляр класса $new = Flight::db(false);
Имейте в виду, что сопоставленные методы имеют приоритет над зарегистрированными классами. Если вы объявите оба с одинаковым именем, будет вызван только сопоставленный метод.
Flight позволяет вам переопределять его стандартную функциональность под ваши нужды, не изменяя код. Вы можете просмотреть все методы, которые вы можете переопределить здесь.
Например, когда Flight не может соотнести URL с маршрутом, он вызывает метод notFound, который отправляет общий ответ HTTP 404. Вы можете переопределить это поведение, используя метод map:
Flight::map('notFound', function() { // Показать настраиваемую страницу 404 include 'errors/404.html'; });
Flight также позволяет заменять основные компоненты фреймворка. Например, вы можете заменить стандартный класс Router своим собственным пользовательским классом:
// Зарегистрируйте ваш пользовательский класс Flight::register('router', MyRouter::class); // Когда Flight загружает экземпляр Router, он загрузит ваш класс $myrouter = Flight::router();
Однако методы фреймворка вроде map и register не могут быть переопределены. Вы получите ошибку, если попытаетесь сделать это.
Flight предоставляет поддержку для отправки JSON и JSONP ответов. Чтобы отправить ответ в формате JSON, вы передаете данные, которые будут закодированы в JSON:
Для запросов JSONP вы можете, опционально, передать имя параметра запроса, которое вы используете для определения функции обратного вызова:
Таким образом, при выполнении GET-запроса с использованием ?q=my_func, вы должны получить следующий вывод:
Если вы не передаете имя параметра запроса, оно будет по умолчанию установлено на jsonp.
Slim - это PHP микрофреймворк, который помогает вам быстро писать простые, но мощные веб-приложения и API.
Многие идеи для некоторых функций v3 Flight фактически были взяты из Slim. Группировка маршрутов и выполнение промежуточного ПО в определенном порядке - это две функции, которые были вдохновлены Slim. Slim v3 был создан в стремлении к простоте, но есть смешанные отзывы относительно v4.
Автозагрузка - это концепция в PHP, где вы указываете каталог или каталоги для загрузки классов. Это намного более выгодно, чем использование require или include для загрузки классов. Это также требование для использования пакетов Composer.
require
include
По умолчанию любой класс Flight автоматически загружается благодаря composer. Однако, если вы хотите загружать свои собственные классы, вы можете использовать метод Flight::path() для указания каталога для загрузки классов.
Flight::path()
Допустим, у нас есть древо каталогов, похожее на следующее:
# Пример пути /home/user/project/my-flight-project/ ├── app │ ├── cache │ ├── config │ ├── controllers - содержит контроллеры для этого проекта │ ├── translations │ ├── UTILS - содержит классы только для этого приложения (это все заглавные буквы специально для примера позже) │ └── views └── public └── css └── js └── index.php
Вы могли заметить, что это та же структура файлов, что и на этом сайте документации.
Вы можете указать каждый каталог для загрузки вот так:
/** * public/index.php */ // Добавить путь к автозагрузчику Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); /** * app/controllers/MyController.php */ // не требуется использование пространства имен // Рекомендуется, чтобы все загружаемые классы были в стиле Pascal (каждое слово с заглавной буквы, без пробелов) // Начиная с версии 3.7.2, вы можете использовать Pascal_Snake_Case для имен ваших классов, запустив Loader::setV2ClassLoading(false); class MyController { public function index() { // сделать что-то } }
Если у вас есть пространства имен, на самом деле становится очень легко это реализовать. Вы должны использовать метод Flight::path() для указания корневого каталога (не корневого документа или папки public/) вашего приложения.
public/
/** * public/index.php */ // Добавить путь к автозагрузчику Flight::path(__DIR__.'/../');
Теперь вот как может выглядеть ваш контроллер. Посмотрите на пример ниже, но обратите внимание на комментарии для важной информации.
/** * app/controllers/MyController.php */ // пространства имен обязательны // пространства имен такие же, как структура каталогов // пространства имен должны следовать тому же регистру, что и структура каталогов // пространства и каталоги не могут иметь нижние подчеркивания (если не установлено Loader::setV2ClassLoading(false)) namespace app\controllers; // Рекомендуется, чтобы все загружаемые классы были в стиле Pascal (каждое слово с заглавной буквы, без пробелов) // Начиная с версии 3.7.2, вы можете использовать Pascal_Snake_Case для имен ваших классов, запустив Loader::setV2ClassLoading(false); class MyController { public function index() { // сделать что-то } }
И если вы хотите автоматически загрузить класс в каталоге utils, вы сделали бы практически то же самое:
/** * app/UTILS/ArrayHelperUtil.php */ // пространство имен должно соответствовать структуре каталога и регистру (обратите внимание на каталог UTILS в верхнем регистре // как в дереве файлов выше) namespace app\UTILS; class ArrayHelperUtil { public function changeArrayCase(array $array) { // сделать что-то } }
Начиная с версии 3.7.2, вы можете использовать Pascal_Snake_Case для имен ваших классов, запустив Loader::setV2ClassLoading(false);. Это позволит вам использовать подчеркивания в именах ваших классов. Это не рекомендуется, но это доступно для тех, кто нуждается в этом.
Loader::setV2ClassLoading(false);
/** * public/index.php */ // Добавить путь к автозагрузчику Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); Loader::setV2ClassLoading(false); /** * app/controllers/My_Controller.php */ // не требуется использование пространства имен class My_Controller { public function index() { // сделать что-то } }
Эта страница поможет вам устранить общие проблемы, с которыми вы можете столкнуться при использовании Flight.
Если вы видите ошибку 404 Страница не найдена (но вы клянетесь своей жизнью, что она действительно там и это не опечатка), на самом деле это может быть проблема с возвращением значения в конечной точке маршрута вместо простого его вывода. Причина этого намеренная, но некоторым разработчикам это может ускользнуть.
Flight::route('/hello', function(){ // Это может вызвать ошибку 404 Страница не найдена return 'Hello World'; }); // Что вам, вероятно, нужно Flight::route('/hello', function(){ echo 'Hello World'; });
Причина заключается в том, что в маршрутизаторе встроен специальный механизм, который обрабатывает возвращаемый вывод как инструкцию "перейти к следующему маршруту". Вы можете ознакомиться с этим поведением в разделе Маршрутизация.
Могут быть несколько причин, почему это происходит. Ниже приведены некоторые примеры, но убедитесь также, что вы изучили раздел автозагрузка.
Самая распространенная причина в том, что имя класса не совпадает с именем файла.
Если у вас есть класс с именем MyClass, то файл должен иметь имя MyClass.php. Если у вас есть класс с именем MyClass и файл назван myclass.php, то автозагрузчик не сможет его найти.
MyClass
MyClass.php
myclass.php
Если вы используете пространства имен, то пространство имен должно соответствовать структуре каталогов.
// код // если ваш MyController находится в каталоге app/controllers и у него есть пространство имен // это не сработает. Flight::route('/hello', 'MyController->hello'); // вам нужно выбрать один из этих вариантов Flight::route('/hello', 'app\controllers\MyController->hello'); // или если у вас есть оператор use вверху use app\controllers\MyController; Flight::route('/hello', [ MyController::class, 'hello' ]); // также можно написать Flight::route('/hello', MyController::class.'->hello'); // или так... Flight::route('/hello', [ 'app\controllers\MyController', 'hello' ]);
path()
В контрольном приложении это определяется внутри файла config.php, но для того чтобы ваши классы были найдены, убедитесь, что метод path() определен (вероятно, к корневому каталогу вашего каталога) прежде чем пытаться его использовать.
config.php
// Добавьте путь к автозагрузчику Flight::path(__DIR__.'/../');
Если вы используете Composer, вы можете запустить следующую команду:
composer require flightphp/core
ИЛИ вы можете скачать файлы напрямую и извлечь их в ваш веб-каталог.
Для Apache отредактируйте ваш файл .htaccess следующим образом:
.htaccess
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L]
Примечание: Если вам нужно использовать flight в подкаталоге, добавьте строку RewriteBase /subdir/ сразу после RewriteEngine On. Примечание: Если вы хотите защитить все файлы сервера, такие как файл db или env. Поместите это в свой файл .htaccess:
Примечание: Если вам нужно использовать flight в подкаталоге, добавьте строку RewriteBase /subdir/ сразу после RewriteEngine On.
RewriteBase /subdir/
RewriteEngine On
Примечание: Если вы хотите защитить все файлы сервера, такие как файл db или env. Поместите это в свой файл .htaccess:
RewriteEngine On RewriteRule ^(.*)$ index.php
Для Nginx добавьте следующее в ваше объявление сервера:
server { location / { try_files $uri $uri/ /index.php; } }
<?php // Если вы используете Composer, требуется автозагрузчик. require 'vendor/autoload.php'; // если вы не используете Composer, загружайте фреймворк напрямую // require 'flight/Flight.php'; // Затем определите маршрут и назначьте функцию для обработки запроса. Flight::route('/', function () { echo 'hello world!'; }); // Наконец, запустите фреймворк. Flight::start();
Авторское право © 2024 @mikecao, @n0nag0n
2024
@mikecao, @n0nag0n
Настоящим предоставляется разрешение на бесплатное использование любому лицу, получившему копию данного программного обеспечения и сопроводительной документации (далее - "Программное обеспечение"), без ограничений, включая право использовать, копировать, изменять, объединять, публиковать, распространять, подлицензировать и/или продавать копии Программного обеспечения и разрешать лицам, которым предоставляется Программное обеспечение, сделать то же самое, при соблюдении следующих условий:
Вышеприведенное уведомление об авторском праве и это уведомление о разрешении должны быть включены во все копии или существенные части Программного обеспечения.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ "КАК ЕСТЬ", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ И НЕНАРУШЕНИЯ. НИ В КОЕМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ОТВЕТСТВЕННОСТИ, ВЫТЕКАЮЩЕЙ ИЗ ДОГОВОРА, ДЕЛИКТА ИЛИ ИНАЧЕ, В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ ОБРАЩЕНИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
Flight - быстрая, простая, расширяемая структура для PHP. Он довольно универсален и может использоваться для создания любого веб-приложения. Он создан с учетом простоты и написан таким образом, чтобы его легко понять и использовать.
Flight - отличная начальная структура для тех, кто нов в PHP и хочет научиться создавать веб-приложения. Это также отличная структура для опытных разработчиков, которые хотят больше контроля над своими веб-приложениями. Он разработан для легкого создания RESTful API, простого веб-приложения или сложного веб-приложения.
<?php // если установлен с помощью композера require 'vendor/autoload.php'; // или если установлен вручную из zip-файла // require 'flight/Flight.php'; Flight::route('/', function() { echo 'привет, мир!'; }); Flight::route('/json', function() { Flight::json(['привет' => 'мир']); }); Flight::start();
Довольно просто, верно? Узнайте больше о Flight в документации!
Существует пример приложения, который может помочь вам начать работу со структурой Flight. Перейдите на flightphp/skeleton для получения инструкций о том, как начать! Вы также можете посетить страницу примеров для вдохновения на то, что можно сделать с Flight.
Мы находимся в чате Matrix с нами на #flight-php-framework:matrix.org.
Есть два способа внести вклад в Flight:
Flight требует PHP 7.4 или выше.
Примечание: PHP 7.4 поддерживается, потому что на текущий момент написания (2024 год) PHP 7.4 является версией по умолчанию для некоторых долгосрочных дистрибутивов Linux. Принудительное переход на PHP >8 вызвало бы много проблем для этих пользователей. Структура также поддерживает PHP >8.
Flight выпущен под лицензией MIT.
overclokk/cookie это простая библиотека для управления куки в вашем приложении.
Установка проста с помощью composer.
composer require overclokk/cookie
Использование так же просто, как регистрация нового метода в классе Flight.
use Overclokk\Cookie\Cookie; /* * Установите в вашем файле bootstrap или public/index.php */ Flight::register('cookie', Cookie::class); /** * ExampleController.php */ class ExampleController { public function login() { // Установить куки // вам нужно, чтобы это было false, чтобы получить новый экземпляр // используйте комментарий ниже, если хотите автозаполнение /** @var \Overclokk\Cookie\Cookie $cookie */ $cookie = Flight::cookie(false); $cookie->set( 'stay_logged_in', // имя куки '1', // значение, которое вы хотите установить 86400, // количество секунд, на которое должно длиться куки '/', // путь, по которому куки будут доступны 'example.com', // домен, на котором будут доступны куки true, // куки будут передаваться только через безопасное соединение HTTPS true // куки будут доступны только через протокол HTTP ); // необязательно, если вы хотите сохранить значения по умолчанию // и иметь быстрый способ установить куки на длительное время $cookie->forever('stay_logged_in', '1'); } public function home() { // Проверить, есть ли у вас куки if (Flight::cookie()->has('stay_logged_in')) { // поместите их в область панели управления, например. Flight::redirect('/dashboard'); } } }
defuse/php-encryption - это библиотека, которая может быть использована для шифрования и дешифрования данных. Начать использование довольно просто для начала шифрования и дешифрования данных. У них есть отличное руководство, которое помогает объяснить основы использования библиотеки, а также важные аспекты безопасности, касающиеся шифрования.
Установка проста с помощью композитора.
composer require defuse/php-encryption
Затем вам нужно сгенерировать ключ шифрования.
vendor/bin/generate-defuse-key
Это выдаст ключ, который вам нужно будет хранить в надежном месте. Вы можете сохранить ключ в вашем файле app/config/config.php в массиве внизу файла. Хотя это не идеальное место, это хотя бы что-то.
app/config/config.php
Теперь, когда у вас есть библиотека и ключ шифрования, вы можете начать шифровать и дешифровать данные.
use Defuse\Crypto\Crypto; use Defuse\Crypto\Key; /* * Set in your bootstrap or public/index.php file */ // Метод шифрования Flight::map('encrypt', function($raw_data) { $encryption_key = /* $config['encryption_key'] or a file_get_contents of where you put the key */; return Crypto::encrypt($raw_data, Key::loadFromAsciiSafeString($encryption_key)); }); // Метод дешифрования Flight::map('decrypt', function($encrypted_data) { $encryption_key = /* $config['encryption_key'] or a file_get_contents of where you put the key */; try { $raw_data = Crypto::decrypt($encrypted_data, Key::loadFromAsciiSafeString($encryption_key)); } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // Атака! Загружен неверный ключ или зашифрованный текст был изменен с момента его создания -- либо поврежден в базе данных, либо намеренно изменен Злодеем, пытающимся провести атаку. // ... обработайте этот случай так, чтобы он подходил для вашего приложения ... } return $raw_data; }); Flight::route('/encrypt', function() { $encrypted_data = Flight::encrypt('Это секрет'); echo $encrypted_data; }); Flight::route('/decrypt', function() { $encrypted_data = '...'; // Получите зашифрованные данные откуда-нибудь $decrypted_data = Flight::decrypt($encrypted_data); echo $decrypted_data; });
Легкий, простой и автономный класс кэширования PHP в файле
Преимущества
Нажмите здесь для просмотра кода.
Установите через composer:
composer require wruczek/php-file-cache
Использование довольно просто.
use Wruczek\PhpFileCache\PhpFileCache; $app = Flight::app(); // Вы передаете каталог, в котором будет сохранен кэш, в конструктор $app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) { // Это гарантирует, что кэш используется только в режиме продакшн // ENVIRONMENT - это константа, которая устанавливается в вашем файле запуска или в другом месте в вашем приложении $cache->setDevMode(ENVIRONMENT === 'development'); });
Затем вы можете использовать его в своем коде следующим образом:
// Получить экземпляр кэша $cache = Flight::cache(); $data = $cache->refreshIfExpired('simple-cache-test', function () { return date("H:i:s"); // возвращает данные для кэширования }, 10); // 10 секунд // или $data = $cache->retrieve('simple-cache-test'); if(empty($data)) { $data = date("H:i:s"); $cache->store('simple-cache-test', $data, 10); // 10 секунд }
Посетите https://github.com/Wruczek/PHP-File-Cache для полной документации и убедитесь, что вы посмотрите папку examples.
Это модуль разрешений, который можно использовать в ваших проектах, если у вас есть несколько ролей в вашем приложении, и каждая роль имеет немного разную функциональность. Этот модуль позволяет определить разрешения для каждой роли, а затем проверить, имеет ли текущий пользователь разрешение на доступ к определенной странице или выполнение определенного действия.
Нажмите сюда для репозитория на GitHub.
Запустите composer require flightphp/permissions и вы готовы к работе!
composer require flightphp/permissions
Сначала вам нужно настроить ваши разрешения, затем сообщить вашему приложению, что означают эти разрешения. В конечном итоге вы проверите ваши разрешения с помощью $Permissions->has(), ->can() или is(). has() и can() имеют одинаковую функциональность, но названы по-разному, чтобы сделать ваш код более читаемым.
$Permissions->has()
->can()
is()
has()
can()
Давайте предположим, что у вас есть функция в вашем приложении, которая проверяет, вошел ли пользователь в систему. Вы можете создать объект разрешений следующим образом:
// index.php require 'vendor/autoload.php'; // некоторый код // затем у вас вероятно есть что-то, что говорит вам, какая текущая роль у человека // скорее всего у вас есть что-то, откуда вы извлекаете текущую роль // из переменной сеанса, которая определяет это // после входа в систему у кого-то должна быть роль 'guest' или 'public'. $current_role = 'admin'; // настройка разрешений $permission = new \flight\Permission($current_role); $permission->defineRule('loggedIn', function($current_role) { return $current_role !== 'guest'; }); // Вам вероятно захочется сохранить этот объект где-то в Flight Flight::set('permission', $permission);
Затем в контроллере где-то вы можете иметь что-то вроде этого.
<?php // некоторый контроллер class SomeController { public function someAction() { $permission = Flight::get('permission'); if ($permission->has('loggedIn')) { // сделать что-то } else { // сделать что-то другое } } }
Вы также можете использовать это для отслеживания, есть ли у них разрешение на выполнение определенного действия в вашем приложении. Например, если у вас есть способ, как пользователи могут взаимодействовать с публикацией в вашем программном обеспечении, вы можете проверить, имеют ли они разрешение на выполнение определенных действий.
$current_role = 'admin'; // настройка разрешений $permission = new \flight\Permission($current_role); $permission->defineRule('post', function($current_role) { if($current_role === 'admin') { $permissions = ['create', 'read', 'update', 'delete']; } else if($current_role === 'editor') { $permissions = ['create', 'read', 'update']; } else if($current_role === 'author') { $permissions = ['create', 'read']; } else if($current_role === 'contributor') { $permissions = ['create']; } else { $permissions = []; } return $permissions; }); Flight::set('permission', $permission);
Затем где-то в контроллере...
class PostController { public function create() { $permission = Flight::get('permission'); if ($permission->can('post.create')) { // сделать что-то } else { // сделать что-то еще } } }
Вы можете внедрять зависимости в замыкание, которое определяет разрешения. Это полезно, если у вас есть какой-то переключатель, идентификатор или любая другая точка данных, которую вы хотите проверить. То же самое работает для вызовов вида Class->Method, за исключением того, что аргументы определяются в методе.
$Permission->defineRule('order', function(string $current_role, MyDependency $MyDependency = null) { // ... код }); // в вашем файле контроллера public function createOrder() { $MyDependency = Flight::myDependency(); $permission = Flight::get('permission'); if ($permission->can('order.create', $MyDependency)) { // сделать что-то } else { // сделать что-то еще } }
namespace MyApp; class Permissions { public function order(string $current_role, MyDependency $MyDependency = null) { // ... код } }
Вы также можете использовать классы для определения ваших разрешений. Это полезно, если у вас много разрешений, и вы хотите, чтобы ваш код был чистым. Вы можете сделать что-то вроде этого:
<?php // код инициализации $Permissions = new \flight\Permission($current_role); $Permissions->defineRule('order', 'MyApp\Permissions->order'); // myapp/Permissions.php namespace MyApp; class Permissions { public function order(string $current_role, int $user_id) { // Предположим, что вы это настроили заранее /** @var \flight\database\PdoWrapper $db */ $db = Flight::db(); $allowed_permissions = [ 'read' ]; // каждый может просматривать заказ if($current_role === 'manager') { $allowed_permissions[] = 'create'; // менеджеры могут создавать заказы } $some_special_toggle_from_db = $db->fetchField('SELECT some_special_toggle FROM settings WHERE id = ?', [ $user_id ]); if($some_special_toggle_from_db) { $allowed_permissions[] = 'update'; // если у пользователя есть особый переключатель, он может обновлять заказы } if($current_role === 'admin') { $allowed_permissions[] = 'delete'; // администраторы могут удалять заказы } return $allowed_permissions; } }
Здесь примечательно то, что есть также сокращение, которое можно использовать (которое также может быть кешировано!!!), где вы просто говорите классу разрешений сопоставить все методы в классе в разрешения. Поэтому, если у вас есть метод с именем order() и метод с именем company(), они будут автоматически сопоставлены, и вы сможете просто выполнить $Permissions->has('order.read') или $Permissions->has('company.read'), и это сработает. Определение этого очень сложно, так что держитесь здесь со мной. Просто вам нужно сделать это:
order()
company()
$Permissions->has('order.read')
$Permissions->has('company.read')
Создайте класс разрешений, которые вы хотите сгруппировать вместе.
class MyPermissions { public function order(string $current_role, int $order_id = 0): array { // код определения разрешений return $permissions_array; } public function company(string $current_role, int $company_id): array { // код определения разрешений return $permissions_array; } }
Затем сделайте разрешения обнаруживаемыми с использованием этой библиотеки.
$Permissions = new \flight\Permission($current_role); $Permissions->defineRulesFromClassMethods(MyApp\Permissions::class); Flight::set('permissions', $Permissions);
Наконец, вызовите разрешение в вашей кодовой базе, чтобы проверить, разрешено ли пользователю выполнение заданного разрешения.
class SomeController { public function createOrder() { if(Flight::get('permissions')->can('order.create') === false) { die('Вы не можете создать заказ. Извините!'); } } }
Для включения кэширования, см. простую библиотеку wruczak/phpfilecache. Пример включения приведен ниже.
// этот $app может быть частью вашего кода, или // вы можете просто передать null, и он извлечет из Flight::app() в конструкторе $app = Flight::app(); // Теперь для этого принимается файловое кэширование. Другие могут легко // быть добавлены в будущем. $Cache = new Wruczek\PhpFileCache\PhpFileCache; $Permissions = new \flight\Permission($current_role, $app, $Cache); $Permissions->defineRulesFromClassMethods(MyApp\Permissions::class, 3600); // 3600 - это сколько секунд кэшировать это. Оставьте это, чтобы не использовать кэширование
И впереди!
Flight невероятно расширяем. Есть ряд плагинов, которые можно использовать для добавления функциональности в ваше приложение Flight. Некоторые официально поддерживаются командой Flight, а другие являются микро/лайт библиотеками, чтобы помочь вам начать.
Кэширование - отличный способ ускорить ваше приложение. Есть несколько библиотек кэширования, которые можно использовать с Flight.
Отладка критически важна при разработке в локальной среде. Есть несколько плагинов, которые могут улучшить ваш опыт отладки.
Базы данных являются основой для большинства приложений. Это то, как вы сохраняете и извлекаете данные. Некоторые библиотеки баз данных просто обертки для написания запросов, а некоторые - полноценные ORM.
Сессии действительно не очень полезны для API, но для создания веб-приложения они могут быть критически важны для поддержания состояния и информации о входе.
Шаблонизация является основой любого веб-приложения с интерфейсом пользователя. Есть несколько шаблонизаторов, которые можно использовать с Flight.
У вас есть плагин, который вы хотели бы поделиться? Отправьте запрос на добавление его в список!
Flight поставляется с классом помощника для PDO. Он позволяет легко выполнять запросы к базе данных с использованием всех этих заморочек с подготовкой/выполнением/fetchAll(). Это значительно упрощает ваш способ выполнения запросов к базе данных. Каждая строка результата возвращается как класс Flight Collection, который позволяет вам получать доступ к данным с использованием синтаксиса массива или объекта.
// Регистрация класса помощника PDO Flight::register('db', \flight\database\PdoWrapper::class, ['mysql:host=localhost;dbname=cool_db_name', 'user', 'pass', [ PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'utf8mb4\'', PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ] ]);
Этот объект расширяет PDO, поэтому все обычные методы PDO доступны. Для упрощения выполнения запросов к базе данных были добавлены следующие методы:
runQuery(string $sql, array $params = []): PDOStatement
Используйте это для INSERTS, UPDATES или если вы планируете использовать SELECT в цикле while
$db = Flight::db(); $statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]); while($row = $statement->fetch()) { // ... } // Или запись в базу данных $db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]); $db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);
fetchField(string $sql, array $params = []): mixed
Извлекает первое поле из запроса
$db = Flight::db(); $count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);
fetchRow(string $sql, array $params = []): array
Извлекает одну строку из запроса
$db = Flight::db(); $row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]); echo $row['name']; // или echo $row->name;
fetchAll(string $sql, array $params = []): array
Извлекает все строки из запроса
$db = Flight::db(); $rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]); foreach($rows as $row) { echo $row['name']; // или echo $row->name; }
IN()
Здесь также есть удобная оболочка для оператора IN(). Просто передайте один вопросительный знак в качестве заполнителя для IN(), а затем массив значений. Вот пример того, как это может выглядеть:
$db = Flight::db(); $name = 'Bob'; $company_ids = [1,2,3,4,5]; $rows = $db->fetchAll("SELECT id, name FROM table WHERE name = ? AND company_id IN (?)", [ $name, $company_ids ]);
// Пример маршрута и как использовать эту оболочку Flight::route('/users', function () { // Получить всех пользователей $users = Flight::db()->fetchAll('SELECT * FROM users'); // Отправить всех пользователей $statement = Flight::db()->runQuery('SELECT * FROM users'); while ($user = $statement->fetch()) { echo $user['name']; // или echo $user->name; } // Получить одного пользователя $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]); // Получить одно значение $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users'); // Особый синтаксис IN() для помощи (убедитесь, что IN написано заглавными буквами) $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]); // вы также можете сделать так $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']); // Вставить нового пользователя Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']); $insert_id = Flight::db()->lastInsertId(); // Обновить пользователя Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]); // Удалить пользователя Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]); // Получить количество затронутых строк $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']); $affected_rows = $statement->rowCount(); });
Менеджер сессий PHP (неблокирующий, flash, сегмент, шифрование сессий). Использует PHP open_ssl для необязательного шифрования/дешифрования данных сессии. Поддерживает File, MySQL, Redis и Memcached.
Нажмите сюда, чтобы просмотреть код.
Установите с помощью composer.
composer require ghostff/session
Вам не нужно передавать что-либо, чтобы использовать настройки по умолчанию для вашей сессии. Вы можете прочитать о других настройках в [Github Readme] (https://github.com/Ghostff/Session).
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); // важно помнить, что вам нужно подтвердить вашу сессию при каждой загрузке страницы // или вам нужно запустить auto_commit в вашей конфигурации.
Вот простой пример того, как вы могли бы использовать это.
Flight::route('POST /login', function() { $session = Flight::session(); // сделайте здесь логику входа // проверка пароля и т. д. // если вход прошел успешно $session->set('is_logged_in', true); $session->set('user', $user); // каждый раз, когда вы записываете в сессию, вы должны подтвердить ее нарочно. $session->commit(); }); // Эта проверка может быть в логике ограниченной страницы или обернута с помощью промежуточного программного обеспечения. Flight::route('/some-restricted-page', function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } // сделайте здесь логику ограниченной страницы }); // версия промежуточного программного обеспечения Flight::route('/some-restricted-page', function() { // обычная логика страницы })->addMiddleware(function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } });
Вот более сложный пример того, как вы могли бы использовать это.
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); // установите пользовательский путь к файлу конфигурации вашей сессии и укажите случайную строку для идентификатора сессии $app->register('session', Session::class, [ 'путь/к/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { // или вы можете вручную переопределить параметры конфигурации $session->updateConfiguration([ // если вы хотите хранить данные сеанса в базе данных (хорошо, если вам нужна функциональность типа "разлогиниться со всех устройств") Session::CONFIG_DRIVER => Ghostff\Session\Drivers\MySql::class, Session::CONFIG_ENCRYPT_DATA => true, Session::CONFIG_SALT_KEY => hash('sha256', 'my-super-S3CR3T-salt'), // пожалуйста, измените это на что-то другое Session::CONFIG_AUTO_COMMIT => true, // сделайте это только если это необходимо или трудно подтвердить вашу сессию. // кроме того, вы можете сделать Flight::after('start', function() { Flight::session()->commit(); }); Session::CONFIG_MYSQL_DS => [ 'driver' => 'mysql', # Драйвер базы данных для PDO dns, например (mysql:host=...;dbname=...) 'host' => '127.0.0.1', # Хост базы данных 'db_name' => 'my_app_database', # Имя базы данных 'db_table' => 'sessions', # Таблица базы данных 'db_user' => 'root', # Имя пользователя базы данных 'db_pass' => '', # Пароль базы данных 'persistent_conn'=> false, # Избегайте накладных расходов на установку нового соединения каждый раз, когда скрипту необходимо общаться с базой данных, что приводит к более быстрой веб-приложению. НАЙДИТЕ ЗА ПОДСТАВКУ САМИ ] ]); } );
Вы устанавливаете данные вашей сессии, и они не сохраняются между запросами? Возможно, вы забыли подтвердить данные вашей сессии. Вы можете сделать это, вызвав $session->commit() после установки данных вашей сессии.
$session->commit()
Flight::route('POST /login', function() { $session = Flight::session(); // сделайте здесь логику входа // проверка пароля и т. д. // если вход прошел успешно $session->set('is_logged_in', true); $session->set('user', $user); // каждый раз, когда вы записываете в сессию, вы должны подтвердить ее нарочно. $session->commit(); });
Другой способ решить эту проблему заключается в том, что при настройке вашего сервиса сессий вам нужно установить auto_commit в true в вашей конфигурации. Это автоматически подтвердит ваши данные сессии после каждого запроса.
auto_commit
$app->register('session', Session::class, [ 'путь/к/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { $session->updateConfiguration([ Session::CONFIG_AUTO_COMMIT => true, ]); } );
Кроме того, вы можете использовать Flight::after('start', function() { Flight::session()->commit(); }); для подтверждения ваших данных сессии после каждого запроса.
Flight::after('start', function() { Flight::session()->commit(); });
Посетите Github Readme для полной документации. Параметры конфигурации хорошо задокументированы в default_config.php файле самого кода. Код прост в понимании, если вы захотите изучить этот пакет самостоятельно.
Взлетная полоса — это приложение CLI, которое помогает управлять приложениями Flight. Он может генерировать контроллеры, отображать все маршруты и многое другое. Он основан на отличной библиотеке adhocore/php-cli.
Нажмите здесь, чтобы просмотреть код.
Установите через composer.
composer require flightphp/runway
Первый раз, когда вы запускаете Взлетную полосу, она проведет вас через процесс настройки и создаст файл конфигурации .runway.json в корне вашего проекта. Этот файл будет содержать несколько необходимых конфигураций для работы Взлетной полосы должным образом.
.runway.json
У Взлетной полосы есть несколько команд, которые вы можете использовать для управления вашим приложением Flight. Есть два простых способа использования Взлетной полосы.
php runway [команда]
vendor/bin/runway [команда]
Для любой команды вы можете передать флаг --help, чтобы получить больше информации о том, как использовать команду.
--help
php runway routes --help
Вот несколько примеров:
На основе конфигурации в вашем файле .runway.json по умолчанию контроллер будет создан для вас в каталоге app/controllers/.
app/controllers/
php runway make:controller MyController
На основе конфигурации в вашем файле .runway.json по умолчанию модель будет создана для вас в каталоге app/records/.
app/records/
php runway make:record users
Если у вас, например, есть таблица users с такой схемой: id, name, email, created_at, updated_at, будет создан файл, подобный следующему, в файле app/records/UserRecord.php:
users
email
created_at
updated_at
app/records/UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Класс Active Record для таблицы пользователей. * @link https://docs.flightphp.com/awesome-plugins/active-record * * @property int $id * @property string $name * @property string $email * @property string $created_at * @property string $updated_at * // здесь вы также можете добавить отношения после их определения в массиве $relations * @property CompanyRecord $company Пример отношения */ class UserRecord extends \flight\ActiveRecord { /** * @var array $relations Установите отношения для модели * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = []; /** * Конструктор * @param mixed $databaseConnection Соединение с базой данных */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
Это отобразит все маршруты, которые в настоящее время зарегистрированы в Flight.
php runway routes
Если вы хотите просмотреть только определенные маршруты, вы можете передать флаг для фильтрации маршрутов.
# Отобразить только GET маршруты php runway routes --get # Отобразить только POST маршруты php runway routes --post # и т.д.
Если вы создаете пакет для Flight или хотите добавить свои собственные команды в свой проект, вы можете сделать это, создав каталог src/commands/, flight/commands/, app/commands/ или commands/ для вашего проекта/пакета.
src/commands/
flight/commands/
app/commands/
commands/
Для создания команды просто расширьте класс AbstractBaseCommand и реализуйте, как минимум, метод __construct и метод execute.
AbstractBaseCommand
__construct
execute
<?php declare(strict_types=1); namespace flight\commands; class ExampleCommand extends AbstractBaseCommand { /** * Конструктор * * @param array<string,mixed> $config JSON конфигурация из .runway-config.json */ public function __construct(array $config) { parent::__construct('make:example', 'Создать пример для документации', $config); $this->argument('<funny-gif>', 'Имя смешной гифки'); } /** * Выполняет функцию * * @return void */ public function execute(string $controller) { $io = $this->app()->io(); $io->info('Создание примера...'); // Сделайте здесь что-то $io->ok('Пример создан!'); } }
Смотрите Документация adhocore/php-cli для получения дополнительной информации о том, как создавать свои собственные команды в вашем приложении Flight!
Это набор расширений, чтобы работа с Flight была немного более обширной.
$_SESSION
Это Панель
И каждая панель отображает очень полезную информацию о вашем приложении!
Запустите composer require flightphp/tracy-extensions --dev и вы на правильном пути!
composer require flightphp/tracy-extensions --dev
Вам нужно сделать очень небольшую настройку, чтобы начать использовать это. Вам нужно инициировать отладчик Tracy перед использованием этого https://tracy.nette.org/en/guide:
<?php use Tracy\Debugger; use flight\debug\tracy\TracyExtensionLoader; // код инициализации require __DIR__ . '/vendor/autoload.php'; Debugger::enable(); // Возможно, вам нужно указать ваше окружение с помощью Debugger::enable(Debugger::DEVELOPMENT) // если вы используете подключения к базе данных в вашем приложении, есть // обязательная оболочка PDO для использования ТОЛЬКО В РАЗРАБОТКЕ (пожалуйста, не в продакшн!) // У него те же параметры, что и обычное соединение PDO $pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass'); // или если вы присоединяете это к фреймворку Flight Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']); // теперь при каждом запросе он будет записывать время, запрос и параметры // Это соединяет точки if(Debugger::$showBar === true) { // Это должно быть false, иначе Tracy не сможет отображаться :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); } // еще код Flight::start();
Если у вас есть пользовательский обработчик сеансов (например, ghostff/session), вы можете передать любой массив данных сеанса в Tracy, и он автоматически выведет его для вас. Вы передаете это с ключом session_data вторым параметром конструктора TracyExtensionLoader.
session_data
TracyExtensionLoader
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); if(Debugger::$showBar === true) { // Это должно быть false, иначе Tracy не сможет отображаться :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]); } // маршруты и другие вещи... Flight::start();
Если у вас установлен Latte в вашем проекте, вы можете использовать панель Latte для анализа ваших шаблонов. Вы можете передать экземпляр Latte в конструктор TracyExtensionLoader с ключом latte вторым параметром.
latte
use Latte\Engine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', Engine::class, [], function($latte) { $latte->setTempDirectory(__DIR__ . '/temp'); // здесь вы добавляете Панель Latte в Tracy $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension); }); if(Debugger::$showBar === true) { // Это должно быть false, иначе Tracy не сможет отображаться :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); }
Трейси - удивительный обработчик ошибок, который можно использовать с Flight. У него есть ряд панелей, которые могут помочь вам отлаживать ваше приложение. Он также очень легок в расширении и добавлении собственных панелей. Команда Flight создала несколько панелей специально для проектов Flight с плагином flightphp/tracy-extensions.
Установите с помощью composer. И вам действительно захочется установить это без версии для разработчиков, так как у Трейси есть компонент обработки ошибок для продакшена.
composer require tracy/tracy
Есть некоторые базовые параметры конфигурации, чтобы начать. Вы можете узнать больше о них в Документации по Tracy.
require 'vendor/autoload.php'; use Tracy\Debugger; // Включение Tracy Debugger::enable(); // Debugger::enable(Debugger::DEVELOPMENT) // иногда вам придется быть явным (также Debugger::PRODUCTION) // Debugger::enable('23.75.345.200'); // также можно предоставить массив IP-адресов // Здесь будут регистрироваться ошибки и исключения. Убедитесь, что этот каталог существует и доступен для записи. Debugger::$logDirectory = __DIR__ . '/../log/'; Debugger::$strictMode = true; // показывать все ошибки // Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // все ошибки, кроме устаревших уведомлений if (Debugger::$showBar) { $app->set('flight.content_length', false); // если панель отладки видима, тогда длина содержимого не может быть установлена Flight // Это специфично для Расширения Трейси для Flight, если вы его включили // в противном случае закомментируйте это. new TracyExtensionLoader($app); }
Когда вы отлаживаете свой код, есть несколько очень полезных функций для вывода данных для вас.
bdump($var)
dumpe($var)
Активная запись - это отображение сущности базы данных на объект PHP. Проще говоря, если у вас есть таблица пользователей в вашей базе данных, вы можете "перевести" строку в этой таблице в класс User и объект $user в вашем коде. Смотрите простой пример.
User
$user
Нажмите здесь для репозитория на GitHub.
Допустим, у вас есть следующая таблица:
CREATE TABLE users ( id INTEGER PRIMARY KEY, name TEXT, password TEXT );
Теперь вы можете создать новый класс, чтобы представить эту таблицу:
/** * Класс ActiveRecord обычно в единственном числе * * Для наглядности рекомендуется добавить свойства таблицы в виде комментариев здесь * * @property int $id * @property string $name * @property string $password */ class User extends flight\ActiveRecord { public function __construct($database_connection) { // можно установить так parent::__construct($database_connection, 'users'); // или так parent::__construct($database_connection, null, [ 'table' => 'users']); } }
Теперь посмотрите, как это легко!
// для sqlite $database_connection = new PDO('sqlite:test.db'); // это просто пример, обычно вы бы использовали реальное соединение с базой данных // для mysql $database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password'); // или mysqli $database_connection = new mysqli('localhost', 'username', 'password', 'test_db'); // или mysqli с созданием не на основе объекта $database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db'); $user = new User($database_connection); $user->name = 'Бобби Тейблз'; $user->password = password_hash('какой-то крутой пароль'); $user->insert(); // или $user->save(); echo $user->id; // 1 $user->name = 'Джозеф Мамма'; $user->password = password_hash('крутой пароль снова!!!'); $user->insert(); // здесь нельзя использовать $user->save(), иначе он подумает, что это обновление! echo $user->id; // 2
И это было настолько легко добавить нового пользователя! Теперь, когда есть строка пользователя в базе данных, как ее извлечь?
$user->find(1); // найдите id = 1 в базе данных и верните его. echo $user->name; // 'Бобби Тейблз'
Что, если вы хотите найти всех пользователей?
$users = $user->findAll();
А что насчет определенного условия?
$users = $user->like('name', '%мамма%')->findAll();
Вот как это весело! Установим его и начнем!
Просто установите с помощью Composer
composer require flightphp/active-record
Эту библиотеку можно использовать как автономно, так и с фреймворком Flight PHP. Полностью на ваше усмотрение.
Убедитесь, что вы передаете соединение PDO в конструктор.
$pdo_connection = new PDO('sqlite:test.db'); // это просто пример, обычно вы бы использовали реальное соединение с базой данных $User = new User($pdo_connection);
Вы не хотите всегда устанавливать соединение с базой данных в конструкторе? См. Управление соединением с базой данных для других идей!
Если вы используете фреймворк Flight PHP, вы можете зарегистрировать класс ActiveRecord как службу, но честно говоря, это не обязательно.
Flight::register('user', 'User', [ $pdo_connection ]); // затем вы можете использовать его так в контроллере, функции и т. д. Flight::user()->find(1);
runway
runway - это инструмент командной строки для Flight, который имеет пользовательскую команду для этой библиотеки.
# Использование php runway make:record имя_таблицы_базы_данных [имя_класса] # Пример php runway make:record users
Это создаст новый класс в каталоге app/records/ под названием UserRecord.php со следующим содержанием:
UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Класс ActiveRecord для таблицы пользователей. * @link https://docs.flightphp.com/awesome-plugins/active-record * * @property int $id * @property string $username * @property string $email * @property string $password_hash * @property string $created_dt */ class UserRecord extends \flight\ActiveRecord { /** * @var array $relations Установите отношения для модели * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = [ // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ], ]; /** * Конструктор * @param mixed $databaseConnection Соединение с базой данных */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
find($id = null) : boolean|ActiveRecord
Находит одну запись и присваивает ее текущему объекту. Если вы передаете $id, он выполнит поиск по первичному ключу с этим значением. Если ничего не передается, он просто найдет первую запись в таблице.
Кроме того, вы можете передавать другие вспомогательные методы для запроса вашей таблицы.
// найти запись с некоторыми условиями заранее $user->notNull('password')->orderBy('id DESC')->find(); // найти запись по конкретному id $id = 123; $user->find($id);
findAll(): array<int,ActiveRecord>
Находит все записи в указанной таблице.
$user->findAll();
isHydrated(): boolean
Возвращает true, если текущая запись была считана с базы данных.
$user->find(1); // если запись найдена с данными... $user->isHydrated(); // true
insert(): boolean|ActiveRecord
Вставляет текущую запись в базу данных.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->insert();
Если у вас есть первичный ключ на основе текста (например, UUID), вы можете установить значение первичного ключа перед вставкой одним из двух способов.
$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]); $user->uuid = 'some-uuid'; $user->name = 'demo'; $user->password = md5('demo'); $user->insert(); // или $user->save();
или вы можете автоматически сгенерировать первичный ключ через события.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]); // вы также можете установить primaryKey таким образом, а не в массиве выше. $this->primaryKey = 'uuid'; } protected function beforeInsert(self $self) { $self->uuid = uniqid(); // или как иначе нужно создавать уникальные идентификаторы } }
Если вы не установите первичный ключ перед вставкой, он будет установлен на rowid, и база данных сгенерирует его для вас, но он не сохранится, потому что это поле может отсутствовать в вашей таблице. Поэтому рекомендуется использовать событие для автоматической обработки этого для вас.
rowid
update(): boolean|ActiveRecord
Обновляет текущую запись в базе данных.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@example.com'; $user->update();
save(): boolean|ActiveRecord
Вставляет или обновляет текущую запись в базе данных. Если у записи есть идентификатор, он будет обновлен, в противном случае он будет вставлен.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->save();
Примечание: Если у вас в классе определены отношения, они также будут рекурсивно сохраняться, если они были определены, инициализированы и имеют данные для обновления. (v0.4.0 и выше)
delete(): boolean
Удаляет текущую запись из базы данных.
$user->gt('id', 0)->orderBy('id desc')->find(); $user->delete();
Вы также можете удалить несколько записей, выполнив поиск заранее.
$user->like('name', 'Bob%')->delete();
dirty(array $dirty = []): ActiveRecord
Грязные данные относятся к данным, которые были изменены в записи.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); // на данный момент ничего не является "грязным". $user->email = 'test@example.com'; // теперь электронная почта считается "грязной", так как она изменилась. $user->update(); // теперь нет грязных данных, потому что они были обновлены и сохранены в базе данных $user->password = password_hash()'newpassword'); // теперь это грязные данные $user->dirty(); // передача ничего не очистит все грязные записи. $user->update(); // ничего не обновится, потому что ничего не было помечено как грязное. $user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // обновятся и имя и пароль.
copyFrom(array $data): ActiveRecord
Это псевдоним для метода dirty(). Это немного более ясно, чем вы это делаете.
dirty()
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // обновятся и имя и пароль.
isDirty(): boolean
Возвращает true, если текущая запись была изменена.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@email.com'; $user->isDirty(); // true
reset(bool $include_query_data = true): ActiveRecord
Сбрасывает текущую запись в начальное состояние. Это действительно хорошо использовать в циклических поведениях. Если передать true, он также сбросит данные запроса, которые были использованы для нахождения текущего объекта (поведение по умолчанию).
$users = $user->greaterThan('id', 0)->orderBy('id desc')->find(); $user_company = new UserCompany($pdo_connection); foreach($users as $user) { $user_company->reset(); // начнем с чистого листа $user_company->user_id = $user->id; $user_company->company_id = $some_company_id; $user_company->insert(); }
getBuiltSql(): string
После выполнения методов find(), findAll(), insert(), update() или save() вы можете получить построенный SQL и использовать его в целях отладки.
find()
findAll()
insert()
update()
save()
select(string $field1 [, string $field2 ... ])
Вы можете выбирать только несколько столбцов из таблицы (это более производительно на очень широких таблицах с множеством столбцов).
$user->select('id', 'name')->find();
from(string $table)
Технически вы можете выбрать другую таблицу тоже! Почему бы и нет?!
$user->select('id', 'name')->from('user')->find();
join(string $table_name, string $join_condition)
Вы даже можете присоединиться к другой таблице в базе данных.
$user->join('contacts', 'contacts.user_id = users.id')->find();
where(string $where_conditions)
Вы можете установить некоторые пользовательские условия where (в этом where вы не можете устанавливать параметры)
$user->where('id=1 AND name="demo"')->find();
Примечание по безопасности - Вас может увлечь что-то вроде $user->where("id = '{$id}' AND name = '{$name}'")->find();. ПОЖАЛУЙСТА, НЕ ДЕЛАЙТЕ ЭТО!!! Это уязвимо для так называемых атак SQL-инъекций. В интернете есть много статей, пожалуйста, загуглите "sql injection attacks php", и вы найдете много статей по этой теме. Правильный способ обработки этого с использованием этой библиотеки заключается в том, что вместо этого метода where() вы бы сделали что-то вроде $user->eq('id', $id)->eq('name', $name)->find();. Если вам действительно нужно это сделать, библиотека PDO имеет $pdo->quote($var), чтобы экранировать его для вас. Только после использования quote() вы можете использовать его в операторе where().
$user->where("id = '{$id}' AND name = '{$name}'")->find();
where()
$user->eq('id', $id)->eq('name', $name)->find();
$pdo->quote($var)
quote()
group(string $group_by_statement)/groupBy(string $group_by_statement)
Группируйте ваши результаты по определенному условию.
$user->select('COUNT(*) as count')->groupBy('name')->findAll();
order(string $order_by_statement)/orderBy(string $order_by_statement)
Сортируйте возвращенный запрос определенным способом.
$user->orderBy('name DESC')->find();
limit(string $limit)/limit(int $offset, int $limit)
Ограничивают количество возвращаемых записей. Если передан второй int, это смещение, ограничение также как в SQL.
$user->orderby('name DESC')->limit(0, 10)->findAll();
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Где field = $value
field = $value
$user->eq('id', 1)->find();
notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Где `self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
CppI"родитель"hasMany`表示一对多关系。`self::HAS_ONE`表示一对一关系。`self::BELONGS_TO`表示从属关系。
Latte - это полнофункциональный движок шаблонов, который очень прост в использовании и ближе к синтаксису PHP, чем Twig или Smarty. Также очень легко расширяем и добавляем собственные фильтры и функции.
composer require latte/latte
Есть несколько основных опций конфигурации, с которых можно начать. Вы можете узнать больше о них в Документации по Latte.
use Latte\Engine as LatteEngine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) { // Здесь Latte будет кэшировать ваши шаблоны для ускорения работы // Одна из хороших вещей в Latte заключается в том, что он автоматически обновляет ваш // кэш при внесении изменений в ваши шаблоны! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Скажите Latte, где будет базовый каталог для ваших представлений. // $app->get('flight.views.path') устанавливается в файле config.php // Вы также можете просто сделать что-то вроде `__DIR__ . '/../views/'` $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path'))); });
Вот простой пример файла макета. Этот файл будет использоваться для оформления всех ваших других представлений.
<!-- app/views/layout.latte --> <!doctype html> <html lang="en"> <head> <title>{$title ? $title . ' - '}Мое приложение</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <nav> <!-- ваши элементы навигации здесь --> </nav> </header> <div id="content"> <!-- Вот где волшебство --> {block content}{/block} </div> <div id="footer"> © Авторские права </div> </body> </html>
И теперь у нас есть ваш файл, который будет отображаться внутри этого блока контента:
<!-- app/views/home.latte --> <!-- Это говорит Latte, что этот файл "внутри" файла layout.latte --> {extends layout.latte} <!-- Это содержимое, которое будет отображаться в макете внутри блока контента --> {block content} <h1>Домашняя страница</h1> <p>Добро пожаловать в мое приложение!</p> {/block}
Затем, когда вы будете рендерить это внутри вашей функции или контроллера, вы сделаете что-то вроде этого:
// простой маршрут Flight::route('/', function () { Flight::latte()->render('home.latte', [ 'title' => 'Домашняя страница' ]); }); // или если вы используете контроллер Flight::route('/', [HomeController::class, 'index']); // HomeController.php class HomeController { public function index() { Flight::latte()->render('home.latte', [ 'title' => 'Домашняя страница' ]); } }
Смотрите Документацию по Latte для получения дополнительной информации о том, как использовать Latte в полной мере!
Flight невероятно расширяем. Существует ряд плагинов, которые можно использовать для добавления функциональности к вашему приложению Flight. Некоторые из них официально поддерживаются командой Flight, а другие являются микро/легкими библиотеками для помощи в начале работы.
Аутентификация и авторизация крайне важны для любого приложения, которому требуется установка контрольных точек для того, кто может получить доступ к чему.
Кэширование - отличный способ ускорить ваше приложение. Существует ряд библиотек кэширования, которые можно использовать с Flight.
CLI-приложения - отличный способ взаимодействия с вашим приложением. Вы можете использовать их для создания контроллеров, отображения всех маршрутов и многое другое.
Cookies - отличный способ хранения небольших фрагментов данных на стороне клиента. Их можно использовать для хранения пользовательских предпочтений, настроек приложения и многое другое.
Отладка крайне важна при разработке в вашей локальной среде. Существует несколько плагинов, которые могут улучшить ваш опыт отладки.
Базы данных - это основа большинства приложений. Это то, как вы храните и извлекаете данные. Некоторые библиотеки баз данных просто обертки для написания запросов, а некоторые - полноценные ORM.
Шифрование крайне важно для любого приложения, которое хранит конфиденциальные данные. Шифрование и дешифрование данных не так уж и сложно, но правильное хранение ключа шифрования может быть сложной задачей. Самое важное - никогда не храните ключ шифрования в общедоступном каталоге или не сохраняйте его в репозитории вашего кода.
Сессии не очень полезны для API, но для создания веб-приложения сессии могут быть крайне важными для поддержания состояния и информации об аутентификации.
Шаблонизация является основой для любого веб-приложения с пользовательским интерфейсом. Существует ряд шаблонизационных движков, которые можно использовать с Flight.
Есть плагин, который вы хотели бы поделиться? Представьте запрос на включение его в список!
Мы постарались собрать все, что можем, о различных типах медиа в интернете, связанных с Flight. См. ниже различные ресурсы, которые вы можете использовать, чтобы узнать больше о Flight.
У вас есть два варианта, чтобы начать работу с Flight:
Хотя они не являются официально поддерживаемыми командой Flight, они могут дать вам идеи о том, как структурировать ваши собственные проекты, построенные с помощью Flight!
Если у вас есть проект, которым вы хотите поделиться, пожалуйста, отправьте запрос на добавление его в этот список!
Убедитесь, что у вас установлен PHP на вашей системе. Если нет, нажмите здесь для получения инструкций по установке на вашей системе.
Если вы используете Composer, вы можете выполнить следующую команду:
ИЛИ вы можете скачать файлы напрямую и извлечь их в ваш каталог веб-сайта.
Это, безусловно, самый простой способ запустить приложение и использовать даже SQLite для базы данных. Просто выполните следующую команду после установки PHP:
php -S localhost:8000
Затем откройте свой браузер и перейдите по адресу http://localhost:8000.
http://localhost:8000
Если вы хотите изменить корневой каталог вашего проекта на другой каталог (например, ваш проект - ~/myproject, а корневой каталог -~/myproject/public/), вы можете выполнить следующую команду после того, как вы находитесь в каталоге ~/myproject:
~/myproject
~/myproject/public/
php -S localhost:8000 -t public/
Убедитесь, что Apache уже установлен на вашей системе. Если нет, найдите, как установить Apache на вашей системе через поиск в Google.
Для Apache измените ваш файл .htaccess следующим образом:
Примечание: Если вам нужно использовать flight в подкаталоге, добавьте строку RewriteBase /subdir/ сразу после RewriteEngine On. Примечание: Если вы хотите защитить все файлы сервера, такие как файл db или env. Поместите это в ваш файл .htaccess:
Примечание: Если вы хотите защитить все файлы сервера, такие как файл db или env. Поместите это в ваш файл .htaccess:
Убедитесь, что Nginx уже установлен на вашей системе. Если нет, найдите, как установить Nginx на вашей системе через поиск в Google.
<?php // Если вы используете Composer, подключите автозагрузчик. require 'vendor/autoload.php'; // если вы не используете Composer, загрузите фреймворк непосредственно // require 'flight/Flight.php'; // Затем определите маршрут и назначьте функцию для обработки запроса. Flight::route('/', function () { echo 'hello world!'; }); // Наконец, запустите фреймворк. Flight::start();
Если у вас уже установлен php на вашей системе, переходите к разделу загрузки файлов.
php
Успехов! Вот инструкции по установке PHP на macOS, Windows 10/11, Ubuntu и Rocky Linux. Я также предоставлю информацию о том, как установить различные версии PHP.
Установите Homebrew (если его нет):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Установите PHP:
brew install php
brew tap shivammathur/php brew install shivammathur/php/php@8.1
Переключение между версиями PHP:
brew unlink php brew link --overwrite --force php@8.1
php -v
Скачайте PHP:
Разархивируйте PHP:
C:\php
Добавьте PHP в системный путь:
Настройте PHP:
php.ini-development
php.ini
extension_dir
Проверьте установку PHP:
Повторите вышеперечисленные шаги для каждой версии, помещая каждую в отдельный каталог (например, C:\php7, C:\php8).
C:\php7
C:\php8
Переключайтесь между версиями, изменяя системную переменную PATH, указывающую на каталог нужной версии.
Обновите списки пакетов:
sudo apt update
sudo apt install php
sudo apt install php8.1
Установите дополнительные модули (по желанию):
sudo apt install php8.1-mysql
update-alternatives
sudo update-alternatives --set php /usr/bin/php8.1
Проверьте установленную версию:
Включите репозиторий EPEL:
sudo dnf install epel-release
Установите репозиторий Remi:
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm sudo dnf module reset php
sudo dnf install php
sudo dnf module install php:remi-7.4
dnf module
sudo dnf module reset php sudo dnf module enable php:remi-8.0 sudo dnf install php