Задать вопрос
Ответы пользователя по тегу PHP
  • Определение значений передаваемой в функцию переменной типа массив?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это один из тех вопросов новичков, на который нельзя давать прямой ответ. Он превратится в пустое умствование и говнокод. Соглашусь с комментарием Дмитрий: тут просто не нужен массив. И тем более не нужно городить огород из абстракций. Тут явно нужен банальный VO/DTO, а автору надо перестать пытаться заворачивать привычные массивы в солидно выглядящие объекты, и начать использовать сами объекты.

    Если нам нужна конкретная структура, то и описываем её в конкретном классе, безо всяких интерфейсов:

    final readonly class Parameters
    {
        public function __construct(
            public string $key1,
            public int $key2,
            public DateTimeImmutable $key3,
        ) {}
    }
    public function execute(Parameters $parameters):


    В итоге у "стороннего разработчика" есть готовая документация - простое и понятное определение класса, экземпляр которого он должен передать в ваш метод. И уже на этапе создания этого объекта РНР надаёт разработчику по рукам, если хоть какое-то свойство не будет задано, или будет не того типа. При желании можно в конструктор добавить дополнительную валидацию, если просто типа недостаточно.

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

    Если же речь про валидацию входящих данных, то это вообще совсем другой вопрос.

    Для этого есть либо стандартные валидаторы, когда на вход подаётся массив и набор правил, вот например как в ларавле, симфони или в десятке отдельно стоящих библиотек, а на выходе - или гарантированно валидная структура данных, или ошибка.

    Либо готовые библиотеки десериализации, когда входящий JSON автоматом мапится на существующий объект, и в итоге получается или либо гарантированно валидный объект, или ошибка.

    В этом случае документацией для обоих вариантов является сваггер, а фидбеком - ошибки валидатора.
    Ответ написан
    Комментировать
  • Как мне защитить файл подключения к бд?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Типичный вопрос новичка, на который не следует давать прямой ответ.
    А вместо этого надо дать новичку по рукам, чтобы не теребил ненужное.

    Никакой проблемы в том, что "на этот файл можно попасть с помощью обычной ссылки" нет. Надо забыть про эти нелепые страхи, и начать защищаться от "инъекций", которые представляют реальную опасность, а не выдуманную. Тем более что сделать это несложно.
    Ответ написан
    1 комментарий
  • Как лучше реализовать проверку передачи данных в api?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Отдельно проверять наличие нет смысла. Если уж валидировать, то нормально, каждое поле, на соответствие ожидаемому формату. Ну и заодно и наличие.
    А скопом если проверять, то скорее на наличие лишних полей.

    Плюс никаких исключений. Странно, что я не обратил на это внимание в прошлый раз, там этот говнокод с try catch просто везде. Самому не надоедает всё время писать эти тру, кетч, ретурн для каждого запроса? И с какой стати пользователь API должен читать, что в БД нету например нужной таблицы? Это ВНУТРЕННЯЯ информация, которая не должна утекать наружу

    Как вариант, метод validate должен возвращать массив с ошибками.
    Если массив пустой, то используем данные
    Если не пустой - возвращаем их пользователю.
    Ответ написан
    1 комментарий
  • Какой параметр php модуля отключает тему формы с сайта?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Проще починить саму форму, чем искать черную кошку в темной комнате. Тем более, что её там скорее всего и нет.
    Ответ написан
    Комментировать
  • Авторизация PHP. Как исправить Warning: Undefined array key "login" in?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Данная ошибка может возникать в двух случаях:
    - если вы обращаетесь к этому скрипту напрямую, а не как к обработчику формы
    - если в форме были ошибки, и она тупо не передаёт поля login и pass методом POST.

    Чтобы исправить первый вариант, и вообще для порядка, надо добавить проверку на метод POST.
    Чтобы получить помощь для второго варианта, надо догадаться добавить в свой вопрос код формы.

    В целом же, эта авторизация будет бессмысленной, даже когда заработает. Поскольку любой придурок легко авторизуется без пароля, тупо через SQL инъекцию. Очердной пример того, что учить программирование "по видео из интернета" - это пустая трата времени
    Ответ написан
    1 комментарий
  • Изучение php с нуля для верстальщика?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Тут проблема скорее не в том, что 4-5 лет, а в том, что за редчайшими исключениями, любые видеокурсы - это отборный говнокод. Конкретно про Дмитрия Лаврика не скажу, но простая статистика говорит о том, что учить РНР по видеокурсам не стоит.

    Лучше потратьтесь на книжку, Джон Дакетт, PHP&MySQL. Там очень толково, на примерах даётся не только язык, но и все важные аспекты программирования - обработка ошибок, отладка, рефакторинг, структура приложения, SQL, обработка изображений, и куча всего остального. В последних главах весь материал даётся на примере создания простой но рабочей социальной сети.
    Ответ написан
    1 комментарий
  • Как правильно настроить права для веб-сервере apache2+php-fpm?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Самое первое, что стоит проверять в таких случаях - это selinux.
    Самое второе - что все папки в цепочке от корня читаемы для пользователя пхп.

    А если говорить в целом, запускать пхп от пользователя хттп довольно бессмысленно. Пользователь фпм должен совпадать с владельцем файлов. То есть запускать надо от девопса.

    Лично я делаю так: веб-сервер работает под своими группой/пользователем, а пхп - под SSH логином пользователя сайта. У вас это может быть видимо этот девопс.
    Чтобы их поженить, просто добавляем пользователя веб-сервера в группу пользователя, usermod -a -G devops www-data, а папочке веб-сервера соответственно выставляются права 750. Веб-серверу нужно только чтение, и он его имеет через группу. Таким образом можно соорудить такой мини-хостинг, разные ползователи не могут ходить в папки друг друга, и при этом нет обычной чехарды, когда пользователь ssh/ftp и пользователь пхп-фпм разные.
    Ответ написан
    2 комментария
  • Можно ли прикрутить нативную функцию?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Можно, но не нужно.

    Функция, которая пытается проискейпить все данные скопом сама по себе не нужна. Каждое значение надо форматировать отдельно.
    И уж тем более функция, которая портит исходные данные. Представим, что одну и ту же информацию мы отправляем по емейлу, и в СМС. Сначала проискейпим HTML для шаблона письма, а потом эти же данные отправим в SMS... И там будут эти "
    И уж тем более функция, которой требуется доступ к свойству объекта на запись, который далеко не всегда есть.
    Ответ написан
    3 комментария
  • Как выбрать максимальное значение во вложенных массивах?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    просто и красиво?

    Перебрать массив и получить максимальное значение - это три строчки. Куда проще-то?

    Есть какая-то функция или сочетание функций

    Есть поговорка. "Дурная голова ногам покою не даёт". И ещё есть принцип, KISS, который переводится как "не надо пытаться выглядеть умнее, чем ты есть, дурачок - опозоришься".

    Самый простой и красивый код - это тот который ты написал сам и понимаешь, как он работает. И сможешь в случае чего исправить. А не побежишь снова на Хабр, "мне тут пацаны дали красивое, а можно чтобы оно ещё и работало?"
    Ответ написан
    2 комментария
  • Что лучше использовать для связей в бд?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ну разумеется, что в общем случае через SQL-запросы. Они для того и придуманы.
    Но есть нюансы, иногда связанные данные приходится доставать другими методами.
    Например, чтобы не делать 500 отдельных запросов, берутся id нужных записей и выбираются одним запросом через where in()

    Кстати, лучше всё-тиаки разделить код на модели и контроллеры. SQL убрать в модели, а в контроллерах оставить только вот это вот if ($pools) {
    Ответ написан
  • Deprecated: Implicit conversion from float to int loses precision in что не так?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Знаю, что надо как-то подставить (int) intval () floor() или round() на худой конец, но как?


    Предлагаю сразу два варианта
    1. разбить вызов imagecopy на строки, чтобы каждый операнд был на своей строке, включая и арифметические. ну то есть
    imagecopy (
    $img,
     $font,
     $x
     - 
    $shift,
    $y
    ...

    Так сразу будет видно, на какой строчке флот окопался.
    2. скопировать строчку, вместо imagecopy написать var_dump и заменить все минусы на запятые, с той же целью
    Ответ написан
  • Почему не работает Cron?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Почему не работает Cron?

    Наверное, вместо бессмысленного /dev/null надо указать путь к файлу, в котором появится ответ на этот вопрос?
    Ответ написан
    Комментировать
  • Положительно ли скажется на производительности перевод бд на utf8mb4 и удаление из after_connect_d7.php соответствующих директив?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Нет, неверно.

    character-set-server и collation-server вообще ни на что не влияют. А только задают умолчания, если при создании БД и таблиц ленивый программист не указал кодировку. Поэтому трогать их нет смысла вообще.

    Добавлять utf8mb4 в соединение также бессмысленно, если сами данные в utf8. Расширенные символы она всё равно сохранить не сможет.
    И наоборот - если таблицы в utf8mb4, то указывать её при соединении надо в обязательном порядке. Не потому что вдруг "конвертация на лету" а потому что если соединение будет utf8, то расширенные символы клиент не получит.

    (В теории, всё может работать нормально и без установки utf8mb4 для соединения, поскольку она в пыхе в какой-то момент начала использоваться по умолчанию, но лучше всё-таки задавать явно)
    Ответ написан
    Комментировать
  • Почему аутентификация возвращает форму авторизации?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что выполняется одно из условий.
    Ответ написан
    Комментировать
  • Почему фид не открывается как xml?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    1. Гуглим simplexml_load_string ошибки
    2. Открываем страницу https://www.php.net/manual/ru/simplexml.examples-e...
    3. Берём с неё код и немного модицифируем

    libxml_use_internal_errors(true);
    
    $sXML = download_page($url);
    $xml = simplexml_load_string($sXML);
    
    if ($xml === false) {
        throw new RuntimeException(
            "XML parsing errors: ". implode("", array_column(libxml_get_errors(), 'message'))
        );
    }


    Смотрим ошибки, исправляем.
    Ответ написан
    Комментировать
  • Как передать имя таблицы как параметр?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    В 99% случаев, необходимость подставлять таблицу в запрос динамически говорит о говнокоде.
    А в данном случае даже гадать не нужно - этот цикл и "неопределённо много таблиц" - это уже стопроцентнтный говнокод из палаты мер и весов.

    Таблица должна быть одна. И все проблемы сразу исчезнут как по волшебству.
    Ответ написан
    Комментировать
  • Как правильно вывести ошибки регистрации?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Просто сама вьюшка разрастается.


    Такова жизнь. Вью - это логика представления. Вот логику мы и добавляем. И это ещё цветочки, бывает куда больше.

    Упростить вьюшку можно перенеся необязательную логику в контроллер. Например явно задавая все используемые значения.

    foreach ($rules as $key => $throwaway) {
        $errors[$key] = $_SESSION['errors'][$key] ?? '';;
        $input[$key] = $_POST[$key] ?? $_SESSION['input'][$key] ?? '';
    }
    unset($_SESSION['errors'], $_SESSION['input']);


    И в шабалоне уже ничего не проверять

    <p>
        Имя: <input type="text" name="name" value="<?= h($input['name']) ?>">
        <?= h($errors['name']) ?>
    </p>


    И сделаю одно замечание. У вас при выводе в HTML экранируются не все значения. А должны - все.
    Чтобы не ломать пальцы, набирая htmlspecialchars каждый раз, сделать функцию-хелпер.
    Ответ написан
  • Как правильно перебрать вложенный массив и вывести результат?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Так и выводить. Во внутреннем фориче только категории, а не всё подряд.
    echo "<ul>\n";
    foreach ($goods as $name => $categories) {
        echo "<li>$name: ";
        foreach ($categories as $i =>$category) {
            echo $i ? ", " : "";
            echo $category;
        }
        echo "</li>\n";
    }
    echo "</ul>\n";
    Ответ написан
  • Как в php получить Последнее значение из таблицы mysql определенной даты даты?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Выносить имя таблицы и колонки в переменные не нужно. Их надо написать прямо в запросе.
    А дату надо подставлять в запрос через подготовленные выражения.

    Если в БД хранится только дата, то чтобы получить все строки за определённую дату, код будет такой.
    $sql = "SELECT * FROM название таблицы WHERE  DATE = ?";
    $result = $conn->execute_query($sql, [$dateNew]);
    $usersArray = $result->fetch_all(MYSQLI_ASSOC);

    Если же хранится дата и время, то надо подставить начальный и конечный период. То есть запрос будет

    SELECT * FROM название таблицы WHERE  DATE BETWEEN ? AND ?

    и в него подставлять значения "$dateNew 00:00:00" и "$dateNew 23:23:59"

    Чтобы получить одну запись, надо добавить в запрос оператор LIMIT 1, а fetch_all(MYSQLI_ASSOC) поменять на fetch_assoc()
    Чтобы получить "последнюю" запись, надо добавить в запрос сортировку по тому полю, по которому считается последовательность добавления. И сделать сортировку в обратном порядке
    Ответ написан
    1 комментарий