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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Все твои проблемы из-за уродливого костыля в виде site. От него надо избавляться.
    Каждый виртуальный сервер должен быть в своей папке. Тогда ты сможешь писать везде нормальные абсолютные пути от корня сайта

    Подробнее про абсолютные и относительные пути, phpfaq.ru/newbie/paths
    Ответ написан
    Комментировать
  • Как понять есть ли нагрузка на БД?

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

    Так вот: я смотрю, что получил 1500 строк из базы за 0.0316 секунд. Это нормально?

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

    База растёт и строк к выводу станет больше.

    С КАКОГО, я стесняюсь спросить, перепугу, с ростом базы строк к выводу станет больше?
    На тостере с каждым днем прибавляется сотня дебильных вопросов.
    Ты уверен что количество запрашиваемых из базы строк тоже растёт? А если подумать? А если прям вот хорошенько подумать?

    Этот ход мысли напоминает старый еврейский анекдот, который рассказывал Джоэл Спольский в далёком 2001 году:
    Маляр Шлёма подрядился красить пунктирные осевые линии на дорогах. В первый день он получил банку краски, поставил её на дорогу, и к концу дня покрасил 300 метров осевой линии. «Отлично! — сказал прораб. — Быстро работаешь!» и заплатил ему.
    На следующий день Шлёма покрасил 150 метров. «Мда, это, конечно, не так здорово, как вчера, но приемлемо», — сказал прораб и снова заплатил ему.
    Ещё через день Шлёма покрасил всего 30 метров. «Всего лишь 30! — заорал прораб. — Это никуда не годится! В первый день было в десять раз больше! В чём дело?»

    «Ничего не могу поделать, — говорит Шлемиэль. — Каждый день я ухожу всё дальше и дальше от банки!»


    Тебе не кажется что эта логика напоминает твоё "но с каждым днём в БД появляется всё больше и больше записей!"?

    На что ориентироваться? На показатели загрузки процессора или время выполнения запроса или расход памяти?

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

    И вопрос в догонку: если одним запросом я получаю 1500 строк и если в запросе я установлю select нужных мне столбиков - это усложняет запрос или нет? Ведь в первом случае я получаю информацию как есть, а во втором случае процессору надо время чтобы перебрать нужные столбики?!

    Судя по количеству восклицательных знаков - это самый важный вопрос во всём этом и так целиком гениальном тексте. Процессор опасносте!!! Срочно надо спасать!

    Запрос выполняется три сотых секунды, дом рисуется 10, но вопрос почему-то "как узнать , не тормозит ли база?"
    Ну ей-богу, снова как в анекдоте - "Где логика??! Где разум??".

    Сейчас я кеширую результаты php на 60 минут,

    Вот это я понимаю. Сразу заходим с козырей.
    странно что на 60 минут, а не на 24 часа. или вообще сделать сайт статикой. тогда вообще всё летать будет. Или вообще перенести всю БД на клиента. Чего не сделаешь ради борьбы за миллисекунды.

    Как понять есть ли нагрузка на БД?/

    Посмотреть, есть ли нагрузка.
    Тормозит ли сайт, есть ли загрузка по процу и памяти, есть ли отказы в обслуживании, ошибки в логах.
    Если ничего этого нет, то сидеть на попе ровно и ничего не трогать!

    А вместо всяких "оптимизаций" типа кэширования на 60 минут запроса, который выполняется пару сотых секунды, или не на покупки бессмысленного диска, а на букварь про работе с БД. И прочитать там про нормализацию, индексы, базовые команды SQL, пагинацию, в конце концов.

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

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

    Но вообще переходи на джаву конечно. Там это более продумано
    Ответ написан