Задать вопрос
Ответы пользователя по тегу PHP
  • Почему mysqli_query всегда возвращает false?

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

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Надо добавить метод getImages($num=2) чтобы она принимала аргументом количество картинок и возвращала массив.
    И в шаблоне можно будет сделать foreach(). Только дергать базу два раза некрасиво, лучше сначала получить в переменную, а потом ее использовать

    <?php if ($images = $product_1->getImages()) : ?>
    <?php foreach ($images as $img): ?>
        <img src="/media/uploads/small/small-<?= $img ?>" alt="<?= $product_1->prname ?>" title="Перейти в товар - <?= $product_1->prname ?>" />
    <?php endforeach ?>
    <?php else : ?>
      <img src="/media/uploads/nofoto.jpg" alt="Нет фото на товаре" title="Нет фото" />
    <?php endif; ?>
    Ответ написан
  • Проблема с переменной php на онлайн серверы, Можно как нибудь исправить?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Насколько я помню по прошлому вопросу, для $allonline надо просто перед циклом написать
    $allonline = 0;

    А для $serversonline надо самому смотреть - что это за переменная, откуда она берется и почему у неё нет значения. Ну в смысле код надо не только бодро строчить, но иногда и читать. На предмет имеет ли вообще смысл то, что мы написали. В частности, есть ли у нас переменная, к которой мы пытаемся обратиться.
    Ответ написан
    1 комментарий
  • Почему fetch() возвращает bool?

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

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

    // перед коннектом говорим mysqli чтобы сообщала об ошибках сама, 
    // чтобы не проверять каждую команду вручную
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    
    // и дальше просто
    $stmt = $connection->prepare("SELECT * FROM users WHERE email = ?");
    $stmt->bind_param("s", $email);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    $hashed_password = $row["password"];
    if (password_verify($password, $hashed_password)) 
    {            
          echo "Вы успешно залогинились";
    }
    Ответ написан
    Комментировать
  • Как посчитать символы после точки и до единицы?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Самый тупой вариант: strpos($num, '1')-2;
    Ответ написан
    1 комментарий
  • Скачка файлов на сервер с удаленного хоста. Как передать параметр из php-скрипта в wget?

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

    Решение смешной проблемы в текущем коде - надо всего лишь использовать двойные кавычки вместо одинарных.
    $fileD = escapeshellarg("https://domain.zone/files/file".date("Ymd").".zip");
    exec ("wget -O todayfile.zip $fileD");

    Для решения же исходной задачи, разумеется, не нужен никакой РНР. Использовать для этих целей РНР - это все равно что сначала завернуть котлету в целлофановый пакет, а потом её есть. Ну ведь wget - это уже шелловая команда, и запускать её надо напрямую.

    /usr/bin/wget -O /path/todayfile.zip "https://domain.zone/files/file$(date '+%Y%m%d').zip"
    Ответ написан
    3 комментария
  • Почему при экспорте средствами crm в файле базы mysql теряются кавычки?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если отбросить все фантастические версии, типа различий между операционными системами Centos и Ubuntu, то ошибка Duplicate entry '1' for key 'cb_tmp_acc_buttons.PRIMARY' при явном указании значения автоинкрементного поля в запросе может быть вызвана двумя причинами:
    1. в дампе дублируются значения id
    2. после установки БД уже заполнена какими-то значениями.

    Оба варианта легко проверить и исправить. В первом случае обращаться к авторам программы или поправить руками, во втором - сначала очистить базу.

    С кавычками же - это однозначно к авторам этой кривой программы.

    Ну и самое главное - нет ни одной настройки, которая одни строки обрамляет в кавычки, а другиие - нет.
    Ответ написан
  • Как округлить round в меньшую сторону c одним знаком после запятой?

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

    floor(758.66318000*10)/10;

    Так же, универсальное решение приведено в пользовательских комментариях к функции round() (я, правда, позволил себе его немного подредактировать):

    function round_down($number, int $precision = 2)
    {
        if  ($precision === 0) {
            return floor($number);
        }
        $fig = pow(10, $precision);
        return round(floor($number * $fig) / $fig, $precision);
    }

    (round() в конце на всякий случай, если вдруг деление вернет не 8, а 7.9999999, как это бывает с дробными числами)
    Ответ написан
    Комментировать
  • Как объединить два файла на php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Правило номер 1: если у вас есть какая-то завиральная идея, типа "а решите мне вот такую-то примитивную стандартную задачу, но только вот с такими, такими и такими ограничениями", необходимо аргументировать свою задачу. То есть объяснять причины, которые привели вас к такой постановке вопроса.
    Ответ написан
  • Почему не работает команда в exec(), но работает, если просто ввести ее в консоли вручную?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если при выполнении exec() возникает ошибка, то она выводится в stderr.
    Надо просто прочитать её, там будет написано, почему не работает.
    В частности, чтобы получать весь вывод кроновских команд на почту, в том числе и ошибки, надо написать в начале крон файла MAILTO=свойемейл

    Если есть проблемы с чтением stderr, то можно добавить перенаправление в stdout, записать его в переменную и дальше уже направлять по своему усмотрению
    $out = exec('cd /path && mysql -u root < "/path/my-sql.sql" 2>&1');
    log_error($out);
    Ответ написан
    Комментировать
  • Почему биндить в PDO надо обязательно переменную?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ну вообще-то в сообщении об ошибке всё сказано. C bindParam можно использовать только переменные. Потому что биндинг идёт по ссылке (by reference). А на строку, вписанную прямо в коде, ссылку не поставишь. В этом случае надо использовать другой метод
    $b=$pdo->prepare(" INSERT INTO `main` SET tel=:tel");
    $b->bindValue(":tel", '79998887766');

    или вообще передавать данные сразу в execute():
    $pdo->prepare(" INSERT INTO `main` SET tel=:tel")->execute(["tel" => '79998887766']);

    и всё будет работать
    Ответ написан
    3 комментария
  • Как выполнить авторизацию в аккаунта при помощи RedBeanPHP?

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

    Ну ОК, давайте учиться.

    Главное в программировании - это делать всё по порядку.

    У вас в текущей задаче участвует примерно миллион разных действий: html форма, код, который получает из неё данные, база данных, код, который ищет данные из формы в базе.
    Если вы ещё не освоились со всеми этими элементами, то не надо их писать все подряд.
    Надо делать по очереди, проверяя каждый этап.
    И вопрос задавать не про весь код целиком, про который вам никто никогда не скажет, почему он не работает, а про конкретный этап.

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

    Если написанный руками емейл находит, а пришедший из формы нет, то надо сделать что?
    Правильно - посмотреть на него глазками. А похож ли он на тот который руками написан? Если похож, то снова urlencode. Если не похож - то разбираться со своей формой.

    Если всё равно не работает, то надо исключить другие посторонние факторы, например библиотеки, особенно такие кривые, как redbean. И отлаживаться на чистом PDO.

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

    Отдельно хочу заметить, что все описанные действия может сделать только сам программист. Обращаться за ними к посторонним людям бессмысленно. У них нету вашей базы данных, вашей формы, вашего кода. Все эти вещи можно сделать только самостоятельно. И именно это и является программированием. А не вот это вот "всё указываю верно".
    Ответ написан
    4 комментария
  • Может ли такой php код считается сделанным по паттерну MVC?

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

    "index.php, который возвращает в браузер разметку (картинки, формы, ссылки и другой HTML)" не имеет ничего общего с View. В клиент-серверной архитектуре в принципе невозможно реализовать десктопный извод MVC (ну кроме разве что SPA, но здесь явно не этот случай).
    В данном случае вообще непонятно, как это работает, поскольку в любом веб-приложении "инфа приходит" не только, и не столько от пользователя, сколько наоборот - с сервера.
    Вам не приходило в голову, что будет ваша система, если она должна будет по команде отобразить список юзеров? А откуда "view" возьмёт его?

    "Всё это передается actions.php, файл который решает, какие функции из файла functions.php" - это винегрет из роутера, контроллеров и модели.
    "(действие может быть сложным)" означает, что у вас классический "толстый контроллер". В то время как по определению все сложные действия делаются в модели, а контороллер их только вызывает.

    Классический вариант клиент-серверного MVC:

    Модель - вся бизнес-логика приложения. Это означает, что приложение должно уметь полностью выполнять свои функции с помощью одной только модели (на уровне вызова РНР кода и возврата структур данных в РНР). То есть возвращать список пользователей, удалять и добавлять пользователей и так далее. Выполнять все "действия, которые могут быть сложными".

    Контроллер - тонкий интерфейс между моделью и браузером. Понимать НТТР запросы, принимать данные, приводить их в понятный модели вид и отправлять в модель. Возвращать нужные НТТР коды.
    При необходимости что-то вывести - вызывает view и передаёт туда данные, полученные от модели.

    Вью - рендерит полученные данные в зависимости от желаемого формата, обычно - HTML

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

    Реализация MVC на классическом РНР спагетти-стайл:

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

    Контроллер - РНР файл, который принимает запрос, например на отображение списка пользователей, вызывает нужную функцию из модели, и отправляет результат в браузер. Это может быть либо НТТР код, или HTML или JSON. В случае с HTML вызывает примитивный шаблонизатор, передавая в него массив с данными и имя файла - шаблона

    Вью - тупо HTML файл с вставками РНР. Делится на две части, общий шаблон сайта и шаблон конкретной страницы/действия.
    Ответ написан
    8 комментариев
  • Как заменить часть текста, если таковой начинается с определённых символов?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если текст всегда начинается либо с https://, либо с //, то это не замена текста, а добавление.
    Надо проверить первый символ, и в зависимости от результата либо добавить https:, либо не добавлять.
    $url = $url[0] === "/" ? "https:$url" : $url;
    Ответ написан
    Комментировать
  • Fatal error: Call to a member function fetch_row() on a non-object in ../arizonalive.zzz.com.ua/engine/server.php Как нужно исправить?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это сообщение означает, что возникла ошибка при выполнении запроса.
    Чтобы увидеть, какая именно ошибка, надо перед коннектом к БД написать
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    Ответ написан
  • Можно ли реализовать "умный" поиск по БД?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это называется полнотекстовый поиск.
    В самом примитивном варианте создаётся fulltext index на поля, по которым будем искать. При этом база данных берет каждую запись в таблице, разбивает её на слова, записывает их в индекс и для каждого слова указывает - в каких строках таблицы оно встречается.
    После этого можно сделать запрос по нескольким словам.
    Например,
    SELECT * FROM goods WHERE MATCH(name) AGAINST ('+выключатель +белый' IN BOOLEAN MODE);

    найдёт таки все белые выключатели

    Но встроенный в MySQL полнотекстовый поиск работает так себе и обычно пользуются внешними системами, Spinx Search или Elasticsearch
    Ответ написан
    4 комментария
  • Как проверить, есть ли в одной из колонок двумерного массива хоть одно непустое значение?

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

    $columns = [];
    foreach($array as $row) {
        foreach ($row as $i=> $col) {
            $filled = $col !== "";
            $columns[$i] = !empty($columns[$i]) ? $columns[$i] : $filled;
        }
    }
    
    foreach($columns as $col => $result) {
        echo "Колонка $col ".($result ? "не" : ""). "пустая\n";
    }
    Ответ написан
    Комментировать
  • Нужно ли фильтровать глобальные переменные в PHP?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Как и многие начинающие, вы путаете фильтрацию (<script>) и валидацию (нужно ли тут проверять пустые ли переменные???), при том что это совершенно разные, никак не связанные между собой задачи.

    И решают их тоже по-разному.

    Фильтрация:
    1. Делается строго в момент использования данных
    2. Не имеет ни малейшего отношения к источнику данных.
    Например, исходя из правила №1, как выше правильно написал alexalexes, при выводе любых данных в контекст HTML, необходимо их обрабатывать htmlspecialchars.
    Исходя из правила №2 (фильтруются любые данные, вне зависимости от источника) становится понятным, что ваш "класс фильтр например который фильтрует входные данные" - это Очень Плохая Идея. Мало того что он никак не фильтрует те данные, которые вы не сочли "входящими" (при том что любая кавычка или знак "меньше" в самых супер-доверенных данных поломает вам верстку не хуже злобного хакера), но главное - на момент централизованной фильтрации вы просто не знаете, как данные будут использоваться. А вдруг это будет не вывод в HTML? А вдруг это XML c из Яндекс.Маркета и ваша "фильтрация" превратит его в тыкву?

    Вывод: фильтровать надо любые переменные, а не только "глобальные", причём не заранее, а строго в момент использования. И не всегда под одну гребёнку, а в зависимости от контекста.
    И в этом случае ваш пример с REQUEST_URI не сработает - он зафильтруется при выводе.

    Валидация:
    Валидация - это проверка данных на соответствие заданным параметрам. Это может быть не только пустота, но и размер, соответствие формату, налитчие уже таких данных в БД - миллион разных проверок.
    Валидация пишется для каждой переменной отдельно.

    Где её делать - спорный вопрос.

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

    При этом по-хорошему, в контроллере тоже необходимо делать валидацию, специфичную именно для входящих данных.
    Например, проверить, что в запросе пришли все требуемые поля, элементы name и password присутствуют во входящем массиве. В этом случае можно в какой-то мере говорить о валидации "глобальных переменных" (хотя на самом деле вы имеете в виду входящие данные)
    Также можно проверять некоторые данные на соответствие формату. Нет смысла дергать модель, если мы заранее знаем, что данные не те. Например, вместо id новости в запросе пришло "админ - дурак".
    Или взять ваш пример с query: если содержимое этой переменной должно соответствовать какому-то строгому формату, который не допускает наличие символов < и >, то вы можете проверить его на соответствие формату, и вернуть 400 ошибку.
    Но опять же - никакой централизованной проверки здесь придумать нельзя. У всех входящих переменных свой собственный формат: у ид из бд - числовой, у емейла - емейл, и так далее. Поэтому проверять надо каждое значение по отдельности. Но все эти проверки в общем не являются обязательными. В отличие от фильтрации.

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

    Учитывая, что эти два вида валидации зачастую пересекаются, обычно никто не заморачивается, и всю валидацию делают в контроллере. Что не совсем правильно с точки зрения архитектуры (модель может быть вызвана не только из контроллера), но зато проще в реализации.

    Главное, что важно помнить про валидацию - она не должна быть молчаливой. Если данные не прошли валидацию, это должно вызывать внятную ошибку. В этом случае это действительно поможет при отладке. А если "валидация" молча коверкает данные, то это наоборот - фантастически затруднит отладку
    Ответ написан
    4 комментария
  • Можно ли использовать return;?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    return; - это бессмыслица, её надо убрать из кода
    И никакое false она не возвращает.
    Про "еще одно противоположное значение" вас тоже обманули

    Если функции нечего вернуть, то ничего возвращать она и не должна.

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