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

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

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

    Если под "сессией" имелось в виду общее хранилище для всех пользователей, то оно называется "база данных". И в этом смысле "БД не предлагать" выглядит беспочвенным капризом. Как правильно заметил N в комментарии, такое заявление звучит как "Как кушать суп? Ложку не предлагать."
    Такие заявления надо всегда подробно обосновывать. И в этом случае вам либо действительно подскажут, как обойтись без БД, либо объяснят, что это просто блажь.

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Заголовок - это очень важная часть вопроса. Над ним надо очень вдумчиво работать
    Чтобы он не вводил отвечающих в заблуждение, и чтобы ответы оказались вам самому полезны.

    Если говорить об изучении с нуля, как можно понять из заголовка, то я рекомендую книгу Jon Duckett, PHP&HTML. Но её, вроде бы, не переводили на русский. Из доступного - Котеров, но она конечно уже подустарела. Хотя там хорошо даются такие основы, как НТТР.

    Но в вашем случае вопрос об изучении РНР явно не идёт. А скорее о повышении квалификации.
    Плюс вопрос "Какую версию учить" тоже не стоит - у седьмой версии поддержка кончается осенью. Но в целом различия между версиями в РНР не настолько принципиальны, чтобы можно было учить какую-то конкретную "версию". Чисто синтаксические нововведения в языке лучше всего изучать по разделам "Новая функциональность" каждой версии отсюда https://www.php.net/manual/ru/appendices.php

    Но начиная с определенного уровня изучение РНР уже перестаёт быть изучением РНР, а скорее программирования в целом - ООП, паттернов проектирования и т.д. Тут уже книжки по РНР не нужны, сами пхпшники учат это по явовским учебникам - Фаулера, Мартина и пр.
    Хотя конечно к зарабатыванию денех на PHP + Битрикс это всё не имеет уже ни малейшего отношения.
    Ответ написан
    Комментировать
  • Как обратиться к элементу масива php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я бы сначала трансформировал массив в словарь
    $rates = [];
    foreach ($array["exchangeRate"] as $row) {
        $rates[$row['currency']] = $row;
    }

    и потом просто обращался по индексу,
    $currency = "BYN";
    echo $rates[$currency]["saleRateNB"];
    Ответ написан
    Комментировать
  • Как реализовать добавление записи в связанные таблицы MySQL?

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

    function textlog($connect, $chat_id, $text, $user_id) {
        if (!$chat_id) {
            return false;
        }
        $sql = "INSERT INTO textlog (chat_id, phone, user_id) VALUES (?,?,?)";
        $stmt = $connect->prepare($sql);
        $stmt->bind_param("sss",$chat_id, $text, $user_id);
        $stmt->execute();
        return true;
    }
    Ответ написан
    1 комментарий
  • Получить значение ключа из многомерного массива?

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

    Дальше читаем:
    Управляющая конструкция foreach существует специально для массивов. Она предоставляет возможность легко пройтись по массиву.

    Переходим по ссылке и снова читаем:
    foreach (iterable_expression as $value)
        statement
    foreach (iterable_expression as $key => $value)
        statement
    Первый цикл перебирает массив, задаваемый с помощью iterable_expression. На каждой итерации значение текущего элемента присваивается переменной $value.

    Второй цикл дополнительно присвоит ключ текущего элемента переменной $key на каждой итерации.
    Ответ написан
    Комментировать
  • Как заставить PHP обрабатывать строку, игнорируя управляющие последовательности?

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

    Вопрос действительно "тупой". И причём путаница тут уже в самом начале.
    Утверждение
    Если я не создаю строковую переменную как литерал в коде, а беру из файла или GET-запроса и т. д., то функциями в PHP она обрабатывается как строка в двойных кавычках.

    является неверным.

    Надо всегда проверять свои предположения на практике.
    То есть на самом деле вся проблема сводится к тому, что ещё до попадания в переменную $_GET['text'], текст был сконвертирован. В случае же, если в адресной строке будет передано значение \xbc, то оно и будет в переменной и прекрасно запишется в базу

    Есть вероятность, что в переменную приезжает один символ, но в кодировке utf-8. И strlen честно показывает длину в несколько байт, что добавляет путаницы ещё больше.
    Ответ написан
    Комментировать
  • Правильно ли реализован класс для работы с базой данных по принципу SOLID?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Во-первых, это никакой не DatabaseManager , а CRUDManager. Работа с БД далеко не ограничивается этими 4 примитивными функциями.

    Отсюда мы делаем логичный вывод, что соединение с БД никаким местом не должно создаваться в конструкторе менеджера крудов. А должно точно так же передаваться в него в качестве зависимости. Это может быть либо ванильная ПДО, либо инстанс реального MySQLDatabase (но поскольку мы пока не знаем, как он должен выглядеть, то лучше остановиться на PDO).

    Сам по себе DatabaseManager выглядит избыточным. Непонятно, зачем он нужен, если любой потребитель DatabaseManager-а может просто написать
    public function __construct(CRUDInterface $crud) {
    }

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

    В-четвёртых, хоть это и не относится напрямую к теме SOLID, но для меня является очень важным: собственно, реализация методов CRUD-а. Что в них передаётся? Откуда берутся названия таблиц, полей? Передаются в параметрах методов? Это прямая дорога к SQL инъекции, не говоря уже о нарушении инкапсуляции. Поэтому, отвечая на вопрос "Как вы реализуете работу с базой данных", лично я всё больше в последнее время от развесистых ORM-ов склоняюсь к простым TableGateway-ам. Да, кода писать больше, но он строже и понятнее. И не встаёт колом в нестандартных ситуациях. Тем более что приведённый пример кода как раз очень и похож на этот паттерн. То есть
    abstract class MysqlTableGateway implements CrudInterface
    {
        protected $db;
        protected $table;
        protected $fields;
        protected $primary = 'id';
    
        public function __construct(\PDO $db)
        {
            $this->db = $db;
        }
        public function read($id): ?array
        {
            $stmt = $this->db->prepare("SELECT * FROM `$this->table` WHERE `$this->primary`=?");
            $stmt->execute([$id]);
            return $stmt->fetch();
        }
         // ну и так далее
    }

    И дальше уже классы по работе с отдельными табличками наследовать от него,
    final class UserGateway extends MysqlTableGateway {
        protected $table = 'users';
        protected $fields = ['email', 'password','phone'];
    }

    Соответственно, если мы захотим перейти с мускуля на какой-нибудь редис с джейсоном внутре, то надо будет создать новый абстрактный класс с тем же интерфейсом, и от него отнаследовать реализации. Соответственно, в интерфейсе надо нормально прописать входные и выходные параметры:
    interface CRUDInterface {
        public function create(array $data):int;
        public function read(int $id):?array;
        public function update(array $data);
        public function delete(int $id);
    }

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

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

    $f = fopen('/var/www/site.ru/data/logs/site.ru.error.log','r');
    while (!feof($f))
    {
      $line = fgets($f);
      $st_strpos = "Nemesida";
      $pos = strpos($line, $st_strpos);
    
            if ($pos !== false) {		
        // тут как раз строка унас уже ЕСТЬ! в переменной $line
      }
    }
    Ответ написан
    Комментировать
  • Как исправить код работы с шаблонами?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Интересно, когда люди научатся читать документацию на функции, которые используют.
    Ну или хотя бы поинтересуются, что по-английски означает слово "once" ...
    Ответ написан
    3 комментария
  • Как сделать файл авто перескачиваемым после его обновления?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    самое тупое решение
    <script src="/path/file.js?t=<?= filemtime($_SERVER['DOCUMENT_ROOT'].'/path/file.js') ?>">
    Ответ написан
    9 комментариев
  • Что лучще использовать для api call JS или PHP?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    если для вызова не нужна никакая авторизация или токены, то разумеется на JS
    во всех остальных случаях разумеется на РНР
    Ответ написан
    Комментировать
  • Как продолжить цепь запросов в php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если отбросить всю не относящуюся к вопросу чепуху, типа каких-то "внутренних запросов"(?!), то ответ сводится цепочке вызовов.
    Ответ написан
    Комментировать
  • Почему выдает ошибку при загрузке фотографии?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    То, что папка images находится в папке с product.php, не имеет вообще никакого значения.
    product.php не имеет отношения к работе веб-сервера. из неё просто читается код класса.

    При этом путь images/ является относительным. То есть, в зависимости от точки входа может вести в совершенно разные места.
    Именно поэтому все пути всегда должны быть абсолютными. Пусть даже и с помощью костыля __DIR__
    Ответ написан
    2 комментария
  • Почему данные заказа не отправляются в базу данных?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что вы вообще никак не отреагировали на те ответы, которые вам дали в прошлый раз на этот же самый вопрос.
    Вам написали, как правильно выполнять запросы. Вы это сделали?
    Вам написали, какие действия выполнять, если код не работает. Вы их выполнили?
    Вы так и планируете ходить на Хабр каждый раз, когда код не работает? Вот прямо серьёзно? Это, по-вашему, именно то, чем занимаются программисты?

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

    К тому что написано в предыдущем ответе надо добавить только одно: перед
    new mysqli(...);
    надо всегда писать
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    чтобы база данных сама сообщала, почему не может выполнить запрос. Если дело именно в нём.
    Ответ написан
  • Как вставить данные в запрос?

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

    В любом случае, public $query убрать, вместо этого добавить private $db, и в конструктор, соответственно, такой же параметр
    public function addProduct(){
        $query = 'INSERT INTO products (title, price, description, category, image, active) VALUES (?,?,?,?,?,?)';
        $stmt = $this->db->prepare($query);
        $stmt->bind_param("ssssss", $this->title, $this->price, $this->description, $this->category, $this->image, $this->$active);
        $stmt->execute();
    }
    Ответ написан
  • Как правильно отправить данные из формы POST-запросом и записать их в бд?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Главная беда задавателей вопросов на форуме в том, что они всегда задают совершенно не тот вопрос, который их интересует.
    Судя по коду, автор прекрасно знает, как "отправить данные из формы POST-запросом и записать их в бд". Спрашивается - зачем задавать этот вопрос? Загадка.

    Ведь настоящий вопрос звучит "Я написал код, который отправить данные из формы POST-запросом и записать их в бд, но он не работает. Как понять, по какой причине он не работает, чтобы я мог это исправить?" - ну разве не так?

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

    Для mysqli это делается командой
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

    Которая пишется перед коннектом.
    Для РНР всё стандартно - error_reporting всегда в E_ALL плюс display_errors в 1 на домашнем компьютере.

    И после этого РНР сам всё расскажет и покажет. И где опечатка в запросе, и любые другие ошибки.
    Ответ написан
    Комментировать
  • Почему не воводятся данные из БД?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что никто никогда не читает документацию.
    В которой написано, например - какой массив возвращает fetchAll(). И можно ли из него получить что-то в виде $user_data['id'].
    А ещё в мануале написано, какая на самом деле функция подойдёт в данном случае.

    Также, там написано, что делает функция fetchColumn(). Которая, во-первых, делает совсем не то что думает автор кода, а во-вторых, даже если бы и делала, то всё равно здесь никаким боком не нужна.

    И я уже не говорю, что в мануале написано темно-красным по светло-красному, что MD5 нельзя использовать для хэширования паролей.
    Ответ написан
    6 комментариев
  • Resource: что из себя представляю потоки в php?

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

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

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

    Вот даже здесь, поскольку fopen работает поверх абстракции, нельзя говорить о едином подходе.
    Если у нас самый простой случай - локальный файл - то РНР оборачивает функции для работы с файлами языка С в свою собственную абстракцию. Но ниже - на уровне этих самых функций языка С - никаких потоков нет. Есть обращение к функциям операционной системы, которые просто позволяют прочитать выбранный кусок файла.
    Тут никаких вопросов нет, всё честно - если мы прочитали из файла 5 килобайт - значит потратили ровно 5 килобайт памяти.
    Но работаем мы с файлом не считывая его весь в память не потому что поток, а потому что так устроена файловая система. А поток этой возможностью только пользуется.

    Если же мы открываем не файл, а URL, то РНР начинает извращаться, пытаясь предоставить те же самые инструменты, какие мы используем для работы с файлами, для доступа к ресурсам совершенно другого типа.
    И здесь возможны нюансы. Я не знаю, как реализован HTTP wrapper, но в теории HTTP позволяет чтение произвольного объема данных через заголовок Range:. То есть РНР вполне может читать и из НТТР кусками, а не целиком.

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

    А упомянутый в вопросе PSR-7 вообще никакого отношения к потокам в РНР не имеет. Это совершенно отдельная реализация принципа потоков, которая не имеет отношения к потокам в РНР.
    Ответ написан
    Комментировать
  • Как сделать так, что бы при пустом запросе в базу выводились ВСЕ значения?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    есть немного замороченный способ, но в целом он требует куда меньше кода
    WHERE (account_id=? OR ? is null)  AND (priority=? OR  ? is null)

    Чтобы его использовать, надо всего лишь передавать каждую переменную в запрос по два раза (и следить, чтобы пустые переменные содержали null).

    Другим вариантом является условная сборка запроса.
    Для этого мы собираем условия и переменные для них в массивы

    $conditions = [];
    $parameters = [];
    if ($account_id)
    {
        $conditions[] = 'account_id=?';
        $parameters[] = $account_id;
    }
    if ($priority )
    {
        $conditions[] = 'priority =?';
        $parameters[] = $priority;
    }

    собираем из условий запрос и выполняем его, привязывая все переменные разом
    тут из сложного будет привязка переменных из массива, но благодаря оператору распаковки аргументов это не так уж и сложно.
    if ($parameters)
    {
        $sql .= " WHERE ".implode(" AND ", $conditions);    
        $stmt = $db->prepare($sql);
        $stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
        $stmt->execute();
        $result = $stmt->get_result();
    } else {
        $restult = $db->query($sql);
    }
    Ответ написан
    3 комментария
  • Как вытащить данные из stmt?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    вместо store_result(); надо писать get_result();
    этот метод даст вам привычный ресурс, из которого уже можно получить данные обычным способом
    $stmt = $link->prepare("SELECT * FROM users WHERE id=?");
    $stmt->bind_param('i', $value);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    Ответ написан
    5 комментариев