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

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    PHP 5.3

    PHP 7.0


    Ничего не смущает?

    На всякий случай напоминаю, что область видимости в анонимках появилась в 5.4 лет 10+ назад.
    Ответ написан
    1 комментарий
  • Какую ORM библиотеку стоит использовать для php веб-приложения в долгосрочной перспективе?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    1) Либо Doctrine, если нужен DM
    2) Либо Eloquent, если достаточно AR (выдирается и используется отдельно от ларки без проблем).
    Ответ написан
    Комментировать
  • Undefined variable при проверке переменной?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    При этом я через if ($errors) else как раз и проверяю существование переменной.


    if - это не проверка на существование. if - это проверка на то, что существующая переменная соответствует boolean true. Почитайте, пожалуйста документацию по основам языка: php.net/manual/ru/control-structures.if.php
    Ответ написан
  • Проблема заголовка Sec-Web-Socket-Accept, как исправить?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Есть подозрения, что pack не нужен:
    // SEC_KEY_UUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
    // $key = Sec-WebSocket-Key header
    
    $accept = \base64_encode(\sha1($key . self::SEC_KEY_UUID, true));
    Ответ написан
  • Где размещать вспомогательные классы в mvc архитектуре?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Есть несколько вариантов решения это проблемы.

    1) Некоторые могут пропагандировать сервисный слой (design-pattern.ru/patterns/service-layer.html), как следствие: "App/Services/ServiceName" - набор классов, отвечающих за какое-то абстрактное действие. Например: "UserAvatarUploaderService", который отвечает за загрузку аватарки пользователя.

    2) В качестве альтернативы и способ, который предпочитаю я - это создание директории "src" с набором независимых компонентов, включая собственный composer.json. Тот же сервис загрузки аватарки будет выглядеть следующим образом:
    - src/
        - AvatarUploader/
            - README.md
            - composer.json
            - tests/ ...
            - src/
                - AvatarInterface.php
                - FileSystemInterface.php
                - FileSystemUploader.php
                - UploaderInterface.php


    Для подключения этой библиотеки достаточно будет прописать в корневом:
    {
        "repositories": [
            {
                "type": "path",
                "url": "./src/AvatarUploader"
            }
        ],
        "require": {
            "app/avatar-uploader": "*"
        }
    }


    А выглядеть внутренний (т.е. внутри "src/AvatarUploader") composer будет так:
    {
        "name": "app/avatar-uploader",
        "autoload": {
            "psr-4": {
                "AvatarUploader\\": "src/"
            }
        }
    }


    Таким образом мы запилим совершенно независимый компонент со своими тестами и зависимостями, а внутри основного приложения будем лишь к нему обращаться.
    Ответ написан
    1 комментарий
  • Шуточная функция на php?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    function money (int $count = 100500): iterable {
        for ($i = 0; $i < $count; ++$i) {
            yield $i => $count;
        }
    }
    
    foreach (money() as $current => $available) {
        echo "\rПожалуйста подождите, идёт загрузка денег $current из $available";
        \flush();
        \usleep(10000);
    }
    Ответ написан
    Комментировать
  • Нормально ли так проверять авторизацию?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Всё печально. Давай по-порядку:

    Одной из ключевых задач ООП является абстракция, что требует декомпозиции кода. Следовательно, первым шагом для причёсывания кода будет:
    class Worker extends User // <- Не стоит забывать о PSR
    {
        public function __construct(array $data)
        {
            if (empty($data)) {
                header(....);
                exit;
            }
    
            // В конструкторе нет ретурна, так что это ошибка
        }
    }


    Шаг 1 Результат: Мы отвязались от кукисов и можем эту же логику переиспользовать вообще с чем угодно.

    Теперь мы больше не связаны с окружением (ещё header надо убрать) и имеем код, позволяющий переиспользовать себя в различных ситуациях:
    $worker = new Worker($_COOKIE);

    Ну и так далее.

    При этом есть фатальные косяки (отвечая на твой вопрос "Нормально ли так проверять авторизацию"): Что если я возьму, открою консоль в браузере и заменю кукис id=1 на id=42?

    Решаем эту проблему:
    $worker = new Worker($_SESSION);

    Вот и пригодились все "улучшения", которые мы произвели ранее. Для решения проблемы нам понадобилось лишь заменить источник данных (т.е. массив) из кукисов на сессии. Этот процесс передачи данных извне называется "делегированием".

    Помимо этого - сам процесс входа в систему называется "аутентификацией", а не "авторизацией". Авторизация - это процесс проверки прав доступа к какому-то функционалу.

    Результат не идеален и содержит ещё кучку проблем, но с фатальными мы вроде разобрались.

    Твоя задача далее, разу уж ты поставил тег "ООП" - смотреть на код, который ты написал и попробовать его перенести в другие условия. Если он там уже работать не будет без изменений его внутренностей - значит в коде есть набор косяков. Пример:
    1) Можно ли использовать твой код, получая данные не из БД, а из файлов?
    2) Можно ли создать нового "рабочего" не передавая туда ID, чтобы он сгенерировался сам на основе, например, auto increment поля в БД?
    3) Можно ли добавить условия в запрос к БД (например, что "рабочий" не забанен)?
    4) и т.д.
    Ответ написан
    7 комментариев
  • Какую OC и веб-сервер выбрать для сайта?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Судя по вашему вопросу (и опыту работы соответственно) - можете выбирать любой. Ничего особенного не изменится.

    Если же детализировать, то
    1) Для новичков, которым пофигу и лишь бы работало - apache + mod_php + всё что угодно
    2) В нормальной же жизни обычно используют nginx + fpm + debian (ну или что-нибудь ещё, просто дебиан самый стабильный, а накатить поверх последние версии ПО - не проблема).
    3) Для хайлоада годным решением будет swoole/roadrunner + clear linux
    Ответ написан
    Комментировать
  • PHP. Почему увеличивается пиковое значение используемой памяти при очистке переменных и массивов?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Не очень понятно, почему при удалении массивов и переменных пиковое использование памяти скриптом растёт.


    Потому что unset не удаляет ничего, а добавляет в zval новые данные - флаг удаления, для того, чтобы GC смог подчистить их при следующем запуске (Хотя это тоже не так, GC в пыхе почти ничего не подчищает, а просто перезаписывает поверх, т.к. аллокации памяти требуют времени).

    А сама операция unset нужна лишь для того, чтобы корректно убирать данные в реалтайм (т.е. грубо говоря while true) приложениях, если нет уверенности в том, что refcount после отработки кода у zval будет равен 0. Если же в приложении нет никакого эвентлупа, то использование unset и gc_collect_cycles будет лишь добавлять тормозов и пиков потребления памяти.

    Это не абсолютная истина, конечно. Но лучше доверить менеджмент памяти именно PHP. Но например, в приведённом выше коде, который устарел лет на 10 и сейчас просто не будет работать - после последней строчки не останется вообще никаких переменных в памяти. Точнее они останутся, но с refcount = 0, а значит создание новой переменной просто перезапишет уже выделенную память.
    Ответ написан
    3 комментария
  • В чем недостатки такого решения?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    В чем недостатки такого решения?

    Помимо отсутствия транзакционности в коде (о чём уже упоминали выше):

    1) Нет ключа на thread_id (желательно foreign)
    2) Типы в INT, вместо UNSIGNED INT
    Т.к. это MySQL, судя по вопросу, то:
    3) Нет указания на collation таблицы (желательно utf8mb4)
    4) Нет указания на движок таблицы (транзакции есть только в InnoDB и их нет в ISAM, MyISAM, Archive, Memory, etc.)
    5) Нет уникальности голосов (т.е. votes), как следствие - таблица денормализованная и подсчитывать так голоса - крайне глупо. В нормальном мире это делается отдельной таблицей с привязкой по comment_id и уникальным ключом на comment_id + user_id.
    6) Так как это комментарии, то использование varchar(255) для поля text - глупо. Нужен TEXT или LONGTEXT.
    7) Отсутствуют поля даты создания и редактирования, что в будущем не позволит строить статистические данные или расширять функционал (разрешать менять текст комментария только в течении 5ти минут, например). На это надо закладываться заранее.

    Это что касается структуры таблицы. Теперь по коду:
    8) Сервис-локация (класс App), вместо нормального DI - это жесть. Скрытые зависимости говорят о невозможности тестирования такого кода.
    9) "Магическая" константа 'comment' говорит о том, что потом такой код нормально не отрефакторить. Т.е. переименовываешь внутри что-то, а потом получаешь кучу ошибок и придётся лазать по коду и везде выгребать этот "get('comment')". И не дай бог где-то они получаются как-то иначе. Работы ещё на пол дня.
    10) Метод getById говорит о том, что сущность должна возвращаться всегда. Однако, может так случиться, что её по указанному id просто не найдётся. Как следствие - нет нормальной обработки ошибок.
    11) Мутабельное поле votes у comment (т.е. имеется прямой доступ к нему). Это говорит о том, что сущность очень сильно связана с БД, а значит любой рефакторинг таблицы ведёт к полному перелопачиванию всего кода.
    12) Нет обработки ошибок во время сохранения сущности.
    13) Метод vote - не лучшее название. Оно переводится и как глагол "голосовать" и как существительное "голос", что может запутать. Я бы переименовал в addVote. Хотя и так тоже норм.

    Это всё, что касается вопроса "в чём недостатки такого решения". Ответ - почти на каждой строчке косяк.

    Если есть вопросы - задавай, могу чуть поподробнее расписать что-либо.
    Ответ написан
    3 комментария
  • Почему не правильно работает регистронезависимость в регулярном выражении?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Потому что одно - исходный текст ($result[0]), а другое - найденные группы (в данном случае - $result[1], т.к. остальные погашены)
    Ответ написан
    2 комментария
  • Что нужно добавить в Dockerfile для php:7.1-fpm, чтобы картинки загружались и обрабатывались?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    RUN apt update && \
        apt install -y libjpeg-dev libpng-dev libfreetype6-dev
    
    RUN docker-php-ext-configure gd \
        --enable-gd-native-ttf \
        --with-jpeg-dir=/usr/lib \
        --with-freetype-dir=/usr/include/freetype2
    
    RUN docker-php-ext-install gd
    Ответ написан
    2 комментария
  • Ошибка: Fatal error: Call to a member function query() on a non-object in C:\OSPanel\domains\localhost\rabotnik\passengers\search.php on line 12?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    mysqli_query


    $pdo


    Ничего странного не находите?
    Ответ написан
    Комментировать
  • Будут ли отличия при экспорте корутины и возврате оной?

    SerafimArts
    @SerafimArts Автор вопроса
    Senior Notepad Reader
    Давным давно задавал этот вопрос. Отвечаю сам себе. В случае yield from он не захватывает return statment, объявленный в экспортируемом генераторе, в отличии от return.

    В качестве аналогии
    return $this->test();

    Можно использовать такой вариант:
    yield from $result = $this->test();
    return $result->getReturn();
    Ответ написан
    Комментировать
  • Элегантное решение для проброса значений в функциях php?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    $this->saver->save(...array_filter([$name,  $value]));
    Но это, кажется, вариант не лучше.
    Ответ написан
    Комментировать
  • Как вернуть 2 значения в PHP return?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Вариант 1 - Деструктуризация:
    // Возврат нескольких значений:
    function some() {
        return [23, 42];
    }
    
    // Получение
    [$a, $b] = some();
    
    \var_dump($a, $b);


    Вариант 2 - Деструктуризация с ключами:
    // Возврат нескольких значений:
    function some() {
        return ['a' => 23, 'b' => 42];
    }
    
    // Получение
    ['a' => $a, 'b' => $b] = some();
    
    \var_dump($a, $b);


    Вариант 3 - Генераторы с ключами:
    function some() {
        yield 'a' => 23;
        yield 'b' => 42;
    }
    
    foreach (some() as $key => $value) {
      echo $key . ':' . $value; // a:23 b:42
    }


    Вариант 4 - Генераторы без ключей:
    function some() {
        yield 23;
        yield 42;
    }
    
    foreach (some() as $value) {
      echo $value; // 23 42
    }


    Вариант 5 - Генераторы с возвратом:
    function some() {
        yield 23;
        return 42;
    }
    
    $value = some();
    echo $value->current(); // 23
    $value->next();
    echo $value->getReturn(); // 42


    Вариант 6 - DTO:
    class DataTransferObject
    {
        private $a;
        private $b;
    
        public function __construct($a, $b)
        {
            $this->a = $a;
            $this->b = $b;
        }
    
        public function getA()
        {
            return $this->a;
        }
    
        public function getB()
        {
            return $this->b;
        }
    }
    
    function some() {
        return new DataTransferObject(23, 42);
    }
    
    $value = some();
    echo $value->getA(); // 23
    echo $value->getB(); // 42


    И ещё куча всяких вариантов, но мне влом придумывать уже)
    Ответ написан
    4 комментария
  • Как обрабатывать файлы с русскими именами при загрузке POST?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Файл сохраняется стандартно:


    Это не стандартно. Так никто не делает, просто потому, что это дыра в безопасности. Не то что дыра, а прям дырищща. Если клиент передаст вам файл с каким-нибудь именем (естественно заэкранированным, т.к. точки сервак не пропустит) "../../../index.php", например, вы его так и сохраните?

    Делайте какой-нибудь "\md5($fileName . \random_int(0, \PHP_INT_MAX))" и не выдумывайте проблем себе.
    Ответ написан
    3 комментария
  • Сакральный смысл обьявлять переменные и массивы в php?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    1) Начиная с какой-то там древней PHP 4.x (или раньше) - необъявленный массив вызывает нотис (читай - ошибку в коде).
    2) Начиная с PHP 7.4 при работе со скаляром, как с массивом - вызывает варнинг

    Говорить о том, что наличие хоть одного нотиса - это очень плохо, думаю, не стоит.

    P.S. Но в данном случае, отвечая на вопрос, наличие этого массива не даёт вообще никакого преимущества. Он просто не нужен.
    Ответ написан
    Комментировать
  • FatalErrorException in PagesController.php. В чем проблема?

    SerafimArts
    @SerafimArts
    Senior Notepad Reader
    Читайте мануал и учите язык: php.net

    Ошибка никак не связана с Laravel.
    Ответ написан
    Комментировать