ЧПУ — в трех соснах …?

Vladchucha

Добрый день,
решил переделать сайт на ЧПУ и пришел тупик,
возможно не понимаю что-то фундаментальное.
Стал пробовать, по простому сначала.
Супер — работает. Но когда стал делать вызов с GET
параметрами, то ….ничего не понимай.
Далее текст

Код (Text):
  1. ini_set(‘display_errors’, 1);
  2. ini_set(‘display_startup_errors’, 1);
  3. error_reporting(E_ALL);
  4. $router=»»;
  5. if (isset($_GET[‘router’]))
  6. { $router = trim($_GET[‘router’]);
  7.     $url= explode(«https://php.ru/», $router);
  8. }
  9. else $url=»»;
  10. echo_r($url);
  11.        
  12.   if ($url==»)
  13.   {      include ‘../app/main.php’;
  14.  
  15.   }
  16.   else
  17.    {
  18.         $myfile=»../app/».$url[0].’.php’;
  19.  
  20.      if (file_exists($myfile))
  21.        {
  22.          include ‘../app/’.$url[0].’.php’;
  23.          echo ‘../app/old-world.php’;
  24.        }
  25.  
  26.        else
  27.        {   include ‘404.html’;
  28.            header(«HTTP/1.0 404 Not Found  » );
  29.  
  30.        }
  31.   }

Это работает, скрипт с формой корректно передает по POST данные.
Теперь хочу обработать с параметрами для поиска в БД.
/app/main.php/id/5/category/44.
И вот здесь ступор.
В лоб не получается, то есть если я это преобразую (неважно как)
в /app/main.php?id=5&category=44,
то не могу include сделать, система не найдет такого файла.
КАК вызывыется в этом случае скрипт не понимаю.
Допустим есть движок с контроллерами, машрутизаторами….
все равно в конечном итоге надо, чтобы скрипт начал выполняться с полученными параметрами.
Тупо проинклудить не получается.
Как это сделать, ну для начала максимально по-простому?
Файл .htaccsess.

Код (CSS):
  1. AddDefaultCharset  utf8
  2. RewriteEngine On
  3. DirectoryIndex index.php
  4. #RewriteCond %{REQUEST_FILENAME} !-f
  5. #RewriteCond %{REQUEST_FILENAME} !-d
  6.  
  7. RewriteRule ^(.*)$ index.php?router=$1 [L,QSA]

Спасибо.

 

don.bidon

ничего непонятно, но очень интересно

 

ADSoft

подход в принципе верный.. реализация не очень )))

1. Единая точка входа — index.php?router=$1 у вас есть
2. в ней нужно разбирать урл, всегда, любой
3. после вашего кода

Код (Text):
  1. if (isset($_GET[‘router’]))
  2. { $router = trim($_GET[‘router’]);
  3.     $url= explode(«https://php.ru/», $router);
  4. }

в $url — путь разбитый по / … то есть если вы передаете как /news/5/24 у вас будет массив [‘news’,5,24]
а уж сам роутер пусть решает чего там как инклудить, как и куда параметры эти передавать

 

miketomlin

Лучше бы и не начинали. Перенос пути в GET-параметр, в PATH_INFO – это прошлый век. Разбирайте прямо $_SERVER[‘REQUEST_URI’]: Как сделать единую точку входа с ЧПУ?
— Добавлено —

Нафига для главной пускать отдельную ветку? Ну, пусть будет файл называться .php – просто и элегантно.

Дыра. В GET-параметре вам легко могут подсунуть ../ и вывести из каталога app ;)
— Добавлено —

Это WP-шная хрень. В норм. движках правило перенаправления во фронт работает в том числе и для главной.
— Добавлено —
Пустая строка в .htaccess явно не на том месте. Условия относятся к тому правилу, которое ниже, а не выше ;)
— Добавлено —

Естественно. Из фронта/роутера параметры передаются обычным для пыха путем: в переменных, в параметрах ф-ции/метода и т.п. ;) Не надо при инклуде пытаться юзать GET-параметры, PATH_INFO :D
— Добавлено —
У тебя в $url[N] будут параметры (необработанные). В последний и не только может затесаться строка параметров, т.к. ты ее не отделил перед разделением пути на компоненты.
— Добавлено —
См. вторую демку в моей статье ;)

 

miketomlin

Тут попутал, сорри. Это нужно будет учитывать, если будешь использовать $_SERVER[‘REQUEST_URI’].

 

Vladchucha

