Ответы пользователя по тегу PHP
  • Надо ли бросать исключение при приеме ошибочных (невалидных) данных?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Нужно ли бросать исключение, в случаях, когда данные не прошли валидацию?

    Если это валидатор - достаточно вернуть ErrorResponse объект с ошибкой.
    Если это вызов метода с не правильным данными - бросайте исключение.

    Или достаточно просто занести код и сообщение ошибки в массив errors и при выводе работать с ним?

    Не стоит, возвращайте сразу ErrorResponse.

    Полезна ли информация с Исключений при валидации во время дебагга?
    Да, так вы получаете stacktrace, помимо сообщения об ошибке.

    Работа с ошибочными данными может вызвать ошибку непосредственно при их обработке.

    Лучше не используйте ошибки, с ними не удобно работать, вместо этого исключения.

    Вот вам пример, Assert::assert - это штука из либы ko-ko-ko/assert
    public function loginAction(Request $request) : Response
    {
        try {
            $userName = $request->request->get('userName');
            $password = $request->request->get('password');
    
            Assert::assert($userName, 'userName')->match('/^[\a-z\d]{3,32}$/i');
            Assert::assert($password, 'password')->lengthBetween(6, 32);
        } catch (\Throwable $exception) {
            return new Response($exception->getMessage(), Response::HTTP_BAD_REQUEST);
        }
    
        try {
            // Your business logic here
            
            return Response();
        } catch (\Throwable $exception) {
            $this->get('logger')->error($exception->getMessage(), ['exception' => $exception]);
            return new Response('Could not login', Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
    Ответ написан
  • Как по-изящнее переписать несколько php echo строк?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Можно-ли как-то красивее переписать строки?

    Используйте шаблонизатор типа twig и будет вам счастье))

    Конкретно ваш случай - printf
    Ответ написан
  • Как перейти на JAVA после PHP?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Последние год полтора пишу продакшен в основном на Laravel.

    Попробуйте Symfony, так же рекомендую почитать

    Собственно в последнее время мне стало скучно и решил я поискать себе приключений на свою точку.

    Смените проект на более крупный))

    Глянул курс по JAVA SE (синтаксис, пару либ), куда двигаться дальше?

    Как и с другими языками: поищите вакансии на проекты, что вас могут заинтересовать и посмотрите требования.

    Что посоветуете попилить в качестве тестового проекта, чтобы посмотреть, что вообще можно реализовать?

    Для начала попробуйте портировать проекты, или их модули из тех, в которых вы участвовали.
    Ответ написан
  • Как вы считаете так делать тупо?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Для 2006-го года вполне норм.
    С тех пор на php нашли следующие напасти:
    * PSR-2 - это набор соглашений по форматированию кода.
    * PSR-4 - это правила по реализации автолодинга.
    * Composer - это библиотека для управления зависимостями и генерации автолодинга.
    * Появилось много шаблонизаторов типа twig.
    * Устоялось понятие router и это понятие реализовано практически в каждом современном фреймворке.

    Как вы считаете, такой подход приемлимый, или быдлокодинг в квадрате?

    Это не говнокод, который нет смысла поддерживать.

    Почитайте на досуге, думаю вам будет полезно.
    Ответ написан
  • Как динамически в зависимости от условий, передавать то или иное количество параметров в функцию?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Почитайте про рефлексию. Будьте осторожны, велика вероятность отстрелить себе яйцы подобной магией.
    Ответ написан
  • Что не так c моим мега php "демоном"?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    TL;DR
    * Стартуйте воркеры через supervisor
    * Для очередей используйте сервер очередей, например rabbitmq
    * Используйте PSR-3 совместимый логгер

    1. Запускалка воркеров по крону... посмотрите supervisor, не создавайте костыльных велосипедов.
    2. Лок таблицы - жирно, очень жирно)) Лок записи - еще куда ни шло. Вы даже малую нагрузку так выдержать не сможете.
    3. Воркер - такая штука, что спокойнейшим образом может отвалиться, по этому лучше ее рестратовать сразу, см. supervisor
    4. В случае проблемных тасок рискуете потерять не отработавшие.
    5. Вы не проверяете аргументы методов - вот это печально, что будет, если вызвать
    $task->start("'; DROP TABLE " . PREFIX . '_tasks');

    6. Для логгирования очень рекомендую использовать что-то на базе PSR-3, Monolog например, не плодите костылей.
    7. В воркере вы локаете таску, в таскере разлокиваете, зачем таскеру это делать? Если уж так, то лок И анлок - задача воркера.
    8. Вы когда выгребаете новые таски, смотрите на lock=0, при завершении ставите lock=0, похоже на хрень. Получается одна и та же таска постоянно будет выполняться.
    Ответ написан
  • Что не так в данном коде PHP и почему?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Проще сказать, что у вас так...
    <?php
    // Не стоит использовать глобальные И суперглобальные переменные.
    // Лучше в принципе забудьте про их существование.
    // В начале обработки сформируйте Request и уже далее с ним работайте.
    // Вы данные на входе даже не проверяете, это ужасно
     $uname = $_REQUEST['user_name'];
     $upass = $_REQUEST['user_pass'];
    
    // Это уже прошлое, mysql_*** НЕ поддерживается.
     mysql_connect("localhost", "root", "12345678");
     mysql_select_db("orders");
    
    // см. выше на счет суперглобальных переменных.
     $user_ip = $_SERVER['REMOTE_ADDR'];
    // Почитайте про PSR и забудьте про существование однострочных управляющих конструкций
     if ($_SERVER['HTTP_X_FORWARDED_FOR']) $user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    
     if ($user_ip=="127.0.0.1")
        {
    // Авторизация по ip, вы серьезно?))
          echo "Добрый день Администратор<br>";
        }
        else
        {
    // Что будет, если отправить $upass="';DROP TABLE users; SELECT '1" ?
    // Это называется sql инъекция
    // Параметры подставляются по другому
           $sqlQuery = "SELECT * FROM users WHERE uname='$uname' and upass='$upass' and `real`=1";
           $result = mysql_quеry($sqlQuery) or user_error(mysql_error()."<br>".$sqlQuery."<br>", E_USER_ERROR);
    // Не используйте присваивания в условиях
           if ($user = mysql_fеtch_array($result));
              {
                echo "Здравствуйте ".$user['fio']."<br>";
              }
              else
              {
                echo "Я вас не знаю"; exit;
              }
        }
    // см. выше на счет суперглобальных переменных
     if ($_REQUEST['search'])
        { // Выводим результаты поиска
          echo "Результат поиска: <br>";
          $search_name=$_REQUEST['search'];
    // Что будет, если отправить $search_name="';SELECT CONCAT(uname, ' ', upass) AS info FROM users" ?
    // тоже sql-инъекция
    // и входящие данные вы не проверяете
          $sqlQuery = "SELECT * FROM forms WHERE satus='$search_name'";
          $result = mysql_query($sqlQuery) or user_error(mysql_error()."<br>".$sqlQuery."<br>", E_USER_ERROR);
          while ($one_form = mysql_fetch_аrray($result))
            {
               echо $one_form['info']."<br>";
            }
    
          }
     echo "<form>Введите поиск: <input type=text name='search'><input type=submit></form>".;
    ?>

    Обязательно посмотрите
    Ответ написан
  • Как собрать логику и работу websockets?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Можете посмотреть в направлении систем типа centrifugo
    Ответ написан
  • Организовать phpDoc для __get property где property это экземпляр класса, как?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Вам магический геттер не нужен, о слова "совсем". Под приватные свойства сделайте геттеры, это вам здорово облегчит жизнь. Да и костыли с док блоками городить не придется.
    Рекомендую почитать про SOLID, ваш Base - это божественный объект.
    Так же очень настоятельно рекомендую почитать про PSR-4, сейчас никто не пишет свои автолодеры.

    На счет dock block property, он объявляется:

    /**
     * @property TYPE_HERE VAR_NAME_HERE [DESCRIPTION]
     */


    П.С. Код не мой, переписать не хочется, так как есть много проектов на этом движке.

    Если есть возможность выбросить этот движок - делайте поскорее, иначе технический долг будет только возрастать, а код очень скоро станет не саппортабельным
    Ответ написан
  • Как реализовать шанс?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Вы зря указываете проценты, это не корректно. 20, 40, 60 - это просто множители вероятности попадания. Так что даже если будет 20, 40, 60, 100 - это проблемой не будет. Считаете rand(0, 20+40+60+100), далее определяете в какие пределы попало число.
    Ответ написан
  • Класс управления зависимостями, как вам реализация?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    // Должен быть приватным
    DependencyManager::$dependencies;
    
    // Что это за хардкод?))
    DependencyManager::__construct
    
    // 1. Вы не проверяете аргументы, что будет, если я передам в $class
    // например new \Exception()? А еще лучше строку "trololo"?
    // 2. Нейминг - гуано, вы не проверяете зависимость, а возвращаете.
    // 3. Если зависимость не найдена - будьте добры исключение.
    DependencyManager::checkDependencies($class)
    
    // Эта переменная не нужна, передавайте ее в метод
    Loader::$className
    
    // Эта переменная должна быть приватная, что будет, если туда вставить
    // например строку и попытаться обработать?
    Loader::$dependencyManager;
    
    // Херня. У вас метод делает какую-то магию.
    Loader::loadClass


    Из SOLID вы нарушили:
    * SRP - Loader выполняет И управление зависимостями и подгрузку. То что вы называете DependencyManager - это конфигурация, но ни как не менеджер зависимостей
    * OCP - у вас явно открыты свойства, которые отвечают за внутреннюю логику выполнения. А то вот конфиги из вашей конфигурации зависимостей стоит возвращать через геттер
    * ISP - вы в принципе не заморачиваетесь с интерфейсами, а полностью зависите от реализации.

    Странно то, что загрузку не делаете рекурсивной, что если у вас у зависимого класса тоже есть зависимость?
    Плохо то, что инициализируете сразу все классы, что если их будет много?

    Еще пришла идея в классы с зависимостями передавать в аргументах интерфейсы, а не объекты.

    Отличная идея)) как только в PHP появится инициализация интерфейсов - вернетесь к ней, а пока что забудьте.

    Когда наиграетесь - выбрасывайте и переходите на качественные решения, по совету shaqster
    Ответ написан
  • Считается ли плохим тоном, наследование PDO в класс вспомогательной обертки?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Вообще говоря \PDO - это чужой вендроский код, вам на прямую неподвластный (разве что сырцы пыхи пилить будете), так что лучше все таки обертку, так как она будет гарантировать вам постоянство интерфейса работы с БД.
    С другой стороны, если выделаете что-то не большое - выбирайте по удобству, если удобнее и быстрее наследование - пусть будет так, если обертка - тогда обертка. Руководствуйтесь здравым смыслом.
    Посмотрите Doctrine на досуге
    Ответ написан
  • Можно ли сохранять в git папку vendor после composer update?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Если одни разработчик обновил библиотеки, другие должны как то об этом узнать, чтобы обновится у себя

    Если другие разработчики делают git pull и не обращают внимания на изменения - это их проблемы. Хорошим тоном является уведомление от автора правок в composer.json, что остальным стоит его обновить.

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

    Вообще говоря композер умеет в кэш и одни и те же версии либ тянутся с кэша.

    В проекте могут быть заняты люди, которые не умеют (или не могут в данный момент) работать с консолью: верстальщики, технические писатели, ревьюер кода (безопасности), сюда же и вопрос оплаты специалиста, которые умеет всё

    Если нужно именно поднять окружение с проектом - настройте vagrant и пропишите в README как им пользоваться конкретно для вашего проекта.
    Что касается людей:
    * верстальщики - vagrant
    * технические писатели - я конечно не в курсе вашего проекта, но я бы доступ даже к репозиторию не дал, максимум - завел отдельный репозиторий для них.
    * ревьюер кода (безопасности) - ревьюер, который не может в composer / консоль?? Шутка не удачная.
    * сюда же и вопрос оплаты специалиста - лолшто? Это вообще не связано с окружением вашего проекта, ну вот ни капли.

    Нет возможности просто и быстро передать кому-то код, просто расшарив ссылку на гит

    Если у вас проект НЕ opensource - то такого делать в принципе нельзя. Доступ к репозиторию должны иметь специалисты, которые работают с кодом этого проекта и ни кто другой, а composer тут вот ни капли ни при чем!

    Вопрос в том, можно ли сохранять папку vendor в git

    НЕТ! Вы придумали НЕ существующую проблему и пытаетесь героически ее решить, только от этого решения будет еще хуже.

    насколько это противоречит принятому стилю

    на полностью

    какие могут быть проблемы с этим (сейчас самый жирный минус от такого подхода вижу в распухании репозитория) ?

    1. Вы становитесь вендором кода, который взяли где-то, как следствие вы следите за его обновлением, у изначального вендора и вы проводите аналогичные правки в своем проекте. Если так не делать - баги, найденные в этой зависимости сами себя не пофиксят и этот код будет быстро устаревать.
    2. В код зависимости появляется соблаз провести собственные наработки - это то, что делать нельзя, иначе процесс обновления будет сложнее на порядки.
    3. Ваш репозиторий разбухнет.
    4. Композер вашу зависимость придется явно прописать иначе автолоад может ее не подтянуть.

    Использует ли кто-нибудь такую практику в своих проектах ?

    Пару лет назад работал на крупном проекте, который начинался до появления композера. Когда зависимостей тьма и ты не знаешь, какие из них содержат артефакты собственных наработок, какие обновляются синхронно с официальными вендорами, а какие тянутся из вне приходится тратить кучу времени на выяснение. Это просранное время.
    Ответ написан
  • Как безопаснее PDO?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Ни первое, ни второе.

    0. SQL запросу ну вот ни как не место в аргументах, это то, что должен делать ваш insert метод. Все что он должен получать - это аргументы которые будут вставляться в ваш запрос!
    1. Вы не проверяете аргументы. Что произойдет, если я вызову insert:
    $db->insert(new \Exception(), []);
    Или так
    $db->insert("DELETE FROM user", []);
    Или так (тут lastInsertId вернет не id вставки)
    $db->insert("SELECT CURRENT_TIMESTAMP", []);
    2. Никогда, слышите? НИКОГДА! Не используйте при работе с БД суперглобальные переменные. Их удел - в самом начале index.php собрать объект Request, далее про их существование можно забыть.
    3. datab обычно называются connection, либо по типу класса
    4. В следующем коде нет смысла, от слова "совсем"
    }catch(PDOException $e){
                    throw new Exception($e->getMessage());

    Вы просто обрубаете стектрейс, который далее стоит использовать для поиска ошибок.
    5. У вас ключи строковые, зачем вот это?
    unset($arr[$key + 1]);
    6. Если в params передать [[]], как себя поведет ":$key"?
    7. lastInsertId возвращает строку, кастовать в ваш тип не помешает.
    8. Ради всего святого: прочитайте и следуйте PSR

    Вот вам пример безопасного кода. Проверок в реальном коде должно быть на много больше:
    * логин стоит прогнать по регулярке на допустимые символы
    * почту стоит прогнать по регулярке, или через filter_var
    * что пароль таки хэш (смотря какой алгоритм используете)
    * если будут еще поля не строковых типов - их подключаем через bindValue с указанием типа
    Тут сделано допущение, что подключение PDO уже настроен на бросание ошибок. В задачи репозитория не входит конфигурирование коннекшна.
    По хорошему это дело еще и в транзакцию обернуть.
    <?php
    declare(strict_types = 1);
    
    class UserRepository
    {
        /** @var \PDO */
        private $pdo;
    
        /**
         * @param PDO $pdo
         */
        public function __construct(\PDO $pdo)
        {
            $this->pdo = $pdo;
        }
    
        /**
         * @param string $login
         * @param string $email
         * @param string $password
         * @return int
         * @throws \InvalidArgumentException
         * @throws \PDOException
         */
        public function insert(string $login, string $email, string $password): int
        {
            if (empty($login)) {
                throw new \InvalidArgumentException('Argument "$login" must be not empty');
            } elseif (empty($email)) {
                throw new \InvalidArgumentException('Argument "$email" must be not empty');
            } elseif (empty($password)) {
                throw new \InvalidArgumentException('Argument "$password" must be not empty');
            }
    
            $sql = '
            INSERT INTO `user`(
                `login`,
                `email`,
                `password`
            ) VALUES (
                :login,
                :email,
                :password
            )';
    
            $this->pdo->prepare($sql)->execute(
                [
                    ':login' => $login,
                    ':email' => $email,
                    ':password' => $password
                ]
            );
            
            return (int) $this->pdo->lastInsertId();
        }
    }
    Ответ написан
  • Как начать осмысленную разработку веб приложений на php?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Вот список штук которые делать не стоит. Если что не понятно, почему нельзя - спрашивай.

    PSR - СВЯТОЕ, ОБЯЗАТЕЛЬНО ЗНАТЬ

    Прошу подсказать, куда искать, что почитать, что бы в голове прояснилось как грамотно проектировать подобные проекты. Хотя бы какие ключевые слова присутствуют в описании данных процедур.

    Если нужно понимение, что и зачем - Symfony ну и разве что Zend.
    Никакие Laravel, Yll тебя хорошим практикам не научат, увы. Это я как в прошлом фан yii говорю.
    Что так? Погугли на тему: "Singleton antipattern", "ActiveRecord antipattern"
    Ответ написан
  • Continuous delivery, Continuous integration, Docker при "многоверсионном" приложении. Как организовать?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Не нравится, что в итоге заводится куча тегов, веток, может есть альтернативное решение для такой задачи?

    На самом деле это оптимальное решение. У вас создается релизная ветка в которую в случае проблем именно на этой платформе будут вливаться фиксы, не мешающие другим. Далее когда релизный образ оттестирован и дан зеленый свет - они размазывается по проду. То что тегов много - да какая разница?)) У вас есть возможность получить состояние любой сборки.

    Схема кажется немного избыточна nginx->nginx->php, в итоге на сервере дофигища разных процессов, особенно nginx.

    Тут все зависит от того, можно ли отдавать клиенту доступ на прямую к nginx2. Если нельзя - ваша схема вполне норм. Если же можно - тогда стоит это делать, смотрите в сторону своего балансировщика, который будет отдавать клиенту сервер, который А - жив, Б - минимально нагружен и штук типа consul.

    ansible забирает из гита исходный код, грузит на сервер, в контейнеры исходники пробрасываются через volume.

    Зачем? Контейнер как бы иммутабельный и все такое. Если у вас там кучка статики подсасывается не под git - смотрите в сторону mogilefs и т.д. Безусловно, для разработки volume - самое оно, но для прода - ну такое..., должна быть веская причина.
    Ответ написан
  • Обычные константы, или константы в классе?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    В константе без класса - не стоит, view тут в принципе ни при чем. Как правило домен - это данные конфигурации вашего окружения/приложения. Можете сделать конфиг-класс с константой своего домена.

    По хорошему в генерацию ссылок по роутам должен уметь сервис (либо в составе роутера, либо отдельный) который уже знает про ваш домен. А дописывать его руками - это не то, что бы плохая практика, скорее странно.
    Ответ написан