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

    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 комментариев
  • Импорт в базу данных не работает 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
    Чебуратор тега РНР
    То что ты ищешь - это вообще не в ту степь.
    у тебя регулярка ищет либо то либо то
    а тебе надо чтобы были И русские И английский
    Как-то так наверное https://regex101.com/r/N20Fo5/1
    Но я, признаться, не очень понимаю как оно работает
    Ответ написан
  • Каким способом можно отловить исключение при ошибке выкачки файла?

    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 комментария
  • Значение @ в php?

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Хороший вопрос, кстати. Сначала ответим на вопрос из заголовка

    file_put_contents($filemame, $somecontent, FILE_APPEND);


    ВСЁ. Это весь код, который нужен, чтобы записать в файл. Одна единственная строчка, без всех этих танцев с саблями.

    А по поводу кода из мануала - это чудовищный, идиотский рудимент из прошлого века, который остался в мануале по недосмотру. Так писать нельзя. Не нужно писать проверки на каждый чих - пхп сам прекрасно сообщит об ошибке. Не нужно заменять четкое и однозначное сообщение об ошибке изложением в свободной форме. И тем более не надо вываливать эти изложения на пользователя сайта. Ему совершенно не интересно читать что у тебя какой то файл не прочитался
    Ответ написан
    3 комментария
  • Выгрузка картинки из базы mysql?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Этот вопрос надо отлить в граните и поместить в палате мер и весов, в виде большой квадратной доски.
    И всех любителей хранить картинки в базе "это же так удобно!!!" заставлять биться об нее головой, пока вся эта дурь из головы не вылетит.
    Ответ написан
    7 комментариев
  • Как правильно прикрепить вложенный файл?

    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");
            // Attach uploaded files
        $mail->addAttachment($filename1);
        $mail->addAttachment($filename2);
        $mail->send();

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Надо включить логику и использовать языковую поддержку для перевода, а не для вывода HTML, JS или canvas

    $lang['use_top_up_cards']       = 'Оплатить с препей карты';
    $lang['available_sum']       = 'Доступная сумма:';
    $lang['pre_deposit']        = 'Оплатить с депозита';
    return $lang;

    В шаблоне
    {$Think.lang.use_top_up_cards}<br><span class="fl ml30">{$Think.lang.available_sum}</span>
    {$Think.lang.pre_deposit}<br><span class="fl ml30">{$Think.lang.available_sum}</span>
    Ответ написан
    Комментировать