THANKS very much,
1. С безопасностю, да, надо ряд дырок закрывать.
2. Вроде ступор (частично) прошел, вечером виски, может совсем уйдет.
3. Посмотрел пару видео умных людей.
Один говорит
www.site.com/ и www.site.com
мы так обработаем, что в обоих случаях корректно
на главную страницу попадем и все доворльны.
Другой говорит— так очень плохо, так как
роботы воспримут это как полное дублирование страниц и вызовут полицию
Что верно/не верно?

 

miketomlin

Это один и тот же адрес, а вот глубже, да, будут дубли. Если смотрели мои демки, там множественные и трэйлинг слеши автоматом корректируются, многое во фронте (этот фильтр есть в статье, ссылку на которую я давал).
— Добавлено —
Корректировка трэйлинг слешей отдана на откуп серверу (.htaccess и т.п.), во фронте они просто обрезаются (см. преобразование в «нормализованный» путь, который в $px сохраняется).

 

MouseZver

@Vladchucha, привет.
Начнем с первого байта строки.

PHP:
  1. ini_set ( string $option, string $value ): string | false

Второй аргумент принимает только строковое значение, а ты присваиваешь значение с типом int.
В результате, правильно делается так:

PHP:
  1. ini_set ( ‘display_errors’, ‘1’ );
  2. ini_set ( ‘display_startup_errors’, ‘1’ );

PHP:
  1. $ini_set = [
  2.     ‘error_reporting’            => E_ALL,    // ругаться на всё интерпретатору php
  3.     ‘html_errors’                => 1,        // хрень, которая в браузере выделяет жирным текстом основу ошибки
  4.     ‘log_errors’                 => 1,         // 0 — использ. system журнал | 1 — использ. пользов. журнал для сохранения ошибок
  5.     ‘log_errors_max_len’         => 0,        // 0 — безлимит | 1024 — байт, максимальный размер содержимого об ошибки
  6.     ‘ignore_repeated_errors’     => 0,        // загуглить, долго объяснять
  7.     ‘ignore_repeated_source’     => 0,        // загуглить, долго объяснять
  8.     ‘error_log’                  => $_SERVER[‘DOCUMENT_ROOT’] . ‘/logs/Debug.log’, // лог файл (пользовательский журнал), куда так же летят все ошибки
  9.     ‘display_errors’             => ‘on’,     // on — включить | off — выкл. Не вывод, а ПОКАЗАТЬ ошибки юзеру
  10.     ‘display_startup_errors’     => 1,        // Презерватив для display_errors. Именно эта опция должна быть отключена на боевом сайте, чтоб ошибки юзеры не видели.
  11.     ‘date.timezone’              => ‘Europe/Moscow’, // Временная зона для всего, кроме БД — загуглить
  12.     ‘default_charset’            => ‘UTF-8’,  // мы должны любить UTF-8 везде
  13. ];
  14.  
  15. foreach ( $ini_set AS $option => $value )
  16. {
  17.     ini_set ( $option, ( string ) ( is_bool ( $value ) ? ( int ) $value : $value ) );
  18. }

Cовет — перед началом любого твоего скрипта, начинай со строки:

PHP:
  1. <?php
  2.  
  3. declare ( strict_types = 1 );
  4.  
  5. /* …code… */

и ты автоматически отсеиваешься от всего сброда говнокодеров.
https://www.php.net/manual/ru/language.types.declarations.php#language.types.declarations.strict
Строгая типизация и повышение токсичности интерпретатору (ошибки) для, например — как было с твоим ini_set во втором аргументе.
——

Это чейт за функция в php ? print_r ? или пользовательская…
——
Роутер… больная тема как с Авторизацией/Идентификацией пользователя.
Начнем с файла .htaccsess

Абсолютно верно и добавлю +15копеек:

Такой метод единой точки не просто прошлый век, он тупо убивает принцип $_GET параметров и у нас остается лишь одинокий router, вместо положенных атрибутов, который пользователь к нам прислал.​

Поэтому, идем к Ларавельке и просто тырим у нее htaccess
——
Оформление кода роутера.
Хм..
Да как хочешь o_O вот реально — как хотелка пожелает.
Хочешь максимально по простому — пили проверки как ты и делал.
Хочешь организованно со всякими плюшками — используй composer + куча всяких фаст роутеров в github.
Но… имей ввиду, что $_SERVER[‘REQUEST_URI’] сырой и нуждается в тотальной мясорубке.

