Задать вопрос
Профиль пользователя заблокирован сроком с 10 апреля 2022 г. и навсегда по причине: систематические нарушения правил сервиса
  • Как сортировать многомерный массив в php?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    php.net/usort - функция для сортировки чего угодно как угодно.

    А вообще данные надо сортировать в базе.
    Ответ написан
  • Как заполнить форму на другом URL?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    нужен подобный «тестер»

    Не нужен. Это бессмысленная проверка.
    Без всякого теста и так очевидно, что бот зарегистрируется.
    Ответ написан
    Комментировать
  • Возможно ли изменить информацию о песне (mp3) PHP?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    google.com/search?q=php+mp3

    Во всех современных браузерах можно не писать адрес сайта а просто вбить в адресную строку два слова: php mp3
    Для более точноно поиска можно добавить третье слово, "запись"

    Не благодарите.
    Ответ написан
    Комментировать
  • Как трансформировать текст более коротко?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Задачу не понял от слова совсем, но если отталкиваться от условия "кодировать покороче", то можно сделать так:
    function incode($string) {
    	return $string;
    }

    вместо 108710881080108410771088 вернёт "пример" - в 2 раза короче.
    Ответ написан
  • Как в 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 комментарий
  • Где найти официльное описание display_template(ссылку бы)?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Спрашивать надо свой собственный код.
    Поиском по файлам подстроки "function display_template" найдется за пару секунд
    Ответ написан
    Комментировать
  • Книги по php с описанием работы с PDO и SQLite на русском языке?

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

    По PDO не нужна книга, поскольку это очень маленький API, буквально из 5 функций.
    Всё что нужно знать про PDO:

    1. Любые переменные должны попадать в запрос только через плейсхолдер. Поэтому все запросы, в которых участвуют переменные, должны выполняться через prepare/execute: сначала запрос подготавливается через prepare(), причем вместо переменных должны стоять плейсхолдеры, такие ? или такие :name. А переменные потом передаются через execute.
    $pdo  = new PDO ( ... );
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id=?");
    $stmt->execute([$_GET['id']]);
    $user = $stmt->fetch();

    2. Для получения данных есть три функции
    - fetch() получает строку. аналог mysql_fetch_array()
    - fetchAll() получает массив строк. Синтаксический сахар для while ($row = mysql_fetch_array()) (эта функция, кстати - единственная, по которой стоит почитать мануал. у неё есть несколько интересных кунштюков)
    - fetchColumn() - синтаксический сахар для $row = mysql_fetch_row(); $flag = $row[0]

    3. Все остальные тонкости и нюансы описаны по-русски здесь: www.phpfaq.ru/pdo

    4. Особые надстройки над PDO не нужны, но иногда хочется исправить пару неудобных вещей. Например, с помощью www.phpfaq.ru/pdo_wrapper код из п.1 сократится до одной строчки (причем код будет работать отовсюду и сразу):
    $user = DB::run("SELECT * FROM users WHERE id=?", [$_GET['id']])->fetch();

    5. По любым другим вопросам можно спрашивать меня
    Ответ написан
    Комментировать
  • Как внести изменения записи в БД, на SQL PHP?

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Начинающим пользователям действительно бывает сложно понять концепцию файловой системы, иерархических каталогов, понятие текущего каталога и отличие относительного пути от абсолютного.
    Рекомендую почитать вот это: phpfaq.ru/paths

    Для данного случая может помочь путь
    $_SERVER['DOCUMENT_ROOT'].'/ext/mail/PHPMailerAutoload.php';

    впрочем, гарантировать нельзя, поскольку мы не знаем, где лежит папка ext

    Подсказка на будущее:
    Сообщение об ошибке надо приводить сразу. И целиком.
    Ответ написан
    Комментировать
  • Как посчитать количество запросов к базе данных?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Учитывая, что цифра совершенно бессмысленная, проще всего будет сделать
    echo rand(10, 15);
    Ответ написан
    3 комментария
  • Предотвратить SQL Injection без использования bindParam?

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Решение отвратительное. Это уже что-то из серии про архиватор Бабушкина.

    Ну разумеется, коллизии будут.

    Лучше оставить MD5 (у которого вероятность коллизий вполне в пределех допустимого), но перевести его из неэффективного base16 в более короткую форму. Base64 вполне подойдёт, поскольку кодировщик есть в пхп из коробки. Вот только оба не буквенно-цифровых символа там не подходят для передачи через урл - лучше их заменить:
    $base64 =  substr(strtr(base64_encode(hex2bin($md5)),'+/',"_-"),0,-2);

    Итого экономим 10 символов из 32-х. Конечно, 22 хуже чем 8, но тут надо выбирать - или достаточная длина, или коллизии и отсутствие безопасности вообще.
    Ответ написан
    Комментировать
  • 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
    Чебуратор тега РНР
    Ответ очевиден:

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

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

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

    В этом случае БД для поддержания уникальности действительно не нужна, но вот для привязки картинок к сущностям писать всё-таки придётся.

    Я только не понял, при чем здесь кэширование
    Ответ написан
    Комментировать
  • Как правильно писать php вставки в tpl файлах?

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

    Единственный нормальный ответ здесь - от lexxpavlov, с которым я могу только согласиться по всем пунктам:
    - Oбъединять РНР операторы нельзя. Это нарушает сематическую корректность шаблона. Вместо простого и легко формализуемого синтаксиса мы получаем кашу.
    - Заменять ?= на php echo не нужно - это абсолютно бессмысленная трата символов.
    - поигравшись с native php следует перейти на twig, в котором одни только наследование и автоискейпинг заменят тонну говнокода на нативном пхп.

    Остальные же ответы здесь - воспалённые фантазии, не имеющие никакого отношения к реальности. Никаких проблем <?= тег не создаёт.
    Ответ написан
    1 комментарий
  • 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 комментариев