• Аналоги почты для домена (дешевле и/или бесплатно) вместо Gmail и Yandex?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я поудалял все ящики и сделал их алиасами для двух оставшихся - то есть почта на них приходить будет. А три ящика бесплатно.
    Не для всех решение, но мне подходит, все равно почта только на прием нужна.
    Ответ написан
    Комментировать
  • Как из JSON корректно передать данные в базу данных?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Немного подрихтуем ученический ответ Taulan Khatuaev

    // Параметры подключения к БД, желательно держать в отдельном файле
    $username = 'myusername';
    $password = 'mypassword';
    $dbname = 'mydatabase';
    $dbhost = '127.0.0.1';
    
    // Подключение к БД
    $dsn = 'mysql:host=$dbhost;dbname=$bname;charset=utf8mb4';
    $options = array(
        // Обязательно - режим информирования об ошибках
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ); 
    $pdo = new PDO($dsn, $username, $password, $options);
    
    // Подготавливаем запрос
    $stmt = $pdo->prepare("INSERT INTO mytable (snippet, amp, date, anchor, link)
                           VALUES (:snippet, :amp, :date, :anchor, :link)"
    );
    
    // Используем транзакцию для скорости и консистентности
    $pdo->beginTransaction(); 
    // Перебираем массив
    foreach ($data as $values) {
        // Выполняем запрос с очередной порцией данных
        $stmt->execute($values);
    }
    // Завершаем транзакцию
    $pdo->commit();
    Ответ написан
  • Можно ли Views созданное в базе данных вывести на сайт?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Можно, но не нужно.
    Представления это те же таблицы, вид сбоку. Обращение к ним ничем не отличается от обращения к таблицам.
    Но вам не нужно никакое View, оно не решает ни одну из ваших проблем.
    Вам нужен банальный джойн с группировкой.
    И немного навести порядок в голове.
    Ответ написан
  • Php ошибка: Parse error: syntax error, unexpected token «}» in C:\Apache\Apache24\htdocs\postgresql.php on line 5. Что не так?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Две главные вещи, которые освоить перед тем как начинать знакомиться с программированием.
    1. Умение читать
    2. Умение логически мыслить, на уровне силлогизмов "если только программисты носят красные рубашки, а петя в красной рубашке, то он программист"
    Это очень важные умения, без которых в программировании совсем никак.

    Сначала читаем сообщение об ошибке:
    Ошибка синтаксиса. Неожиданный элемент «}» в 5 строке.
    Затем считаем строки. 5 строка это "echo "PostgreSQL connection failed";"
    Символа «}» в ней нет.

    Далее делаем логическое умозаключение:
    Если в приведенном коде на 5 строке нет символа «}», это означает, что сообщение об ошибке относится к какому-то другому коду, а совсем не к этому. То есть искать в нем ошибку бесполезно.
    Надо найти тот код, который вызывает эту ошибку, и искать проблему в нем.
    Ответ написан
    Комментировать
  • Можно ли с локального сервера отправить письмо под любым именем?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Можно.
    Но все нормальные почтовые сервера отправят его в помойку не глядя.
    Ответ написан
    4 комментария
  • Экранирование sql запросов, достаточно ли функции?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Эта функция не самописная, а цельнотянутая. Причем из самых смрадных помоек интернета.
    К защите от инъекций не имеет вообще никакого отношения.

    - trim() ни к инъекциям, ни к защите отношения не имеет
    - stripslashes() просто бессмысленная функция, которая только портит данные
    - htmlspecialchars() не имеет отношения к SQL. Применяется при выводе данных, а не при получении
    - real_escape_string() - единственная функция, которая имеет отношение к SQL, но при этом вообще не предназначенная ни для каких защит.

    Попробуйте на основании этой информации самостоятельно оценить полезность вашей функции.

    Возьмем классический пример
    $_GET['id'] = '1;DROP TABLE Students;';
    $id = formatstr($_GET['id']);
    $sql = "SELECT * FRPM Students WHERE id=$id";

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

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    При соединении с БД надо указывать кодировку.
    Поскольку на сайте используется юникод, то соответственно указывать надо utf8mb4

    А сессии тут вообще не при чем.
    Ответ написан
    1 комментарий
  • Как грамотно сделать обработку ислючений в php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Структура проекта какая-то странная, в нем, судя по всему, контроллером называется роутер, но на этом я останавливаться не буду, обработка исключений от этого не зависит.

    Основных правил при обработке исключений три:
    1. Не использовать исключения там, где они не нужны. Например, при проверке пользовательских данных.
    Собственно, эмпирическое правило звучит так: функция должна бросать исключение, если она не может выполнить ту работу, для которой она предназначена.

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

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

    2. Системные ошибки обрабатывает глобальный обработчик исключений, логируя саму ошибку, а на клиент отправляя статус 500 и какое-нибудь абстрактное сообщение о проблеме на сервере. Это самое важное в системных исключениях - текст ошибки никогда, не при каких обстоятельствах не уходит наружу.

    Пример такого исключения - когда запрос в БД порождает ошибку.

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

    Для информирования можно действительно ловить исключение через try..catch и писать какое-то свое сообщение.
    Но можно и автоматизировать этот процесс, вот две статьи, которые показывают примеры, как это можно сделать:
    https://angelovdejan.me/2022/11/24/centralized-exc...
    https://habr.com/ru/articles/688202/
    Ответ написан
    Комментировать
  • Почему не записываются данные в БД, UPDATE не работает?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если данные не обновляются в БД, то на это может быть три причины
    1. Код добавления вообще не вызывался.
    2. При добавлении произошла ошибка.
    3. Данные добавились, в одну базу, а результат смотрим в другой.

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

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Приватная репа на гитхабе
    Ответ написан
    Комментировать
  • Как правильно распределять ответственность между классами?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Сервис - это часть модели. Класс, который реализует некую бизнес-логику, не связанную напрямую с хранилищем.
    Репозиторий - часть модели, класс, который содержит методы для работы с хранилищем.
    Стор - это какая-то местечковая приблуда. Из битрикса небось? Либо какие-то академические измышления, вот как в соседнем ответе. Вроде человек что-то пишет, но яснее ничего не становится.
    Маппер имеет много значений. Если речь про Data Mapper, то это разделение самих данных и их отображения в БД.

    Читать стандартно - Дядюшка Боб Мартин и Мартин Фаулер. Конкретно по РНР - Зандстра.
    Ответ написан
    2 комментария
  • Как исправить кракозябры вместо кириллических символов?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    У вас в этой таблице лежат данные, закодированные в windows-1251.
    Вам надо или перекодировать полученные данные нормально, через mb_convert_encoding(), а не вот это вот недоразумение utf8_encode.

    Или лучше всего один раз и навсегда перекодировать данные в БД.
    Для этого надо сделать дамп, поменять в нем set names с utf8 на cp1251, и выполнить сначала на тестовой БД
    Если данные будут читаться, то выполнить на боевой.
    Ответ написан
    1 комментарий
  • Как работает htmlspecialchars()?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ну уж для такой-то простой функции должно быть достаточно написанного на странице документации.
    И, в частности, про ENT_QUOTES ;)

    Эта функция заменяет спецсимволы, которые являются управляющими в контексте HTML, на безобидные HTML-сущности. Вот и всё.
    Чисто визуально управляющие символы будут выглядеть так же, как и должны, но в коде не будут представлять ни малейшей опасности.

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

    <?php $name = "' onclick='alert(\"pwned!\")"; ?>
    <input value="<?=htmlspecialchars($name) ?>"> Не важно. Весь текст так и заключен в двойные кавычки
    <input value='<?=htmlspecialchars($name) ?>'> Важно. Закрыли одинарную, вписываем, что хотим

    Во втором случае этот код отрендерится, как
    <input value='' onclick='alert(&quot;pwned!&quot;)'>
    (но при этом &quot; отрендерятся в двойные кавычки, и в onclick будет уже валидный яваскрипт
    alert("pwned!")

    А с взведенным флагом ENT_QUOTES мы получим
    <input value='&#039; onclick=&#039;alert(&quot;pwned!&quot;)'>

    И хотя значение внутри атрибута отрендерится, как ' onclick='alert("pwned!"), но оно все целиком будет внутри атрибута value.

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

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

    Чтобы не ломать пальцы, каждый раз набирая всё это htmlspecialchars ENT_QUOTES, толковые джуны всегда пишут пользовательскую функцию-макрос, типа
    function esc($var) {
        return htmlspecialchars($var, ENT_QUOTES);
    }

    Правда, надолго с этой функцией не задерживаются, потому что она годится только при обучении. А любой проект сложнее, чем домашняя страничка про любимого котика, в обязательном порядке уже должен для вывода использовать специальный шаблонизатор, например Twig. Где весь вывод идет с помощью специального оператора, который уже по умолчанию экранирует HTML
    <input value="{{$name}}"> Не важно. Все уже проэкранировано до нас

    Важно помнить, что это экранирование работает только в контексте HTML.
    Если выводим данные внутри кода яваскрипт, то htmlspecialchars поможет как мертвому припарки. И в этом случае надо использовать json_encode.

    Ну и разумеется, надо не забывать комбинировать все варианты экранирования.
    Например, код яваскрипт, который пишется в атрибут HTML тега, надо весь целиком экранировать c с помощью htmlspecialchars. А данные для этого кода - c с помощью json_encode:
    <button onclick="<?= htmlspecialchars("window.open(".json_encode($name).")", ENT_QUOTES) ?>">
    Ответ написан
    2 комментария
  • Почему не происходит изменение записи?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    4 комментария
  • Зачем для кеширования использовать Redis, если можно сделать файловое кеширование?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Вы очень узко понимаете понятие кэширования.
    И забываете о том, что из кэша не только читают, но в него еще и пишут.
    в .php файлах эффективнее хранить не кэш, а какую-то статичную информацию, которая редко изменяется (скажем, только при деплое), и при этом общую для всех пользователей. При соблюдении этих условий кэширование в .php файлах вполне себе используется.

    Но понятие кэша гораздо шире. Кэшироваться может и специфичная для конкретного пользователя или запроса информация. В этом случае никаких .php файлов не напасешься.

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

    Еще одна причина, не главная, но все равно важная - масштабирование. Один сервис редиса можно использовать с несколькими инстансами РНР. Плюс сам редис можно масштабировать на несколько физических инстансов.
    Ответ написан
    Комментировать
  • Что делать если хост отвергает подключение к mysql из вне?

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    В этом примере три переменных содержат по одной букве "в". поэтому этот код выводит 3.
    Чтобы вывести 1, надо убрать букву "в" из содержимого двух переменных

    Если надо узнать, содержимое какой переменной равно в, то тогда это и проверять, без всяких substr_count

    $count_a = $id1 === "в";
    Ответ написан
  • Почему не срабатывает тернарный оператор?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Есть конструкция которая выдает предупреждение Notice: Undefined index: priceweek in ...

    Это неправда.
    Ответ написан
    3 комментария
  • Почему может создаваться большое количество файлов сессий на сервере Ubuntu?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Сессии сами не создаются, их создает РНР при обращении к сайту.
    Сколько обращений - столько сессий.

    Соответственно, смотреть надо по двум направлениям
    1. проверить, не долбит ли кто-то запросами, и заблокировать или ограничить, например использовать Rate Limit у NGINX
    2. файловая система - самое убогое хранилище для сессий, и используется по умолчанию только потому, что для всех других нужно указывать параметры подключения. Соответственно, вместо файлов использовать базу данных.

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если вы тупо не знаете, какие бывают типы исключений, то это легко исправить, посмотрев в документации.
    Там написано, что объекты исключений имеют иерархическую структуру, и самым общим предком является интерфейс Throwable.

    Отдельно следует отметить, что за использование try catch чтобы тупо написать "Получена ошибка" надо бить по рукам. Так никогда не надо делать. Это глупо и бессмысленно. РНР и сам прекрасно выведет и $e->getFile(), и $e->getLine(), и даже $e->getMessage(), и помогать ему в этом не надо.

    Исключение надо ловить только тогда, когда есть определенный сценарий обработки. Например, в случае, если test() выполнилась с ошибкой, то вызвать test2().
    Но главное - внутри блока catch ничего не выводить пользователю.
    Общением с пользователем должны заниматься только специально предназначенные для этого блоки программы. А не любая строчка, которой вдруг захотелось это сделать.

    Поэтому в данном конкретном случае ваша задача еще больше упрощается - не надо ловить вообще никакое исключение.
    Ответ написан