Профиль пользователя заблокирован сроком с 10 апреля 2022 г. и навсегда по причине: систематические нарушения правил сервиса
  • PDO Firebird. Причина возникновения 324 ошибки?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Два заблуждения:
    Во-первых, error_reporting не имеет никакого отношения к выводу в браузер. За вывод отвечает директива display_errors
    Во-вторых, error_reporting не имеет никакого отношения к исключениям PDO. Чтобы этот класс выкидывал исключения, надо ему об этом специально сказать, phpfaq.ru/pdo#connect
    Ответ написан
    Комментировать
  • Как проверить добавление в базу в PDO?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Как проверить добавление в базу в PDO?

    По какой-то причне новички этот вопрос задают постоянно.
    Но при этом никто не может ответить, ПОЧЕМУ надо проверять успешность вставки.
    Только чтобы написать сакраментальную фразу 'Ошибка при регистрации'?

    Ну то есть, понятно, что в мануале из прошлого века был код -1 !== mysql_affected_rows(), и его надо обязательно перетащить в новый проект. Но надо иногда задумываься - какой смысл в тех действиях, которые ты совершаешь. Какой юзкейс должен привести к необходимости такой ошибки. И как надо по-человечески её обрабатывать.

    Дя тех, кто хочет жить в XXI веке, а не застрять навечно в XX, несколько пояснений:

    1. Проверять результат работы функций PDO не нужно никогда.
    2. Если хочется вывести сообщение типа "что-то сломалось", надо это не писать после каждой функции, а делать ЦЕНТРАЛИЗОВАННО, в error handler-e
    3. Если хочется проверить одну-единственную ошибку, про которую заранее известно, и есть понимание того, как её надо обрабатывать - можно использовать try-catch.

    Всё. Кроме этих трёх пунктов никаких проверок на успешность вставки быть не должно
    Ответ написан
  • Как добавить в дочерний класс функцию с PDO?

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

    1. Не надо писать функцию select().

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

    В итоге из практически натурального английского "выбрать все поля из таблицы пользователей, где логин равен тому-то и пароль тому-то" получаем на выходе непонятные иероглифы, про значение которых автор и сам забудет через пару месяцев.
    $this->db->select('*', 'ftl_workers', "login = ? AND password = ?");

    в этом коде автор экономит себе три слова.
    Вопрос: стоит ли эта экономия читабельности и портируемости?
    Вопрос: а что будет, когда автор узнает о других операторах SQL, таких, как GROUP BY, JOIN и пр.?
    Неужели так сложно написать нормальный SQL запрос:
    $this->db->get('SELECT * FROM ftl_workers WHERE login = ? AND password = ?");

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

    2. Самые развесистые грабли. Класс бизнес-логики наследует классу БД. ООП же! Надо же что-то наследовать! При этом совсем не приходит автору в голову, что, скажем, пользователь - это не база данных! И нет ни одной причины наследовать первого от второй. БД может присутствовать в классе как сервис. Как свойство. Но не как. праордитель

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

    4. Как всегда, исключение кидается только для того, чтобы ТУТ ЖЕ его поймать и радостно вывалить на экран. И здесь мы опять видим совершенно поголовное убеждение пользователей похапе в том, что они являются единственными и эксклюзивными пользователями своего сайта. Средний похапешник совершенно искренне не понимает, что у сайта могут быть и другие пользователи, которые эти сообщения ни к чему. А сам он не всегда сидит за монитором, чтобы увидеть сообщение об ошибке.
    И это при том, что сам РНР обработает исключение в сто раз лучше - главное просто ему не мешать. Подробнее можно прочитать здесь: phpfaq.ru/pdo#exceptions

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

    Если уж так уж прям хочется сэкономить одну строчку, то изменения нужны совсем крошечные:
    - надо сделать так, чтобы prepare возвращала statement, и singleton по вкусу.
    получается https://github.com/colshrapnel/thebestpdowrapper
    С нормальным враппером код остаётся читаемым, но в то же время кратким:

    class UserAuth {
        function check($user, $pass) {
            $sql = 'SELECT * FROM ftl_workers WHERE login = ? AND password = ?';
            return DB::prepare($sql)->execute([$user, $pass])->fetch();
        }
    }
    include 'bestpdo.php';
    $ua = new UserAuth();
    $ua->check('admin', 'pqwe');
    Ответ написан
    5 комментариев
  • Почему возвращается только первое совпадение при использование оператора LIKE в mysql?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Суть, на самом деле, в том, что

    Первое: портируя свой код с "процедурной модели" на "объектно-ориентированную" аффтар умудрился не заметить цикл, который был в первой, но испарился во второй. Но виновата оказалась модель ООП РНР.

    Второе и самое главное: портируя свой старый говнокод с mysql_* аффтар осилил только добавление буковки i и стрелочек, всё остальное оставив как есть. Получив в итоге ровно тот же самый говнокод, что и раньше.

    Для справки:
    Смысл перехода с mysql на mysqli не в том, чтобы добавить палочку с точечкой. А в том, чтобы использовать подготовленные выражения.
    Смысл ООП не в том, чтобы писать палочки с угловой скобочкой. А в том, чтобы объект инкапуслировал внутри себя всю работу по обработке данных, возвращая сразу желаемый результат. В итоге код, реально использующий ООП, должен выглядеть как-то так:
    $sql = "SELECT `service` FROM `service_synonyms` WHERE `synonym` LIKE ?";
    $result = $this->_dbconn->getAll($sql, "%$query%");
    Ответ написан
    3 комментария
  • Правильно ли составлена функция php, mysql?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Функция составлена отвратительно.
    Две самых главных проблемы - вывод и работа с БД.

    1) Нужно всегда разделять логику приложения и логику отображения.
    Во-первых, как правильно написал Fesor, никакого вывода в функциях быть не должно.
    Во-вторых, и в остальном коде работа с БД и вывод должны быть всегда разделены. Сначала работает код, который получает данные из базы, и только потом начинается вывод, желательно в отдельном файле-шаблоне.

    2) Несмотря на модную буковку i названиях функций, сам подход остался прежним, и представляет собой классический говнокод из прошлого века.
    Во-первых, любые данные всегда должны подставляться в запрос только через плейсхолдеры. новичкам это традиционно сложно понять, поэтому рекомендуется просто запомнить
    Во-вторых, работать с БД надо не напрямую, а через враппер. Самый примитивный враппер - это PDO. Оно совсем не такое страшное, как написал каментатор выше, и код на самом деле получается короче, чем через mysqli
    function get_banners($limit) {
      global $link;
    
      $sql = "SELECT banner_id,banner_title,banner_text,banner_img FROM banner LIMIT ?";
      $stm = $link->prepare($sql);
      $stm->execute([$limit]);
      return $stm->fetchAll();
    }

    или (с осмысленным враппером):
    function get_banners($limit) {
      $sql = "SELECT banner_id,banner_title,banner_text,banner_img FROM banner LIMIT ?";
      return DB::prepare($sql)->execute([$limit])->fetchAll();
    }


    Вот пример нормального вывода:
    <?
    $banners = get_banners(5);
    ?>
    
    <?php foreach ($banners as $row): ?>
    <div class='last_banner'>
      <div class='banner_item'>
        <img src='<?=$row['banner_img']?>' alt='<?=$row['banner_title']?>'>
        <a href='/click/banner_id<?=$row['banner_id'].?>' target='_blank'><?=$row['banner_title']?>"</a> 
        <?$row['banner_text']?>
      </div>
    </div>
    <?php endforeach ?>


    Впоследствии весь блок с HTML можно будет вынести в отдельный файл

    А вот mysqli_free_result() как раз делать здесь бессмысленно - эта функция будет вызвана автоматически.
    Ответ написан
    2 комментария
  • Как использовать имя переменной как строку таблицы PHP PDO?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Удивительно, что никто не написал, что так НЕ НАДО делать.
    А надо купить себе учебник по реляционным СУБД, узнать, наконец, что это такое, и попробовать впервые в жизни спроектировать БД грамотно.
    Ответ написан
    Комментировать
  • Как сделать зачисление денег на баланс пользователя?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Нанять программиста.
    Если нет денег - пойти работать подавальщиком в макдональдс.
    Ответ написан
    Комментировать
  • Что предпочтительнее отдавать шаблонам для рендеринга страниц?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    С точки зрения архитектуры - подготовленные данные. Так убудет достигнуто лучшее разделение полномочий, и запросы к БД не будут осуществляться на этапе рендеринга шаблона

    С точки зрения удобства разработки АКА программистской лени - объекты все равно пролезают, таща за собой методы, лейзи лоадинг и всю прочую логику модели.
    Ответ написан
    Комментировать
  • На сколько нормально использовать в приложении два PDO объекта?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Самому приложению от этого ни жарко ни холодно. Ну разве что мизерные накладные расходы на второй коннект.
    Вопрос в том, потянет ли база удвоенное количество соединений. Если потянет, то без проблем.
    Ответ написан
  • Mysqli: Commands out of sync; - как исправить чтобы не было ошибки?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Судя по следующему вопросу, этот уже решен. Ну, просто для других читателей - перед тем, как выполнять следующий запрос, надо прочитать информацию обо всех запросах, выполненных через мультиквери, с помощью next_result()

    А лучше вообще не пользоваться этой функцией, а выполннять запросы по отдельности, используй prepared statements
    Ответ написан
  • Mysqli - как исправить ошибку с bind_param?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Перед коннектом к mysqli пишем волшебную строчку
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

    и выясняем, какая проблема была с нашим запросом
    Ответ написан
    Комментировать
  • Mysqli - multi_query - как правильно использовать?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Какой-то странный пример.
    Обычно примеры выглядят по-другому.
    строчка
    if (!$mysqli->more_results()) {
    позволит что-то вывести только если все результаты (и их ошибки!) уже кончились. Поэтому, в упрощенном варианте её надо просто убрать,
    if ($mysqli->multi_query($toadd)) {
        do {
                echo 'Insert ' . $i . ' Error: ' . $mysqli->error . '<br />';
        } while ($mysqli->next_result());
    }

    а в каноническом - добавить в условие while.

    Смысла выполнять мультизапросы, действительно, немного. В 99.999% случаев одинарные запросы лучше.
    Если только УЖЕ есть готовый дамп - тогда имеет смысл применять эту функцию. Специально же собирать запросы в кучу не нужно.
    Ответ написан
  • Насколько prepare и execute обеспечивают безопасность sql-запроса от инъекции?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Вообще, вопрос звучит довольно странно. "Можно ли применять автомобиль для езды?" "Годятся ли деньги для оплаты товаров?", "Безопасны ли подготовленные выражения с точки зрения защиты от инъекций?".
    Собственно, если это их основное предназначение - то наверное, не обеспечивай они защиту, то были бы бесполезны чуть более, чем полностью?

    Смысл подготовленных выражений в том, чтобы решить 3 задачи при формировании динамического запроса:
    1. чтобы вставляемый в запрос литерал был отформатирован корректно
    2. Чтобы форматирование было обязательным
    3. Чтобы оно производилось как можно ближе к фактическому исполнению запроса.

    Благодаря этим трем пунктам обеспечивается гарантированная защита даже с учетом человеческого фактора.

    Так что да - если ЛЮБАЯ переменная попадает в запрос только через плейсхолдер - этот запрос безопасен. Другое дело, что в реальной жизни так не выходит, и переменные в запрос добавлять приходится. Как поступать в таких случаях, я описал в специальной статье

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

    Ну и под конец можно упомянуть редчайший случай, раздуваемый истеричками типа Шифлетта или Феррары - если вы китаец, и используете кодировку GBK (или одну из пары других, столько же часто используемых), то надо не забыть выставить кодировку соединения именно в DSN и только в DSN. Потому что если использовать по привычке SET NAMES, то в режиме эмуляции инъекция будет возможна. То есть, ситуация, когда инъекция через ? плейсхолдер возможна - она существует. Но для этого должны совпасть три фактора:
    - вы должны быть китайцем и использовать кодировку GBK
    - кодировка должна быть задана не в DSN
    - режим эмуляции должен быть включён
    Ответ написан
    1 комментарий
  • Как на PHP сгенерировать уникальную строку?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    $name = md5_file(file_get_contents($old_name));
    Заодно и дубли почистятся.
    Плюс разбивка по каталогам получится более-менее равномерной.
    Ответ написан
  • Сколько символов можно отправить через Get?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Отправлять методом POST
    Ответ написан
  • Как исправить ошибку после установки phpmyadmin?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Let me google that for you, helpless baby: https://www.google.ru/search?q=Fatal+error:+Call+t...
    Ответ написан
    Комментировать
  • Какую выбрать CMS на PHP?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Ну если тебе, болезный, вордпресс слишком сложен, то есть много других профессий, не требующих такого умственного напряжения. Правда, гайки закручивать на заводе тоже сложновато будет, но вот за коровами убирать или сено косить - в самый раз.
    Ответ написан
    8 комментариев
  • Как создать динамические поддомены?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Удивительный факт из мира животных:
    По какой-то очень странной причине хомячки жить не могут без .htaccess
    Без использования этого файла настройки веб-сервера приложение кажется им несолидным, неполным. И они стараются пихать его везде, где только можно.

    Хотя стоило бы на минутку остановиться и просто подумать - а нужен ли он здесь вообще? Какую проблему мы собираемся решать с его помощью? А есть ли она вообще - эта проблема?

    1) Настройках DNS вашего домена добавляете wildcard (*.example.com), чтобы любой поддомен шел на основной
    2) В настройках веб-сервера прописываем виртуалхост *, чтобы все запросы обрабатывались рдним и там же виртуалхостом.
    3) ВСЁ. Больше ничего не надо. Всё уже готово и работает.
    Ответ написан
  • Как преобразовать листинг массива в массив (PHP)?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Адъ.
    Вот я не представляю в любом другом сообществе такой вот вопрос.
    Типа "Я врач-отоларинголог. Из инструментов Горздрав привез только автоген. подскажите, как вырезать им гланды?"
    Ответ написан
    1 комментарий