PHP:
  1. $uri = $_SERVER[‘REQUEST_URI’];
  2.  
  3. $routing = [
  4.     «https://php.ru/» => ‘index’,
  5.     ‘/test’ => ‘test’,
  6.     ‘/test/(d+)’ => ‘test’, // /test/54
  7. ];
  8.  
  9. $action = ‘404’;
  10.  
  11. foreach ( $routing AS $route => $name )
  12. {
  13.     if ( preg_match ( «#^{$uri_string}$#», $uri, $matches ) === 1 )
  14.     {
  15.         $action = $name;
  16.        
  17.         break;
  18.     }
  19. }
  20.  
  21. require __DIR__ . «/resource/{$action}.php»;

Помню давным-давно @igordata постил свою пипетку, там было наглядно и максимально упрощен роутер.
https://github.com/igordata/PinPIE/…ee634a12816140eee74/pinpie/classes/pinpie.php
Начиная с 36 по 113 строки. Довольно типичный и приближенный вариант для твоей ситуации.

——

На данном этапе изучи composer php.
Единственное, ценное и нужное тебе сейчас знание, на которое грех не потратить свободное время. В итоге получаешь и единую точку автозагрузки требуемых классов, своих/чужих библиотек и не надо будет использовать по 100500 раз require к каждому файлу.
Зарегистрируйся на сайтах
https://github.com
https://packagist.org
Это все нужно будет для composer.
Скачай если нет, openserver. Через его консоль сможешь использовать его, подключать библиотеки различных разработчиков. Сможешь так же подключить FastRouter или подобные им. А в своем скрипте просто одной строкой:

PHP:
  1. <?php
  2.  
  3. require ‘vendor/autoload.php’;

——

После, через некоторое время захочется узнать, как устроен фреймворк, каков его скелет, что запускается, когда сессия стартует, идентификация пользователя, в каком ввиде контент отдавать юзеру / кому еще, какова логика последовательных действий в кратком понимании. Сам лично чуть ли не переписал процедуру обработки данных. И после сверки со Symfony, задался вопросом — а нахрена я буду тратить время, там логика идентична. Бери и пользуйся.

PHP:
  1. require ‘vendor/autoload.php’;
  2.  
  3. // загрузка конфига, подготовка апи (инструменты фрейма) к использованию
  4.  
  5. // дебаг, прочее, ini_set
  6.  
  7. // сессия
  8.  
  9. // GET POST COOKIE SERVER в ооп стиль со всякими вкусняшками
  10. // SymfonyComponentHttpFoundationRequest :: createFromGlobals();
  11.  
  12. // Идентификация юзера
  13. // еще что-то кучу важных операций
  14.  
  15. // роутер
  16.  
  17. // логика кода — что надо юзеру
  18.  
  19. // SymfonyComponentHttpFoundationResponse
  20.  
  21. // конец

https://symfony.com/doc/current/components/http_foundation.html
Но тебе эта ссылка сейчас ничего не скажет / покажет

 

miketomlin

Флаг QSA помогает. Там основная проблема – это мегадубль /path vs /[index.php]?router=path, с которым можно бороться до [сами придумайте слово] :)

 

Vladchucha

Спасибо за кучу информации.
Потихоньку (время свободного мало) буду делать/разбираться
1. echo_r($url); Это пользовательская, просто вывод с <pre>.
2. Несколько лет назад прочел книгу немецкого автора «PHP: quick & dirty».
Предназначена для полуновичков и если разработчик
а. один все делает
б. Время мало и/или заказчик с топором над душой стоит.
Сейчас понимаю, что многое там спорно, подход не совсем корректный.
В то же время для одиночки ( то есть я не в коллективе программистов)
и практически с нуля, единственный источник тогда нашел,
где описывается процесс создания сайта, начиная со структуры каталогов,
какие файлы вообще нужны, взаимосвязи и пр.
Мне кажется, что и сейчас такких книг(статей) практически нет.
Вот, с вашей помощью буду дальше разбираться,
на пенсии напишу правильную книжку.

 

Evgenii_web

книг много но в основном они поверхностные и когда получаешь проблему нет возможности решить ее, книги пишутся плохо. Русские книги можно не покупать, авторы в России отдалены от проблем создания сайтов их код php живет своей жизнью DDD. Иностранные толковые книги переводятся с опозданием лет так на 5 ито если переведут. Научная толковая литература разбирается моментально. Сегодня купил последнюю книку по созданию каталога от Ларри Ульман по всей рашке их не было в Таганроге последнюю урвал. Код прост, процедурный минимум функции и ооп. Буду писать каталог свой с осенью.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *