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

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

    Для этого надо правильно соединяться с mysqli.
    Не одной строчкой, а указывая все нужные параметры. В частности режим отображения ошибок:
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    И тогда БД сможет тебе наконец сказать, что ей не так.

    Если взять код mysqli.php по ссылке выше, то правильный, безопасный, и сообшающий о своих ошибках код будет таким
    function SendNotice($conn, $p1, $p2) {
        $sql = "SELECT `id` FROM `users` WHERE `login` = ?";
        $row = prepared_query($mysqli, $sql, [$p1])->get_result()->fetch_assoc();
        if (!$row['id']) echo 'Ошибка!';
        $sql = "INSERT INTO `notifications` VALUES (null, ?, 0, NOW(), ?)";
        prepared_query($conn, $sql, [$row[id], $p2]);
    }

    И вызываться она должна так
    include 'mysqli.php';
    SendNotice($conn, 'test', 'Test text');
    Ответ написан
    2 комментария
  • Генерация php кода и его исполнение из бд, возможно ли?

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

    Чудовищнее всего здесь ответы: "очень-очень осторожно", "нужно делать валидацию". При этом спроси их - что именно осторожно? Какую именно валидацию? - не ответят. Потому что простого ответа нет, надо учитывать кучу деталей. А в итоге все равно станутся дыры.

    В общем, генерировать РНР код можно, но только на этапе разработки. Генерировать РНР код на основе пользовательского ввода - это ад и харакири.
    Ответ написан
    6 комментариев
  • Invalid datetime format. Как решить?

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

    <?php
    require("connect.php");
    
    $task = R::dispense( 'tasks' );
    $task->task = strip_tags( $_POST['tasks'] );
    $task->date = date('Y-m-d');
    $task->time = date('H:i:s');
    $id = R::store($task);
    Ответ написан
    1 комментарий
  • Что лучше Laravel или Lumen для REST API?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Именно поэтому подход Симфони 4 рулит. Выбираешь только те компоненты, которые нужны.
    Ответ написан
    Комментировать
  • Как с помощью класса для PDO получить результат update?

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

    А ответ на вопрос простой но неожиданный - никак.
    Результат запроса update тебе не нужен.

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

    Если же говорить о количестве строк, которые затронул запрос, то, поскольку у тебя абстракция не течет, то вместо метода sql(), который тупо дублирует run(), я бы сдела метод dml()

    public static function dml($query, $args = []) {
        $stmt = self::run($query, $args);
        return $stmt->rowCount();
      }

    и применял ее только для запросов, модифицирующих данные (DML).
    Ответ написан
    1 комментарий
  • Как запускать php скрипт после каждого завершения работы?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    просто в командной строке написать
    while true; do php -f /путь/скрипт.php; done
    остановить - Ctrl-C
    Ответ написан
    5 комментариев
  • Виртуальный поддомен или физический?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Этот вопрос задавался 100500 раз, но искать лень.

    В ДНС делается wildcard запись *.example.com, чтобы все запросы к субдоменам вели на один хост.
    Апач настраивается аналогично.
    Конкретный запрошенный хост берется из HTTP_HOST.
    Всё, больше ничего не надо.
    Ответ написан
    5 комментариев
  • Как правильно передать и обработать X-Request-ID?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Я не занимался, но прочел ответ на стаковерфлое

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Не надо хранить в базе данных " массивы значений в JSON'е".
    MySQL - реляционная датабаза. Это означает, что база данных строится из связанных таблиц.
    И вместо колонки values должна быть отдельная таблица,
    table_id | value
    1 | 1
    1 | 2
    1 | 3
    2 | 2
    2 | 3
    2 | 4

    И тогда все выборки будут делаться примитивными SQL запросами, без малейших затруднений со стороны разработчика.
    Ответ написан
    5 комментариев
  • Хорошо ли написан класс БД?

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

    Можно поправить только по мелочам.

    - код соединения никуда не годится. Брать отсюда: Как правильно соединяться с mysql в PDO
    - при этом конфиграцию (хост, пароль, чарсет и прочее) вынести отдельно и передавать в конструктор в виде массива
    - query() переписать так:
    private function query($query, array $params = array()){
        $stmt = $this->db->prepare($query);
        $stmt->execute($params);
        return $stmt;
      }

    - добавить getRow() и использовать в getById именно его.
    - getRows переименовать в getAll чтобы не было путаницы и переписать так
    public function getRows($query, array $params = array(), $mode= PDO::FETCH_ASSOC){
        return $this->query($query, $params)->fetchAll($mode);
      }
    - либо добавить методы для всех методов PDO, либо сделать $db публичной. потому что когда тебе нужно будет выполнить десяток инсертов обернутых в транзакцию, эта обертка превратится в тыкву.
    Ответ написан
    5 комментариев
  • Какой есть 100% способ перекодировать строку в utf-8?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Такого способа нет.
    Для стопроцентного результата необходимо знать кодировку исходного текста.
    Ответ написан
  • Как соединить работу двух методов?

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

    В идеале цепочка вызовов должна быть такая
    Контроллер вызывает инстанс хелпера (или сервиса) CustomerHelper.
    В этот хелпер через конструктор передается инстанс CustomerRepository и присваивается свойству класса.
    В методе Create класса CustomerHelper вызывается метод Create класса CustomerRepository.
    И в этом методе уже и происходит искомая транзакция.
    Ответ написан
    3 комментария
  • Почему не хочет создаваться запись в бд?

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

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

    Не говоря уже про дырявость и дурацкую идею про "сначала пусть заработает". Проверять работу запроса надо в mysql. А в PHP "пробовать" не надо, надо сразу писать запрос через prepare
    Ответ написан
    Комментировать
  • Как изменить путь $_SERVER['DOCUMENT_ROOT']?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    RewriteEngine On
    RewriteRule ^main/(.*)$ /$1 [L]


    Но на будущее надо не лениться и не пложить папочки на локальном компе, а делать честные домены.
    Это совсем нетрудно.
    Ответ написан
  • Нужен ли класс в этом случае? Или можно держать функцию особняком?

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

    Кроме того, авторы видеокурсов в большинстве своем - неграмотные имбецилы, которые с трудом понимают код, который пишут. Кроме шуток. Пример. Вот так пишут обезьяны:
    $i = 0;
        $newsList = array();
        while($row = $result->fetch()) {
          $newsList[$i]['id'] = $row['id'];
          $newsList[$i]['title'] = $row['title'];
          $newsList[$i]['date'] = $row['date'];
          $newsList[$i]['author_name'] = $row['author_name'];
          $newsList[$i]['short_content'] = $row['short_content'];
          $i++;
        }
        return $newsList;

    Реально, макаки.
    Этот гамадрил где-то сам увидел обучающий материал из 1990-х годов прошлого века, запомнил его, и теперь лепит уже в свои "обучающие ведидео".
    при том что если бы он понимал смысл этого кода, то написал бы просто
    $newsList = array();
        while($row = $result->fetch()) {
          $newsList[] = $row;
        }
        return $newsList;

    Поскольку $row уже содержит все нужные данные и переливать их из пустого в порожнее не нужно.
    А если бы наш бабуин хотя бы раз в жизни поинтересовался инструментами, которые он использует, то написал бы и вовсе одну строчку,

    return $result->fetchAll();

    Поскольку все уже написано до нас - надо только руку протянуть и использовать готовое.

    И это я не говорю о том, что класс насковозь дырявый в плане безопасности.

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

    В нормальной же модели класс нужен, поскольку в ней будут использоваться переменные класса, например соединение с БД. Таким образом его можно будет передать в конструктор один раз и не писать соединение в каждом методе.
    Также в модели удобно прописать имя таблицы. Тогда множество методов можно будет унаследовать от единого прототипа. например

    abstract class Model {
        protected $table;
        protected $db;
        public function __construct($db) {
             $this->db = $db;
        }
        public function find($id) {
            $sql = "SELECT * FROM `$this->table` WHERE id=?";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$id]);
            return $stmt->fetch();
        }
    }
    class News extends Model {
            protected $table = 'news';
    }
    $news = new News($db);
    $article = $news->find($id);


    Вот это уже будет минимальное оопэ, и использование класса будет более чем оправдано - один раз написали код, а потом его используем.

    Если хочется нормальных обучающих материалов, рекомендую канал Дмитрия Елисеева, https://www.youtube.com/user/ElisDN/videos
    Ответ написан
  • Как проверить в php результат запроса?

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

    Проверять надо не карман, а деньги. Не результат запроса, а строки, которые он вернул. То есть надо просто сделать фетч и вот уже результат фетча проверять в условии. То есть if ($post)

    Ну и как всегда надо напомнить, что переменные никогда не пихают в запрос напрямую, а передают отдельно. Готовый код можно посмотреть здесь, https://phpdelusions.net/mysqli/check_value
    Ответ написан
    Комментировать
  • Почему так странно ищет substr?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Что вопрос, что ответы - АД.

    Как правильно написали, это PHP serialize, только не целая строка, а какой-то огрызок
    Поэтому надо брать оригинаьную строку, и делать так
    $array = unserialize($findstr);
    echo $array['name'];
    Ответ написан
    Комментировать
  • Подключение к базе данных MySql, как правильно и современно?

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

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

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

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

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

    Хорошим вариантом будет использовать высокоуровневую абстракцию типа redbean. Но поскольку нормальной документации по нему нет, а есть только пара хайповых видео, где он используется, причем без каких бы то ни было объяснений и разбора основ, то я бы рекомендовал редбин уже опытному разработчику, а не начинающему. Но в любом случае как в нем соединяться, написано в документации

    Пароль в базе данных не шифруется а хэшируется. Делается это с посощью функции password_hash
    Ответ написан
    3 комментария
  • Где сейчас тусуются серьезные PHP программисты?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Завсит от цели, для чего это спрашивается.

    Если чтобы поприставать с нубскими вопросами - то нигде.
    Если чтобы почитать умных мыслей - РНР дайджест на Хабре прекрасно суммирует все, что было написано за две недели. У меня например никогда не хватает времени, чтобы прочесть всё. Куда больше-то - я уж и не знаю.
    Если чтобы поучаствовать в серьезном прокете - на гитхабе, выбирай любой.
    Если чтобы послушать интересные доклады и пообщаться вживую - то конференции.
    Если интересует внутренне устройство языка - то php internals.
    Если интересует, что пишут пхп селебрити про что угодно, кроме программирования - то твиттер (Расмус показывает картинки из аэропортов и роботов, которых собирает его сын, Сара постит котиков - и так далее).

    Где точно не тусуются:
    Тостер и всякие подобные ресурсы типа стаковерфлоя.
    Ну то есть специалиста можно найти, если поискать, но концентрация будет гомеопатическая, если учитывать количество восторженных щеночков, которые увидели язык вчера, и спешат срочно поделиться уже накопленным багажом знаний.
    Чаты. Телеграм, дискорд - вот это вот все.
    Самая адовая трата времени, которая в принципе бывает в жизни.
    Опять же, люди пишут о чем угодно, кроме программирования, и ради пары полезных строчек надо убить весь день.
    Ответ написан
    4 комментария
  • Что конкретно делает эта функция mysqli_real_escape_string()?

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

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

    Как ты, наверное, уже знаешь, строки в SQL берутся в кавычки:
    SELECT * FROM table WHERE name='vasya'
    Вот чтобы vasya не приняли за имя таблицы или ключевое слово, его берут в кавычки. Очень просто. Но иногда у человека имя не просто вася. Что будет вот с таким запросом?
    SELECT * FROM table WHERE name='Я Д'Артаньян, а все вокруг ...'

    Мясорубка будет. БД решит, что имя - это 'Я Д', а дальше какая-то фигня, которую она не понимает. И выдаст ошибку.
    Поэтому кавычки надо экранировать.
    SELECT * FROM table WHERE name='Я Д\'Артаньян, а все ...'

    никаких ошибок не выдаст.
    Вот mysqli_real_escape_string() как раз этим и занимается - экранирует кавычку слешем, а заодно и сам слеш, потому что если слеш окажется в конце строки,
    SELECT * FROM table WHERE text='Мну сегодня в любви вкладкой ошиблись :\'

    то БД решит, что последняя кавычка экранирована, и строка не заканчивается. Снова мясорубка.
    Также mysqli_real_escape_string() экранирует еще несколько символов, но уже из чисто эстетических соображений.

    Еще одна функция этой функции - принимать в расчет кодировку текста. Есть кодировки, в которых слеш - это не слеш, а часть другого символа. И когда БД будет парсить запрос, она не поймет, что это слеш, а решит что это просто буква. И снова мясорубка.
    Поэтому перед использованием mysqli_real_escape_string() надо сказать БД, в какой кодировке у нас данные, с помощью функции mysqli_set_charset().

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

    1. Строки надо форматировать в любом случае, независимо от того, ждем мы инъекцию, или нет. Мясорубка нам точно так же не нужна.
    2. Строками синтаксис SQL запросов не исчерпывается. Есть числовые литералы, есть имена полей. Для всех них mysqli_real_escape_string() бесполезна чуть более чем полностью.

    То есть, отсюда можно сделать вывод, что нельзя использовать mysqli_real_escape_string() для защиты от инъекций. Она предназначена для другого. Вот для этого другого, для форматирования строк, ее использовать можно. Но не нужно.

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

    В принципе, mysqli умеет так делать, но не так удобно как PDO. Поэтому при возможности вместо нее лучше использовать PDO:
    $stmt = $pdo->prepare("SELECT * FROM table WHERE name=? or name=?")
    $stmt->execute(["Vasya", "Д'Артаньян"]);
    $rows = $stmt->fetchAll();
    - и получить, в итоге, готовый массив с данными, которые вернула БД.
    Если же возможности нет, то кода придется написать чуть побольше
    $stmt = $mysqli->prepare("SELECT * FROM table WHERE name=? or name=?")
    $stmt->bind_param("ss", ...["Vasya", "Д'Артаньян"]);
    $stmt->execute();
    $rows = $stmt->fetch_all(MYSQLI_ASSOC);


    Но при этом всё равно никакой тебе возни с кавычками, слешами, real, escape, и прочей ерундой. Просто, быстро, лаконично и безопасно.
    Ответ написан
    4 комментария