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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я думаю, имелось в виду что-то вроде этого
    function regis($pdo, $login, $pass ): bool
    {
        $res = $pdo->prepare("INSERT INTO users(login, password) VALUES (:login,:pass)");
        $res->execute(["login" => $login, "pass" => $pass]);
        return true;
    }


    На будущее: функция должна всегда делать что-то одно. Все проверки, работа с НТТР, сессии - должно быть снаружи.
    Ответ написан
    2 комментария
  • Как узнать размер файла на PHP?

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

    В данном случае скорее всего подойдёт
    $file = $_SERVER['DOCUMENT_ROOT']."/files/file.png";
    echo filesize($file);


    Если нет - надо сначала разобраться, как этот код вызывается и где на самом деле лежит файл.
    И обязательно почитать про абсолютные и относительные пути
    Ответ написан
    1 комментарий
  • Как получить данные с БД за Н количество дней?

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

    r.date_added > curdate() - interval 30 day

    И на будущее, никогда не использовать date() в условии.
    Ответ написан
    1 комментарий
  • Fatal error: Allowed memory size. Как сделать запрос SQL чтобы не получать ошибку?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Читаем https://www.php.net/manual/ru/mysqlinfo.concepts.b...
    и делаем свой запрос небуферизованным.
    Ну и разумеется читаем все 300 офигиллиардов строк не сразу в массив, а обрабатываем по одной.
    Ответ написан
    6 комментариев
  • Как работать с сырыми результатами SELECT MySQL CLI в PHP CLI?

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

    Ну и всякие мелочи, типа -N чтобы получить сразу значение, если запрос возвращает одно поле одной строки, group_concat() если надо получить значения через запятую, и прочее
    Ответ написан
    1 комментарий
  • Как обновлять данные каждые 24 часа в MySQL?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Никак не увеличивать, при запросе добавлять к исходному значению число прошедших дней
    Ответ написан
    Комментировать
  • Дают ли выигрыш ссылки на элементы массива и на поля объектов в PHP?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    С точки зрения памяти не даёт, потому что в РНР и так очень оптимальное управление памятью.
    В частности, при присвоении значений переменным применяется принцип copy-on-write. Объекты же и так всегда копируются по ссылке.

    С точки зрения "вычислять адрес промежуточного объекта" - я никогда не слышал о таких проблемах. Судя по всему, это явно не является узким местом для динамически интерпретируемого языка.
    В любом случае, учитывая copy-on-write, исходно это снова будет опять ссылка.

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

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

    Чтобы узнать, почему РНР код не работает, надо прочитать сообщение об ошибке РНР. В данном случае мы его не видим, а видим только сообщение веб-сервера о том, что РНР завершился с ошибкой.
    Чтобы увидеть ошибку РНР, надо сделать две вещи:
    1. Убедиться, что РНР генерирует сообщения об ошибках. Для этого во-первых, всегда должен стоять максимальный уровень генерации ошибок, error_reporting(E_ALL);, и во-вторых, программист не должен сам себе стрелять в ногу, насильно подавляя сообщения об ошибках. И никогда не использовать оператор подавления ошибок, @.
    2. На время разработки поставить режим вывода ошибок на экран, ini_set('display_errors', 1);. На боевом сервере, соответственно, этот режим должен быть выключен, а логирование наоборот - включено.

    И только после получения сообщения об ошибке можно уже приходить на Хабр с вопросом. Но сначала предварительно погуглить, потому что все вопросы уже задавали по миллиону раз.
    В данном случае вероятной причиной может быть нестандартный порт mysql. Но опять же, гадать нет смысла, надо сначала увидеть сообщение об ошибке.

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

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

    Исходя из здравого смысла, в данном случае (когда из потенциально большого массива значений надо выбрать несколько случайных) чтобы избежать повторений, надо запоминать все уже использованные значения. Для этого подойдёт массив.
    А для проверки идеально подойдет цикл do while, это редкий случай его использования. просто генерируем новые ключи до тех пор, пока не найдётся ещё не использованный.
    do {
        $key = rand(2,$count);
    } while (array_key_exists($key,$exists));
    $exists[$key] = true;


    Важно не забыть определить пустой массив $exists перед началом цикла.

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

    Если же количество требуемых случайных значений сравнимо с количеством всех данных, то удобнее будет сначала сгенерировать массив всех ключей и перемешать его
    $keys = range(2, $count);
    shuffle($keys);
    for ($a=0; $a < 10; $a++) {
        $key = $keys[$i];
    Ответ написан
    7 комментариев
  • Как улучшить код, который проверяет наличие элемента в массиве и его значение?

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

    И ответ зависит от двух вводных, которые мы не знаем:
    1. по какой причине элемент 'test' может отсутствовать
    2. какие ещё значения могут быть у $arr['test']

    Если совсем всё равно на всё и пишем говнокод-стайл лишь бы покороче, то, как правильно написано в соседнем ответе - empty().

    Если элемент обязательно должен присутствовать, то либо убираем проверку на isset совсем, либо - если это интерактивное приложение - выносим отдельно, и при отсутствии элемента сообщаем об ошибке. Пусть даже и тупо 400 кодом.

    Если у $arr['test'] не могут быть другие значения, кроме true, то тоже проверить, и выбросить ошибку, если значение какое-то другое.
    Ответ написан
    Комментировать
  • Что именно делает этот код?

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

    По факту это такой магический геттер на стероидах.
    Отрезает от имени метода первые три буквы и ищет свойство с получившимся именем.
    Свойства добавляются в класс в конструкторе через массив.

    Если свойство не найдено, ищет в массиве имя класса, объект которого надо создать и вернуть.
    Для этого зачем-то меняет регистр с camelCase на snake_case и ищет элемент массива с таким именем по вышеприведённой карте классов. То есть getForwardFrom превращается в forward_from, и по этому индексу возвращается имя класса. почему нельзя было сразу написать в том же регистре - загадка

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

    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 комментария