Задать вопрос
  • Можно ли настроить запросы к php через вебсокет и http одновременно?

    3. Вебсокет и unix сокет - это совершенно разные вещи. Websockets - это протокол обмена информацией по TCP/IP.
    Как работают websockets:
    - Клиент начинает с простого HTTP запроса с просьбой апгрейднуться до websockets.
    - Сервер соглашается, и тогда между Клиентом и Сервером устанавливается постоянное TCP/IP соединение, по которому данные могут ходить туда-обратно по протоколу websockets уже без кучи церемониальных ритуалов, как принято в обычном HTTP.

    1. Изначально PHP совершенно не подходил для постоянного соединения, потому что он создавался как скриптовый язык. Скрипт должен был отработать один раз и почистить все следы своего выполнения. Поэтому создатели особо не заботились об утечках памяти и т.д. В результате было очень обременительно создавать постоянно-живущие процессы, необходимые для websockets. Но в настоящее время PHP очень сильно развивается, разработчики уделяют очень много внимания такому сценарию использования языка. PHP стал производительнее и гораздо надёжнее работает с памятью. Однако, напрямую реализовывать долгоживущий сервис самому всё еще муторно, поэтому лучше всего использовать отличные сторонние фреймворки/библиотеки.

    2. Что можно использовать:
    - Ratchet
    - Swoole / OpenSwoole
    - Workerman

    У каждой из этих асинхронных библиотек/фреймворков есть свои особенности и нюансы. Но это всё очень хорошо описано в их документации, так что просто следуйте тому, что там написано, и не волнуйтесь. Советовать что-то одно не буду, потому что на вкус и цвет все фломастеры разные, и выберете то, что будет отвечать вашим конкретным задачам.
    Ответ написан
  • Может ли браузер дублировать POST запрос?

    Такое обычно происходит, когда запрос кидается в lifecycle-хуках, которые могут сработать много раз (например, updated), либо в watch. И когда у вас что-то ошибочно повторно перерендерится, то может бахнуть второй запрос. Дабл-клик по кнопке, которую вы не выключаете сразу после первого клика также не исключается.

    Насчёт идентификатора вашего ничего не могу сказать, потому что не вижу, где и как вы его генерируете.

    Дебажить, дебажить, и ещё раз дебажить VUE.

    1. Если есть возможность запустить фронтенд на локалке в development environment, установите в браузер плагин Vuejs devtools, и посмотрите поведение компонента, кидающего запросы, может быть там что-то увидите.

    2. Откройте devtools браузера и на вкладке Network и кликните ссылку в колонке Initiator (не знаю, как по-русски, не пользуюсь русским в браузере) у этих повторяющихся запросов. Если будут показаны разные участки кода, значит, где-то еще в коде затерялся такой же запрос.

    3. Самое простое: прямо перед строчкой с вызовом запроса axios (прямо перед запросом, в этой же функции, не где-то вне её, а прямо в предыдущей строчке) напишите банальный console.log("Gotcha!!!!"). Если сообщение в консоли браузера появится дважды, значит, проблема исключительно в логике вашей программы.

    4. Если ваш ID действительно генерируется прямо рядом с вызовом запроса, прямо в той же самой функции (что исключает баг с тем, что в запрос подставляется где-то сохранённый и кэшированный фреймворком ID), и это действительно подлый Chromium повторяет запросы из-за крайне нестабильного коннекта у пользователя, то тогда генерируйте ID не просто рандомом, который всё же может повториться, а сгенерируйте нормальный UUID, вероятность повторения которого ЗНАЧИТЕЛЬНО ниже. При приходе запроса сохраняете этот UUID на короткое время где вам удобнее, и если придёт такой же запрос с таким же UUID, то не обрабатываете его. Этот же UUID вам может помочь и в других аспектах: например, вы можете его использовать как "Correlation ID" данного конкретного запроса. Его можно отражать в логах, передавать в другие сервисы, если у вас их несколько. И тогда вы сможете без проблем отслеживать жизненный цикл каждого конкретного запроса.
    Ответ написан
    6 комментариев
  • Кто должен устанавливать cookie, клиент или сервер?

    1. Клиент - ваш враг! Это единственно-верный подход при разработке web-сервисов. У клиента может быть дырявый древний браузер насквозь пробитый вирусами и вредоносными расширениями. Ваша задача - максимально обезопасить и сервер и бедного юзверя от этой гадости.

    2. Поэтому лучше всего генерировать куку на сервере. И не простую, а минимум:
    • HttpOnly
    • Secure
    • SameSite=lax


    3. Приложите уникальный CSRF-токен, и спите относительно спокойно.

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

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

    Серверное решение без JS более надёжно:

    Реализуем паттерн Post/Redirect/Get (PRG) плюс одноразовый уникальный токен.

    - Допустим у нас форма по адресу "/form".
    <form id="myForm" action="/save-data" method="post">
      <!-- ...поля... -->
      <button type="submit">Отправить</button>
    </form>


    - Когда сервер принимает POST запрос по адресу, по которому была отправлена форма "/save-data", он проверяет валидность данных, и ежели всё верно, то не рисует ответ с успешным успехом прямо по этому адресу, а делает серверный редирект 303 на страницу "/success". Т.е. другой адрес. Почему 303? Потому что такой редирект даёт браузеру понять, что на страницу "/save-data" нет смысла возвращаться и хранить его в истории, ведь 303 нам сказал искать контент по другому адресу.
    - Это решает проблему с клавишей "F5" (обновление страницы). К тому же в истории у нас всё нормально без никакого редиректа.
    - Однако кнопка назад может заставить браузер вернуться на страницу с заполненной формой "/form". И повторная отправка сработает.

    Для решения этой проблемы мы вводим для каждого отображения формы специальный уникальный токен.

    - При загрузке страницы с формой генерируем этот токен на сервере.
    - Сохраняем токен в сессию
    - Рисуем в HTML формы дополнительное невидимое поле, содержащее этот же токен.

    <form id="myForm" action="/save-data" method="post">
      
      <input type="hidden" name="form_token" value="уникальное_значение_12345">
      
      <!-- ...другие поля... -->
      <button type="submit">Отправить</button>
    </form>


    Когда пользователь нажимает кнопку Отправить правильно, без возвратов назад, происходит следующее:

    1. Сервер получает POST запрос с данными формы на "/save-data"
    2. Забираем значение form_token и сравниваем его с сохранённым ранее токеном из сессии.
    3. Если токены совпадают, то немедленно удаляем его из сессии. Это и есть решение.
    4. Делаем редирект на страницу "/success"
    5. Пользователь видит красивую зелёную галочку и сообщение об успешном успехе. Он доволен.

    Если же он вернётся-таки на страницу формы через кнопку Назад, увидит там всё ту же заполненную форму с данными, и подумает, что он не отправил данные, и попробует снова отправить форму, то произойдёт следующее:

    1. Сервер получает POST запрос с данными формы на "/save-data"
    2. Забираем значение form_token и сравниваем его с сохранённым ранее токеном из сессии.
    3. Т.к. токены не совпадают (в сессии токена нет, мы его удалили ранее), то делаем редирект на страницу "/error", где сообщаем пользователю, что он уже отправлял эту форму раньше, и всё в порядке, пусть не переживает.
    4. Пользователь видит сообщение и утирает пот со лба. Он доволен.

    Решение только выглядит сложным. На самом деле оно простейшее.

    Очистку данных формы конечно можно делать, очищая поля формы с помощью Javascript. Но... Зачем?
    Но если надо, то обрабатывайте событие 'pageshow'. Проверяйте, ежели браузер действительно загрузил страницу из bfcache, и очищаете форму. Можно еще и кнопку снова активировать, если задизаблили её раньше.

    window.addEventListener('pageshow', function(event) {
      // event.persisted бывает true, когда страница загружается из bfcache
      if (event.persisted) {
        const form = document.getElementById('myForm');
        if (form) {
          form.reset(); // Сбрасываем все поля формы
          const button = form.querySelector('button[type="submit"]');
          button.disabled = false; // Убедимся, что кнопка снова активна
          console.log('Страница восстановлена из кэша. Форма сброшена.');
        }
      }
    });
    Ответ написан
    Комментировать
  • Symfony 6.4 php 8.4 много сыплется deprecated, есть ли пути решения?

    Если сыплются deprecated, и вы не хотите их совсем отключать, можете для канала deprecation создать отдельный хэндлер в монологе. Если пишете в файлы, то настроить ротацию. И тогда и сами deprecated сохранятся, и основные логи не будут замусорены.
    Ответ написан
    Комментировать
  • Как называется такая вложенность в php?

    Это называется PHP. Потому как PHP изначально создавался как сам себе шаблонизатор HTML. Именно поэтому в коде присутствуют открывающие и закрывающие конструкции "<?php" и "?>"

    Люди, разрабатывавшие PHP, прекрасно понимали, как отвратительно будет выглядеть и читаться код, если они заставят людей писать так, как на вашем скрине. Именно поэтому они придумали совершенно другой синтаксис для условий и циклов, который как раз хорошо подходит для написания шаблонов. Ваш пример можно было бы переписать вот так:

    <?php if ($isSent): ?>
    
        <p>Email sent successfully!</p>
    
    <?php else: ?>
    
    <form method="post" action="<?php echo $_SERVER["PHP_SELF"]; ?>">
        <label for="subject">Тема письма : </label> <br>
        <input type="text" name="subject" size="30"> <br>
    
        <label for="elvismail">Содержание письма : </label> <br>
        <textarea name="elvismail" id="" cols="30" rows="10"></textarea> <br>
    
        <input type="submit" name="submit">
    </form>
    
    <?php endif; ?>


    Погуглите "php endif endfor"
    https://www.php.net/manual/en/control-structures.a...
    Ответ написан
    4 комментария
  • Почему PHP считает int числа после математических операций как float?

    Все коллеги, ответившие выше, правы. float заразен. Всё, чего он касается в математических выражениях, превращается во float.

    Я лишь хотел посоветовать эдакий костыльный подход, который позволит вам не так сильно напрягаться, вспоминая, как же эти динамические языки приводят одно к другому.

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

    На наше счастье в PHP завезли хоть какую-то типизацию. К сожалению, на данный момент она касается только аргументов и возвращаемых значений функций, а так же свойств и методов классов. Явно типизировать обычную переменную не получится.

    Попробуем использовать хотя бы то, что нам дали. Для этого будем придерживаться простого правила:

    все вычисления всегда выносить в отдельные функции, а эти функции всегда типизировать по-максимуму.

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

    <?php
    
    $sum = 400;
    
    // Было
    $all = $sum * (55 / 100);
    var_dump($all); // На выходе float(220.00000000000003)
    
    // Стало
    $all2 = calculateAll($sum);
    var_dump($all2); // На выходе int(220)
    
    function calculateAll(int $sum): int
    {
        return $sum * (55 / 100);
    }


    Вывод
    float(220.00000000000003)
    PHP Deprecated:  Implicit conversion from float 220.00000000000003 to int loses precision in /Users/vitiok78/Downloads/float.php on line 12
    
    Deprecated: Implicit conversion from float 220.00000000000003 to int loses precision in /Users/vitiok78/Downloads/float.php on line 12
    int(220)
     
    Ответ написан
  • Как отследить кнопку "назад" на телефонах?

    Опишу только принцип, реализацию уже сделаете сами, либо попросите AI.

    Кнопка "назад" работает просто: переводит браузер на предыдущий урл.

    Это можно использовать. Вы же, наверняка, используете history API в вашем приложении.
    Так вот, при открытии модального окна добавляйте хэш к адресу в history.

    https://example.com/page // окна нет
    https://example.com/page#modal1 // окно открыто


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

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

    Решение уважаемого historydev полностью работоспособно, к нему претензий нет никаких, но можно предложить и альтернативу при помощи cloneNode(true) (глубокое клонирование объекта DOM).
    таким образом переменная html у нас остаётся объектом DOM, и её можно далее использовать по коду.
    - var html = e.target.parentNode.querySelector('.firmware-window');
    + var html = e.target.parentNode.querySelector('.firmware-window').cloneNode(true);
    			$('.modal-wrapper').attr('class', 'modal-wrapper').html(html);
    			html.classList.remove('hiden');


    cloneNode намного эффективнее, чем преобразование элемента в текст, а потом из текста в элемент, если исользовать подход с innerHTML, и если бы это был какой-то цикл с очень большим количеством элементов, то разница почти в 2 раза была бы видна невооружённым взглядом.
    Ответ написан
    Комментировать
  • Чем frontend разработчик занят на реальных проектах?

    С резким ростом популярности React Server Components и Next.js в последнее время происходит некий сдвиг в понимании, что такое фронтенд.
    BFF уже почти становится неотъемлемой частью "фронтенда", и становится обременительно разделять браузер и сервер на разные команды.
    На Западе, вообще, уже очень давно и макетами, и вёрсткой, и анимациями очень часто занимается один человек - дизайнер, фронтендеры занимаются связкой браузер + BFF, а бэкендеры занимаются более сложной бизнес-логикой.
    К тому же, джуниорам зачастую дают те задачи, которыми сами не хотят заниматься, и на что нет времени. Т.е. это что-то занудное, работа с legacy, передвижение кнопки на 5px влево и т.д. Крайне редко джуниорам дают интересные творческие задачи. Не факт, что вам на новом месте не дадут такие же неинтересные задачи.
    Вы можете либо молча сильно стараться в надежде, что вам потом дадут что-то интересное, заметив ваше рвение, либо, лучше всего, пообщаться по-человечески с коллегами и начальством, объяснив, что вы рветесь в бой, а вас в тылу держат. Попросите рассказать об их планах на ваш счёт.
    Не исключено, что у вас как раз хорошо получается "Настройка тестов, CI/CD, OLAP CUBE, оптимизация запросов к БД", и поэтому вам эти задачи и дают)
    В общем, человеческое общение с коллегами очень часто решает проблемы.
    Если же вы к ним придёте с открытой душой, а вас токсично отошьют, вот тогда подумайте о смене работы.
    Ответ написан
    7 комментариев
  • Установлена CMS Drupal версия 7.60 нужно ли обновлять?

    Поддержка Drupal 7 закончилась 5 января этого года. Без обновлений безопасности сайт может стать уязвимым.
    Варианты:
    - Купить у них расширенную поддержку.
    - Обновить на текущую версию. Но!!! Версии после 7-й перешли на Symfony в качестве базы. Они даже шаблонизатор на Twig перевели. Это означает, что миграция сайта с Drupal 7 на более свежую версию становится такой попоболью, что зачастую сайт проще полностью переписать, чем мучиться. Контент можно экспортировать со старого и импортировать в новый. У них на сайте есть какие-то инструкции и модули, которые могут с этим помочь. Но это крайне серьезная, долгая и ответственная задача
    Ответ написан
  • Какой посоветуете фреймворк (с роутингом, orm и мидлваре) для Golang?

    Не рекомендую даже пробовать.
    В Go не принято использовать такое. Какие-то люди пишут и ORM (например Gorm), и различные роутеры, но это пользуется всё меньшей популярностью. В результате вы не получите много информации, когда вам понадобится решать какие-то проблемы с этими монстрами.
    Я когда-то приходил в Go с навыками Symfony + Doctrine ORM, и тоже не понимал, как они без этого живут. И в результате понял, что в подавляющем большинстве проектов эти монстры просто не нужны и становятся обузой, когда проект развивается. Да, поначалу всё хорошо и быстро, а когда в проект приходят новые сложные фичи, начинается борьба не только с этими фичами, но и с самим фреймворком, и, особенно, с ORM. В результате получается Франкенштейн, пляшущий на костылях. Всё это еле ворочается, а Доктрина выплёвывает такие запросы, что их даже читать страшно.

    P.S. Если вот всё же хотите пойти против системы и пользоваться наворотами, то можно рассмотреть связку Gin + Gorm
    Ответ написан
    3 комментария
  • На каком слое принято обрабатывать ошибки?

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

    https://www.youtube.com/live/p9XiOOU52Qw?si=CO1Sqx...
    Ответ написан
    2 комментария
  • Почему GORM создает пустую таблицу?

    Сделайте типы object и reference экспортируемыми. Иначе у Gorm будут проблемы с рефлексией, и он не увидит поля.
    Ответ написан
    Комментировать
  • Как сделать правильную табуляцию в html?

    Ситуация следующая: нет никаких официальных стандартов оформления HTML. Это в документации HTML нигде не прописано. Потому что для экономии трафика вообще нежелательно, чтобы в передаваемом body были лишние символы, не несущие никакой функциональности. Лишние пробелы между тегами вообще не учитываются браузером.

    Исходя из этого можно заключить, что любые style guides, которых придерживаются программисты, - это просто соглашение, действующее в рамках какой-то одной организации либо сообщества. Вы устраиваетесь на работу и там вам дадут документ либо конфигурационный файл, в котором будут перечислены все правила, которых придерживаются в данной организации: 2, 4, 8 пробелов, символ табуляции, полное отсутствие пробелов между тегами. И вот этих правил надо придерживаться.

    Таким образом, в вашей ситуации случилось одно из двух:
    • преподаватель изначально дал вам список всех правил, но вы просто забыли об этом либо пропустили это занятие. Тогда преподаватель прав, и вам надо уточнить у него весь этот список правил и сказать, что больше так не будете.
    • преподаватель не дал вам этот список, поэтому, если у вас во всём проекте одинаковое количество пробелов в отступах в HTML, то правы вы, и вы можете потребовать от преподавателя предоставить вам список правил, которые он требует, и вежливо пояснить ему, что он не прав, критикуя вас за выбор количества пробелов без предварительного предоставления подробных style guides.
    Ответ написан
  • Что чаще всего пишут на Go?

    На Go мало фреймворков, потому что у Go просто невероятная стандартная библиотека. Например, с недавним обновлением библиотеки http я тупо не вижу смысла в сторонних роутерах. Не знаю почему, какая у языка магия, но мне почти всегда хочется написать своё решение, подходящее именно для этой конкретной задачи, чем лепить монстра из внешних зависимостей.

    Основной домен языка - это Web. Это и полноценные REST (и не только) API, это и отдельные узлы систем. А я, например, стал писать на Go и фронтенд, познакомившись с замечательной JavaScript библиотекой HTMX.

    Многие люди пишут на Go консольные приложения. Я часто всякие утилитки пишу вместо того, чтобы мучиться с корявым синтаксисом bash, от которого меня тошнит.

    Кстати, Докер и Кубернетес написаны на Go, но это, скорей исключение.

    Есть даже пакеты, позволяющие писать десктопные приложения.

    На Go отлично писать всяких ботов.
    Ответ написан
    2 комментария
  • Почему не запускается PhpStorm?

    Самый очевидный способ:
    - удалите PhpStorm
    - удалите все версии Java
    - установите PhpStorm
    Ответ написан
    3 комментария
  • Как из строки с путём получить элемент массива?

    <?php
    function getArrayValueByPath($array, $path, $separator = "/")
    {
        // Разбиваем путь на ключи
        $keys = explode($separator, $path);
        // Текущий уровень массива - начинаем с корня
        $current = $array;
    
        foreach ($keys as $key) {
            // Если ключа нет в массиве, то выбрасываем исключение
            if (!isset($current[$key])) {
                throw new \Exception(
                    "Ключ $key не найден в массиве по адресу '$path'"
                );
            }
            // Переходим к следующему уровню вложенности массива
            $current = $current[$key];
        }
    
        // Возвращаем значение по заданному пути
        return $current;
    }
    
    // Использование функции:
    
    $arr = [
        "k1" => [
            "k2" => [
                "k3" => [
                    "k4" => "v",
                ],
            ],
        ],
    ];
    
    $result = getArrayValueByPath($arr, "k1/k2/k3");
    
    var_dump($result);
    
    /** Результат выполнения:
    
    array(1) {
      ["k4"]=>
      string(1) "v"
    }
    
    */
    Ответ написан
    Комментировать
  • Как научиться декомпозиции в ООП?

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

    Есть куча книжек, роликов на ютубчике и т.д.
    Но можно начать как раз с ChatGPT.
    Задайте ему вот такую задачку:

    Объясни принципы SOLID. Используй примеры на PHP. Объясняй как десятилетнему ребёнку


    Не стесняйтесь упоминания ребенка в сложных вопросах. Он тогда очень красочно и очень понятно описывает. Такое лучше входит в мозг.
    Ответ написан
    Комментировать