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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Никакой не выбирать. Выбрать надо charset. utf8mb4.
    А collation подставится сам, по умолчанию.
    Ответ написан
    1 комментарий
  • Как запретить вывод ошибок SQL запроса в PHP?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Во-первых, error_reporting(0); нельзя писать вообще НИКОГДА. Эта строчка всегда должна быть только в виде error_reporting(E_ALL);
    Во-вторых, ini_set('display_errors', 0); - это единственное, что нужно, чтобы запретить вывод ошибок, которые генерирует РНР.
    В-третьих, чтобы твой код не выводил ошибки, не надо писать код, который сам же выводит ошибки на экран. Логично, правда?
    В частности, никогда не использовать обезьяний код, который очень любят рекомендовать местные "специалисты", echo $mysqli->error или or die. То есть тупо выкинуть все такие места из кода

    Вместо этого надо просто сказать РНР чтобы ошибки при работе с БД генерировались сами. И тогда их вывод будет подчиняться директиве display_errors

    В частности, для mysqli это
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    Ответ написан
    7 комментариев
  • Что означает этот фрагмент кода?

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

    В то время как нормальный код должен выглядеть вот так
    function reverse_vowels($word) {
        $vowels = [];
        foreach(str_split($word) as $c) {
            if (preg_match('/[ayeiou]/i', $c)) {
                $vowels[] = $c;
            }
        }
        $v = 0;
        $reverse = '';
        for ($i=0; $i < strlen($word); $i++) {
            $is_vowel = preg_match('/[ayeiou]/i', $word[$i]);
            $reverse .=  $is_vowel ? $vowels[count($vowels) - 1 - $v++] : $word[$i];
        }
        return $reverse;
    }

    который не вызывает вообще никаких вопросов

    Плюс по-хорошему можно первый цикл заменить на
    preg_match_all('/[ayeiou]/i', $word, $matches);
    $vowels = $matches[0];
    Ответ написан
    7 комментариев
  • Как заставить работать .htaccess, если скрипт скрипт работает благодаря php -S localhost:8000?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    учитывая, что словом "хэтеаксес" пэхапешные массы называют роутинг, который заворачивает все запросы на индекс пхп, то достаточно всего лишь прочитать документацию
    php -S localhost:8000 index.php
    Ответ написан
    Комментировать
  • Как сделать json в mysql пустым, чтобы rowCount возвращал 0?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    $query = $db->prepare("SELECT * FROM `followers` WHERE `author_id`=? AND follower_id=?");
    $query->execute([$authorsID,$followersID]);


    и о чудо! rowCount() внезапно работает!!!!

    if ($query->rowCount() > 0) {
          echo 'subscribed';
    } else {
          echo 'unsubscribed';
    }
    Ответ написан
    Комментировать
  • Как правильно работать с большим количеством данных?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Не хочется ругаться, но вопрос очень бессвязный и в нем перемешаны реальные проблемы с нелепыми фантазиями.

    И проблема тут не в незнании как работать с большими базами данных, а в неумении работать с БД в целом.

    Про идею "всем индекс не поставишь" надо сразу забыть. Там где индекс нужен, он должен стоять без вариантов. Другое дело что тупо натыкать индексов по всем полям, по которым идёт поиск - это тоже глупость. Индекс в запросе может использоваться только один, и индексы по второму-третьему полю уже будут бесполезны. Надо анализировать запросы и, возможно, делать составные индексы.

    Детсадовский запрос вида like '%...%' - это отдельный ужас. Надо смотреть на полнотекстовый поиск. А лучше вообще его избегать. На крайний случай использовать внешние поисковые сервисы типа эластика. И только не говори что этот лайк у тебя идёт по полю типа джейсон или "через запятую"

    Но самый конечно кошмар - это select distinct для фильтров. То есть неумение проектировать бд на самом базовом уровне, непонимание самых начальных принципов реляционных бд, нормализации. Вот с этих принципов и надо начать. В потом уже хвататься за большие объемы. Очевидно, что поля по которым ты собрался делать "distinct" - это должны быть отдельные таблицы, от которых в основной таблице будет просто id. поле размером в 4 байта.

    Непонятно, откуда взялись фантазии про гигабайтные индексы, кстати. Большая часть полей в нормальной бд - это не больше десятка байт. То есть индекс - это десятки мегабайт, а не "гигабайты".

    В общем, куда лучше бы смотрелись здесь не абстрактные рассуждения про большие объёмы, а конкретный запрос, который "отваливается". С обязательным результатом EXPLAIN

    А ответ на абстрактный вопрос "как работать с большими объемами" очень простой: точно так же, как с небольшими. Реляционные бд изначально проектировались под большие размеры. То есть надо просто уметь работать с бд. Читать про реляционную модель, нормализацию, индексы, оптимизацию запросов.

    Конкретно для грида надо смотреть в сторону Эластика/Сфинкса. В смысле чтобы не только для полнотекстового поиска, а чтобы все фильтры, которые есть выборке, были забиты в поисковый индекс. И все выборки - через поисковый сервис, а не через прямой запрос к базе
    Ответ написан
    8 комментариев
  • Rest api это обработка запросов?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Как всегда отвечателей понесло не в ту степь. Здесь вопрос не "что такое REST API". Автор не понимает что такое вообще API.

    "Просто" просто хтмл страница, как и " нехитрая таблица" - это пользовательский интерфейс. Странички, на которые живые пользователи смотрят глазками.

    А API - это программный интерфейс. То есть запрос к серверу делает программа. И читает ответ тоже программа. Которой твои таблички сто лет не сдались. И которой нужен программно-читаемый ответ. который программа прочтет и потом уже будет строить таблички. Или не будет - это уж как она сама решит.

    То есть REST API - это когда запрос к твоему веб-серверу делает не браузер по запросу пользователя, а программа. Эта программа может быть либо написана на яваскрипте и исполняться в браузере, либо написана на чем угодно и обращаться с другого сервера.
    При этом для работы API используется стандартная обработка запросов, которая входит по умолчанию в любой веб-сервер (в том числе апач)
    Ответ написан
    Комментировать
  • При загрузке страницы вылетело исключение. На какую страницу делать редирект?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Редирект в случае ошибки сделать невозможно.
    Потому что в случае ошибки сервер обязан отдать НТТР статус с кодом 5хх
    А редирект выдает код 3хх
    То есть, если сделать редирект, то клиент не узнает, что это ошибка.

    При возникновении ошибок поведение боевого сервера должно быть стандартным:
    1. залогировать ошибку для программиста
    2. Отдать корректный код статуса для НТТР клиента
    3. В случае, если запрос делал браузер, то желательно показать посетителю сайта какую-то осмысленную страницу.

    Можно, кстати, обойтись без try-catch, Правильно ли я понял централизованную обработку исключений в PHP?
    Ответ написан
    1 комментарий
  • Как хранить ID категорий в базе?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Для нормальных разработчиков, а не хипстеров, разъясняем:

    "В колонке с типом JSON" - это не современный хайповый способ, а очень редкий вариант, которые следует применять не где попало как советует тов. Rsa97, а с большой осторожностью и только в предназначенных для этого случаях: а именно, когда структура хранимых данных не определена.

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

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

    foreach ($results as $key => $item) {
        if ($item['id'] === 4) {
            unset($results[$key]);
        }
    }
    Ответ написан
  • SQL инъекция в UPDATE возможна ли?

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

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

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

    То есть сама уязвимость никак не зависит ни от каких второстепенных факторов - типа запроса, передаваемых данных, способов их валидации, твоих знаний SQL. Это сам факт. Можно подставить свой код в запрос? Значит он уязвим. А как конкретно можно нагадить - это отдельная тема.

    Кроме того, любая уязвимость - это всегда ошибки. Если в $id будет пусто, то запрос вызовет ошибку. Если в $id будет слово select то запрос вызовет ошибку. Если будет слово "привет", то запрос вызовет ошибку. Оно тебе надо?

    При этом разных вариантов возможных ошибок и способов воспользоваться уязвимостью - тысячи, им посвящены целые учебники и статьи. Но для того чтобы защищаться, не надо знать ни одного. Потому что защищаться надо не от отдельных способов эксплуатации, а закрывать саму уязвимость. И сделать это очень просто:
    1. Любые данные должны добавляться в запрос только через плейсхолдеры
    2. Любые другие элементы запроса должны выбираться из белого списка - заранее прописанных в нашем коде значений.


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

    Если каждый раз писать по три строчки долго
    $sql = "INSERT INTO users SET email = ?, password = ?"; // заменяем на знаки вопроса
    $stmt = $db->prepare($sql); // подготавливаем запрос, получаем stmt
    $stmt->bind_param("ss", $email, $hash); // два знака вопроса - две переменных - две буквы s
    $stmt->execute(); // выполняем запрос

    То надо воспользоваться такой вещью, как программирование. И написать функцию, которая возьмет на себя всю рутинную работу.
    function prepared_query($mysqli, $sql, $params, $types = "")
    {
        $types = $types ?: str_repeat("s", count($params));
        $stmt = $mysqli->prepare($sql);
        $stmt->bind_param($types, ...$params);
        $stmt->execute();
        return $stmt;
    }

    и в итоге предыдущие 4 строчки превратятся в одну:
    prepared_query($db, "INSERT INTO users SET email = ?, password = ?", [$email, $hash]);

    или твой запрос:
    prepared_query($db, "UPDATE table SET test WHERE id = ?", [$id]);

    - просто, быстро, удобно и безопасно
    Ответ написан
    26 комментариев
  • Как вернуть и кол строк выборки и данные из этой же выборки с заданным лимитом?

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

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

    Для тех, кому ехать, а не шашечки. единственный реальный и осмысленный вариант
    SELECT COUNT(*) FROM ## задача с блекджеком и JOIN'ами
    SELECT * FROM /* задача с блекджеком и JOIN'ами */ LIMIT 150


    а "ресурсоёмкие" запросы надо оптимизировать. чтобы они перестали быть ресурсоёмкими.
    Ответ написан
  • Импорт в базу данных не работает null. В чем ошибка?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Использовать подготовленные выражения
    пруф
    Ответ написан
  • Фильтрация данных?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Ты как и все пхпшники путаешь валидацию и форматирование данных.

    Форматирование обязательно, по правилам той среды, в которую ты отправляешь данные.
    У тебя это
    - при использовании переменной в запросе делать это через подготовленные выражения
    - при выводе переменной в браузер обрабатывать через htmlspecialchars

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

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Вопрос сложный.

    Правильный ответ: передавать в конструктор класса.
    Всякие "хранилища" - это костыли, не сильно лучше жлобалсов.

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

    Тут фокус в том, что мы не создаем объекты руками через new.
    И мыслим не отдельными объектами, а конкретным функционалом.
    В А мы передаем тот функционал, который нам создаст экземпляр объекта Бэ

    Самый тупой пример: контроллер принципиально не работает с БД.
    С БД работает модель. Но модель мы вызываем из контроллера. Как быть? Вот он твой случай.

    И тут нам DI, при создании экземпляра контроллера, и передаст в него нужную модель.
    У которой внутри уже будет подключение к БД.
    И которая нам вернет какой-нибудь DTO, создав его сама.

    То есть в ООП мы на самом деле мыслим не отдельными классами, а функционалом. Не "я хочу такой объект создать в А", а "я хочу такой-то функционал получить в А"
    А этот функционал уже сам говорит DI, какой функйионал, какие зависимости ему в свою очередь нужны для работы. DI их прилежно создает. И так по цепочке до самых первичных объектов типа соединения с БД, логгера и пр.
    Ответ написан
    2 комментария
  • Как правильно использовать mysqli_num_rows()?

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

    Да, в mysqli действительно есть специальная функция, которая может сказать, какое количество строк вернул запрос SELECT.
    Традиционно употребляется в двух случаях:

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

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

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

    Правильным решением этой задачи будет сделать запрос вида SELECT COUNT(*) FROM .... В этом случае БД сама внутри себя посчитает количество строк (очень быстро) и вернёт только одно число, которое не занимает оперативную память вообще.

    Вот и получается, что функция mysqli_num_rows() является либо вредной, либо бесполезной

    В данном случае надо сначала получить записи из БД
    // БЕЗОПАСНО выполняем запрос
    $stmt = $link->prepare("SELECT * FROM comments WHERE art_id = ?");
    $stmt->bind_param("s", $note_id);
    $stmt->execute();
    // получаем данные
    $result = $stmt->get_result();
    $comments = $result->fetch_all(MYSQLI_ASSOC);
    ?>

    А после этого уже их выводить
    <?php if ($comments): ?>
        <?php foreach ($comments as $row): ?>
             <?=$row['comment']?><br>
        <?php endforeach ?>
    <?php else: ?>
        Эту запись еще никто не комментировал
    <?php endif ?>


    Как видно, никакой mysqli_num_rows нам не понадобилось
    Ответ написан
    9 комментариев
  • Каким способом можно отловить исключение при ошибке выкачки файла?

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

    Но вообще переходи на джаву конечно. Там это более продумано
    Ответ написан
  • В mysql для быстрого поиска по дате лучше использовать timestamp как int или как date (datetime)?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Для скорости абсолютно без разницы, а для хранения даты и времени надо использовать предназначенные для этого типы данных
    Ответ написан
    6 комментариев
  • Почему SMTP не отправляет русские символы на почту?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Три простых шага для решения данной проблемы:

    1. Посмотреть на календарь и уточнить, какой сейчас век на дворе.
    2. Аккуратно выделить этот код, и нажать кнопочку Del
    3. Скачать phpmailer
    4. Забыть все эти кустарные ковыряния как страшный сон.

    В итоге код должен получиться примерно таким:

    require 'PHPMailerAutoload.php';
    $mail = new PHPMailer;
    $mail->setFrom('from@example.com', 'First Last');
    $mail->addAddress('whoto@example.com', 'John Doe');
    $mail->Subject = 'PHPMailer file sender';
    $mail->msgHTML("My message body");
    $mail->send();

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

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

    проверка на существование и пустоты массива $messages


    Под "проверкой", как я понимаю, тут имеется в виду заметание мусора под ковер? Любимый нубами подход, который заключается в том чтобы помешать РНР сообщить тебе о проблеме, когда ты пытаешься перебрать в цикле несуществующую переменную или не массив?

    И что имеется под пустотой? Если пустой массив - то зачем это проверять-то?

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

    <ul class="list">
      <?php foreach( $messages as $message ) : ?>
      <li class="list__item"><?= $message['content']; ?></li>
      <?php endforeach ?>
    </ul>

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

    tag( 'ul class="list"', $messages as $message )

    которая непонятно - то ли РНР, то ли HTML, которую непонятно как расширять, непонятно как читать.

    Не говоря уже о том, что по синтаксису - это шаблонизатор, а не синтаксис РНР, а ты про них даже не слышал.
    Ответ написан
    2 комментария