Профиль пользователя заблокирован сроком с 10 апреля 2022 г. и навсегда по причине: систематические нарушения правил сервиса
Ответы пользователя по тегу MySQL
  • Почему PDO не создает новое подключение, пока не завершится предыдущее?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Дело не в ПДО.

    Как быть, господа?

    Учиться правильно выявлять причинно-следственные связи, а потом уже задавать вопрос.

    Скорее всего, второй скрипт попросту не может начать работу, и это связано с сессиями. Если скрипт работает ТАК долго, то сессию в нем надо завершить, как только она стала не нужна. Но если это онлайн скрипт, то надо делать так, чтобы он отрабаотывал мгновенно, и таких вопросов вообще не возникало.
    Ответ написан
    7 комментариев
  • Почему не работает in ?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Потому что нет столбца с ключом 'where_1, where_2, where_8'

    Кстати, на будущее запомни, что БД, с которой ты работаешь, называется Mysql, а не mysqli
    Ответ написан
    Комментировать
  • Объясните пожалуйста, что за ошибка в функции?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Это означает, что ошибка была в запросе.
    По умолчанию mysqli не сигнализирует об ошибках в mysqli_query(). Чтобы заставить её делать это, надо перед коннектом написать волшебное слово:
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

    Это самый простой, но менее удобный способ, поскольку в сообщении об ошибке нам желательно сразу увидеть и запрос с ошибкой. Поэтому лушче проверять результат запроса, и порождать ошибку РНР с ошибкой mysql и запросом.

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

    Поэтому вместо того, чтобы продолжать писать на mysqli ТОТ ЖЕ САМЫЙ УРОДЛИВЫЙ ГОВНОКОДО, что и на mysql, надо использовать более интеллектуальный подход, который будет обеспечивать как форматирование, так и обработку ошибок:
    function get_products($db, $ids, $start_pos, $perpage){
        if($ids){
            $query = "SELECT * FROM sdvd_products WHERE parent IN($a) LIMIT ?i, ?i";
        } else {
            $query = "SELECT * FROM sdvd_products LIMIT ?i, ?i";
        }
        return $db->getAll($query, $ids, $start_pos, $perpage);
    }
    Ответ написан
    Комментировать
  • Структура БД диалогов: как построить?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Я бы хранил всю переписку во-первых, в одной ячейке, а во-вторых, тупо дублировал бы её. Это, конечно, расход места, но зато просто.
    Ответ написан
  • SELECT * vs SELECT COUNT(*) vs ... - что быстрее?

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

    ЕСЛИ не читать тело вопроса, а отвечать на вопрос из заголовка (а это ключевой момент для Q&A сайта, поскольку тупые поисковики приводят именно по заголовкам. И администрация должна следить за релевантностью оных и вычищать вопросы, которые автор не в состоянии сформулировать), то ответ однозначный - за выборку ЗАПИСЕЙ только для того, чтобы ПОСЧИТАТЬ их, дают пожизненный эцих с гвоздями. Считать должна база!

    ЕСЛИ отвечать на вопрос вне контекста вставки, а только глядя на запросы, то ответ - ОДИНАКОВО. В обоих случаях никакого подсчета нет а есть только выборка по ключу.

    ЕСЛИ вникать в контекст задачи чуть глубже, то появляются варианты ускорить МНОЖЕСТВЕННУЮ проверку, такие как prepared statements (тот редкий случай, когда их фича с множественным исполнением может выстрелить).

    ЕСЛИ вникать в задачу окончательно, то правильным будет ответ @zeromodule. Причем вставку надо либо делать множественную, по тысяче записей, либо заворачивать в транзакцию - поскольку ОБНОВЛЕНИЕ ИНДЕКСА при таком количестве вставок начнет тормозить работу куда сильнее, чем нищасные селекты, столь пугающие аффтара. И опять же использовпать prepared statements.
    Ответ написан
    Комментировать
  • Как реализовать механизм очистки кэша?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Насколько я вижу, этот кэш на 99% кэшрует то что не нужно кэшировать.

    Рекомендую сначала научиться работать с БД, и отладить работу с ней, чтобы в 99% случаев кэш не требовался вовсе.
    После этого отпрофилировать приложение, понять узкие места, и оптимизировать их.
    И только после этого, если даже разумная оптимизация не помогает - начинать что-то кэшировать.

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

    При этом ни к PDO, ни к php-fpm вопрос отношения не имеет.
    Ответ написан
  • Где найти скрипт mysql->xml?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    $xml = `mysql --xml --execute="SELECT 1 num FROM dual;"`;
    Ответ написан
    Комментировать
  • Что может быть не так с insert mysql?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    ооооооо! Очередной боретс с ужасными инъекциями применяет секретное хакерское кодирование.
    Ответ написан
  • Как поймать ошибку соединения MySQLi?

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

    Писать перед коннектом.
    Отлавливает ошибки не только коннекта, но и запросов.

    А функцию error_handler() надо выкинуть - она вредная и ненужная.
    Равно как и идея писать ошибки БД в базу данных.
    Не надо выпендриваться. Пишите в лог как все.
    Ответ написан
    5 комментариев
  • Как в PDO значение LIMIT при запросе сделать INT?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Хороший вопрос. Как раз показывает убогость стандартной системы плейсхолдеров.
    В моей библиотеке для работы c MySQL тип указывается самым простым и эффективным способом - прямо в плейсхолдере:
    //первый запрос (лимит здесь не нужен)
    $id = $db->getOne("SELECT id FROM users WHERE mail = ?s AND pass = ?s", $mail, $pass);
    // второй запрос
    $sql  = "SELECT id, name FROM news WHERE category = ?s AND subcategory = ?s LIMIT ?i";
    $news = $db->getIndCol('id', $sql, $cat, $subcat, $limit);

    Как видно из этих примеров, тип ставится в самом плейсхолдере и все входящие данные обрабатываются корректно.

    Вернемся теперь к несчастному PDO.
    Цикл с подстановкой в bindParam?

    Цикл, увы, не поможет. Потому что мы не знаем, какой тип использовать для привязки. То есть, все сведется к дефолтному PARAM_STR и в итоге мы получим то же самое execute() с массивом, только в профиль.
    Если вдруг возникнет идея определять тип по составу переменной, то делать это НИ В КОЕМ СЛУЧАЕ НЕЛЬЗЯ. Если бы мог, я бы выделил ещё большим шрифтом и красным цветом. Потому что практически каждый продвинутый пользователь похапе рано или поздно наступает на эти грабли. Если число, хранящееся в MySQL, всегда можно безопасно сравнивать со строкой, то наоборот - это будет катастрофа: MySQL будет пытаться привести содержимое поля к числу. То есть, если взять пример из вопроса, и пытаться определить тип привязки по содержимому переменной, то при введенном пароле 12345 ctype_digit() скажет нам использовать INT и в итоге пароль 12345 подойдет к любому паролю вида "12345буквы".
    Так что цикл - не вариант.

    Я читал, что можно еще отключить режим эмуляции, но я не знаю, как это повлияет на безопасность

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

    Так что либо в параметрах DSN, либо с помощью
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

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

    И последнее замечание.
    Функцию для выполнения запросов писать в общем-то нет смысла. PDO достаточно лаконичен и сам по себе. Единственное, что мешает писать однострочники - это дурацкая execute(), которая возвращает не себя, а булево значение. Но это легко исправить, и в итоге код получится ненамного длиннее, чем при вызове функции, но гораздо более гибким (ненавижу скроллинг, поэтому выношу параметры на другие строчки):
    // с функцией
    $sql   = 'SELECT `user_pass` FROM `users` WHERE `user_mail` = :mail LIMIT :lim';
    $param = array(':mail' => 'vlad-dub1994@mail.ru', ':lim' => 1);
    $data  = select($sql,$data);
    // с патченым PDO
    $data = DB::prepare($sql)->execute($data)->fetch();
    
    // или другой вариант записи
    $data = DB::prepare('SELECT user_pass FROM users WHERE user_mail = :mail LIMIT :lim')
    	->execute([':mail' => 'vlad-dub1994@mail.ru', ':lim' => 1])
    	->fetch();

    Всего на пару слов больше, но зато можно исполнять любые запросы (INSERT к примеру):
    $sql   = 'INSERT INTO users VALUES(?,?,?)';
    $param = array(NULL, 'vlad-dub1994@mail.ru', 'pass');
    DB::prepare($sql)->execute($data); //OK
    select($sql,$data); // ошибка из-за fetch()

    и использовать любые варианты получения данных, которые поддерживает PDO:
    $sql = 'SELECT id FROM tree WHERE parent_id=?';
    $subcat = DB::prepare($sql)->execute([$parent])->fetchAll(PDO::FETCH_COLUMN);
    Ответ написан
    1 комментарий
  • Как внести изменения записи в БД, на SQL PHP?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Покажи человеку, который писал этот код, вот эту ссылку: phpfaq.ru/debug
    Пусть прочтет и попытается понять.
    Ответ написан
  • Предотвратить SQL Injection без использования bindParam?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    С помощью небольшой магии и короткого синтаксиса код можно еще больше сократить
    $sql = 'SELECT * FROM users WHERE email = ?';
    $rows = $db->prepare($sql)->execute([$email])->fetchAll();
    Ответ написан
    Комментировать
  • PDO PHP как убрать экранирование в запросе?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    А теперь, по традиции, правильный ответ, от единственного здесь человека, который видел PDO, а не просто слышал краем уха, что пацаны на раёне рассказывали.

    $dbh = new PDO(
    	"mysql:host=$db_host;dbname=$db_name;charset=$db_charset",
    	$db_user,$db_pass, array(
    		PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    		PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ
    	));
    $sql  = "SELECT * FROM files WHERE name = '/var/www/test/1.txt'";
    $data = $dbh->query($sql)->fetchAll();

    при появлении ошибки - прочесть и исправить.

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Прекрасный, прекрасный пример того, что такое эти Q&A сайты.
    Ну неужели жалкий ручеек тафика, состоящего из убогих и ламеров всех мастей, стоит того, чтобы терпеть это позорище?

    Вопрос, который к ПДО имеет такое же отношение, как я - к балету, и - самое главное - ответы, прекрасно описываемые анекдотом про Вовочку "Я, конечно, не профессор..."

    Вопрос, код в котором принципиально не будет работать, поскольку аффтару надо либо крестик снять, либо трусики надеть, и опеределиться - нечеткое у него сравение (и добавить LIKE) или четкое (тогда убрать процентики).

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

    Ну и вишенка на торте - совершенно детская причина всех страданий - коварные переводы строк, возвращаемые file() по умолчанию.
    Ответ написан
    Комментировать
  • Как правильно проиндексировать longtext в mysql?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Ответ очевиден:

    Чтобы отсортировать числовые значения, их надо записывать в колонку числовогго типа.

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

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

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

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

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

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

    Всё. Кроме этих трёх пунктов никаких проверок на успешность вставки быть не должно
    Ответ написан
  • Почему возвращается только первое совпадение при использование оператора 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 комментария