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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Докер выполняет ту роль, которую до этого у тебя играли всякие денверы, опенсерверы, и прочая вампа-юмба. Вместе с панельками на хостинге.
    Кроме симфони есть еще много других программ. Которые устанавливаются через композер. Надо уметь добавлять пакеты в проект, как самому, так и добавленные другими. Надо уметь разворачивать локально проект, который использует композер. Надо уметь читать composer.json. А по-хорошему ещё и писать. Но вообще по сути главное понимать разницу между install и update
    До того как "отправлять сделанные задачи" (только в git, а не github), сначала надо эту самую тестовую ветку завести локально. И уметь разруливать возникающие конфликты.
    Кроме того, контроль версий помогает в первую очередь тебе. Это не для дяди-тимлида, а для себя делается. Чтобы можно было посмотреть историю изменений, откатить, посмотреть какой код ты менял, когда он перестал работать.

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

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

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

    скачать пхп, распаковать, перейти в папку с пхп файлами, запустить команду
    c:\путь куда распакован РНР\php -S localhost:80
    Ответ написан
  • Проверьте метод, ничего не упустил?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Тут скорее очень много лишнего.
    Начиная с названия.
    Почему функция с названием intClean занимается и теми и другими числами?
    Зачем вырезать "случайно поставленную букву"? Зачем вообще позволять вводить буквы?
    Зачем заменять точку в интах?
    Зачем позволять точку в поле, которое требует целое число
    Зачем ловить исключение внутри функции?!

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

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

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

    - Error exceptions, или по простому говоря - ошибки. Обычные ошибки при выполнении программы. Обычно код бросает их сам. Решение "обрабатывать все ошибки через set_exception_handler" будет вполне логичным.
    - Business logic exceptions - это не ошибка в строгом понимании этого слова, а скорее нормальное поведение программы. Ситуация исключительная, но только для бизнес-логики. Их всегда кидает программист.

    И вот просто тупо исходя из того что их два типа, уже можно сказать что единого ответа "где лучше" не существует.
    У каждого типа своя логика обработки. Но при этом, как только ты уложил в голове различия, эта логика становится совершенно очевидной:

    - Error exceptions почти никогда не ловятся через try-catch, по крайней мере на месте. За исключением редких исключительных ситуаций обработка ошибок производится в единой точке, обработчике ошибок
    - Business logic exceptions всегда ловятся через try-catch

    Отсюда мы видим, что

    - //PDOException при коннекте (эммм... я понимаю что пример, но блин, new PDO в конструкторе репы, серьёзно?ладно, мы сейчас не об этом) - это однозначно ошибка
    - //PDOException в запросе - это тоже ошибка, тут два раза думать не надо
    - условно пустое имя. Ну вот здесь мы уже переходим в область бизнес-логики. Коду тут без разницы, пустое имя, или полное. Это важно нам - программисту, пользователю.

    Но тут есть один, блин, тонкий момент.
    Валидация, по сути, пытается разорваться между всеми слоями приложения.
    С одной стороны, это функция Сущности (которую ошибочно называют моделью) - проверять валидность своих данных.
    С другой - если нам надо донести результаты валидации до пользователя, то как быть с переводами? Тащить в модель переводчик, серьёзно? Ну ок, ладно, возвращаем ключи для перевода. Хотя тоже как-то...
    Но вот проверка емейла на уникальность. Её-то где делать?
    В Сущности? И тащить в нее соединение с БД?
    На уровне БД? А где ловить тогда исключение? В сервисе? И ломиться через несколько уровней абстракции к сырому PDOException? Не вариант.
    Или, к примеру, для модели естественно проверять каждое поле отдельно, и кидать исключение. А для пользовательского интерфейса это неприемлемо - надо выдавать все ошибки валидации скопом, а не скармливать по одной.
    Вопросы...

    Но "где валидировать данные" - это отдельная тема, которая не относится напрямую к вопросу "где ловить ошибки".

    В данном случае я предлагаю оставить Сущность Юзер без валидации, а всю валидацию делать в сервисе.

    Хотя опять же - в современных фреймворках валидацию (Не будем показывать пальцем, но это был Ларавель) вообще делают еще до запуска контроллера, в миддлвари. Это кстати спорное решение, которое нарушает целостность модели. Если мы обращаемся к модели через другую точку входа, не контроллер, а, к примеру, создаем юзера через командную строку, то нам нужна точно такая же валидация. Запускать команды через мидлварь? В сущности, это мысль... Но всё равно, мы в итоге бизнес-логику размазываем между моделью и точками входа в неё, а это костыль.
    И при всём при этом оставлять Сущность Юзер совсем без валидации тоже как-то не комильфо... А если оставлять - то получится по сути дублирование кода.
    Вопросы, вопросы...

    Но вернемся к нашим баранам, в смысле юзерам.

    Начнем с того, что проверка имени на равенство пустой строке или нулю - это какой-то детский лепет (и кстати, почему ноль нельзя? вот у Маска ребеночка зовут X Æ A-12 - почему у кого-то не может быть имя "0.0"?).

    Отдельно побурчу насчет empty. Вообще, это один из самых сложных операторов, на нем спотыкаются все поголовно. В частности,
    function f($name){
        if (empty($name))...

    - это бессмыслица. Звучит, в переводе на русский, немного шизофренически: "пусть у нас будет переменная $name. Если у нас нет переменной $name...". Ну как нет, если мы только что ее в функцию передали?
    empty() проверяет переменную на существование И "пустоту". И в данном случае первая проверка будет бессмысленной. Никогда не надо писать бессмысленный код.
    Поэтому логичнее будет написать просто if(!$name). Хотя по нынешним временам это тоже говнокод. Что мы имеем здесь в виду? Имя не может быть пустой строкой? Пустым массивом? Нулём? null? false? А true или заполненный массив - это, получается, хорошее, годное имя?
    Лучше все-таки четче определять свои претензии. К примеру, проверять длину строки.

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

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

    class ValidationError extends Exception{ ... };
     
    class User
    {
        private string $name;
    
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    }
    
    class UserRepository
    {
        public function __construct(PDO $pdo)
        {
            $this->builder = $pdo;
        }
        public function add(User $user): User
        {
            $saved = $this->builder->query('INSERT INTO users (name) VALUES ("user")'); //PDOException
        }
    }
    
    class UserSerivce
    {
        private UserRepository $repository;
        private Validator $validator;
    
        public function new(array $data): User
        {
            $rules = [...] ;
            $errors = $this->validator->validate($data, $rules);
            if ($errors) {
                throw new ValidationException("", $errors);
            }
            $user = new User($data['name']); // в принципе, сучность может здесь бросить своё ValidationException
            return $this->repository->add($user);
        }
    }
    
    class UserController
    {
        private UserSerivce $service;
    
        public function store(array $data)
        {
            try {
                $user = $this->service->new($data);
            catch (ValidationError $e) {
                // рассказываем юзеру что он дурак
            }
            return redirect()->to('/' . $user->id);
        }
    }


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

    Как можно заметить, вот весь этот длинный и путанный текст посвящен исключительно ошибкам бизнес-логики.
    Поскольку с ошибками кода всё куда проще - единый хендлер тупо их обрабатывает в одном месте, как описано в статье по ссылке @Spartak-2205
    За исключением редких случаев, когда они ловятся по месту. Когда ошибка некритичная, или есть сценарий обработки - например, попробовать выполнить то же действие еще раз.
    Ответ написан
    3 комментария
  • Можно ли использовать die при валидации?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Просто разве это не защитит меня от человека, который просто поймёт как он генерируется.

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

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

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    1. Надо включать отображение ошибок РНР.
    Тогда ПХП тебе бы прямым текстом сказал, что в нет никакой переменной "priceMan". Хотя если смотреть на полный запрос, то скорее отсутствует parpage
    2. Надо использовать для запросов подготовленные выражения
    Тогда даже при отсутствии переменной не будет ошибки запроса. Не говоря уже про взлом сайта

    Даже такая параша, как тухлая фасоль, и то умеет в замещение переменных в запросе

    $params = [
    'min' => $_GET['priceMin'],
    'max' => $_GET['priceMax'],
    'cnt' => $cnt,
    'start' =>$start, 
    'perpage' =>$perpage,
    ]
    $idparam = '';
    foreach ($ids as $i => $item)
    {
        $key = ":id$i";
        $idparam .= $idstr? "," : "" . $key;
        $params[$key] = $item; 
    }
    $filterparam = '';
    foreach ($ids as $i => $item)
    {
        $key = ":f$i";
        $filterparam .= $filterparam? "," : "" . $key;
        $params[$key] = $item; 
    }
    
    
    
    $sql = "SELECT id, articul, category_id, brand_id, title, alias, content, price, old_price, status, keywords, description, img, hit, novinki  
    FROM product 
    WHERE status = '1' AND category_id IN ($idparam) 
    AND price > :min AND price < :max
    AND id IN (SELECT product_id FROM attribute_product WHERE attr_id IN ($filterparam) 
    GROUP BY product_id 
    HAVING COUNT(product_id) = :cnt)
    LIMIT :start, :perpage"
    
    $rows = \R::getAll($sql, $params);
    Ответ написан
  • Почему базовый класс ловит исключение?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Это очень плохой подход.
    Все делается ради красивости, а не для реальной пользы.
    FileWriteException может случиться примерно по 100500 разных причин.
    НИ ОДНА ИЗ НИХ не будет сообщена несчастному разработчику, который будет пытаться понять, ПОЧЕМУ не получилось файл записать. Ему, как в том анекдоте, будут говорить "слушайте свою песню Валенки!", вместо реального сообщения об ошибке.

    Кидать красивости можно на уровне файлового враппера, но при этом обязательно сохранять исходное сообщение об ошибке!

    public function write($filename, $data) {
        try {
            file_put_contents($filename, $data);
        } catch (Throwable $e) {
            $e = new FileWriteException($e->getMessage());
            $e->setName($filename);
            throw $e;
        }
    }
    Ответ написан
    6 комментариев
  • Как безопасно использовать WHERE?

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

    class Test {
        protected $where;
        protected $params;
    
        public function getAll()
        {
            $result=$this->db->prepare("SELECT * FROM table WHERE 1=1 ".$this->where);
            $result->execute($this->params);
            return $result->fetchAll(PDO::FETCH_ASSOC);
        }
    
        public function byDate($start,$end=false)
        {
            if ($end) {
                $this->where .= " AND data BETWEEN :start AND :end";
                $this->params['end'] = $end;
            } else {
                $this->where .= " date >= :start";
            }
            $this->params['start'] = $start;
            return $this;
        }
    
        public function byCol($col)
        {
            $this->where .= " AND col = :col";
            $this->params['col'] = $col;
            return $this;
        }
    }
    
    $sql = new Test;
    $data = $sql->byCol($col)->byDate($start)->getAll();


    по-хорошему тут еще должны быть отдельные переменные для самого запроса, для order by, limit и так далее
    Но начать можно с такого
    Ответ написан
    3 комментария
  • Освобождается ли память?

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

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

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

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

    Данные не бывают "опасными" или "безопасными" сами по себе.
    Всё зависит от контекста.
    А любая обработка "просто на всякий случай" тупо испортит данные.
    К примеру твоя strip_tags() изуродует математический текст, в котором встречаются символы "больше" и "меньше".

    Поэтому и надо форматировать данные перед использованием, в зависимости от конкретного контекста, а не заранее. Используем в SQL? Применяем подготовленные выражения. Используем в HTML? Применяем htmlscpecialchars. Используем в URL? Применяем urlencode. Используем в яваскрипте? Применяем json_encode. И так далее. Тебе уже самому должно быть смешно, глядя на этот набор "базовых проверок", если их накатывать все скопом.

    Плюс не надо путать форматирование данных и их валидацию.
    Валидация, в принципе, хорошая вещь, но надо понимать что во-первых, она не имеет никакого отношения к безопасности, и не может заменить контекстное форматирование данных, а во-вторых, уж тем более не может быть "универсальной" по определению.
    Ответ написан
    5 комментариев
  • Как сделать, чтобы при удалении записей остальные id записей начинались с 0?

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

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

    Либо тебе это поле вообще не нужно, и его надо убрать, либо просто оставь его в покое и никогда не трогай его руками
    Ответ написан
    1 комментарий
  • Покритикуйте код! Какие грубые и негрубые ошибки совершил?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Ну тут скорее ни одной почти строчки нормальной.
    • exit('Ошибка подключения к базе данных!'); дважды глупость. Пользователю сайта не интересно читать, что у тебя сломалось - база данных или деньги на пиво кончились. Как программисту, тебе эта бессмысленная фраза тем более бесполезна, она ничего не говорит о том, ЧТО КОНКРЕТНО сломалось, чтобы ты мог исправить
    • if ($numRows > 0) { бессмысленный кусок кода
    • while ($row = $result->fetch_assoc()) { заменяется на $result->fetch_all(MYSQLI_ASSOC)
    • $this->connect() коннектимся каждый раз, чтобы выполнить запрос, серьёзно?
    • А когда будет еще один класс, для другой таблицы, снова будешь писать код подключения к БД? И так в каждом?
    • Почему класс для работы с "позициями" называется DBh?
    • По сути это не класс, а набор функций. Если ты уберешь красивые слова class и this, то НИЧЕГО не изменится
    • SQL инъекции кругом
    • class Handler extends Dbh ВООБЩЕ непонятно зачем



    В общем, как-то так
    dbh.php
    class Dbh
    {
        public $conn;
    
        public function __construct($config)
        {
            mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
            $this->conn = new mysqli(...$config);
            $this->conn->set_charset('utf8mb4');
        }
    
        public function preparedQuery($sql, $params, $types = '')
        {
            $types = $types ?: str_repeat('s', count($params));
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            return $stmt;
        }
    
        public function selectResult($sql, $params, $types = '')
        {
            if (!$params) {
                return $this->conn->query($sql);
            }
            return $this->preparedQuery($sql, $params, $types)->get_result();
        }
        public function selectAll($sql, $params = [], $types = '')
        {
            return $this->selectResult($sql, $params, $types)->fetch_all(MYSQLI_ASSOC);
        }
        public function selectAssoc($sql, $params = [], $types = '')
        {
            return $this->selectResult($sql, $params, $types)->fetch_assoc();
        }
        public function selectRow($sql, $params = [], $types = '')
        {
            return $this->selectResult($sql, $params, $types)->fetch_row();
        }
        public function selectCell($sql, $params = [], $types = '')
        {
            $row = $this->selectRow($sql, $params, $types);
            return $row ? $row[0] : false;
        }
    }

    position.php
    class Position
    {
        protected $dbh;
    
        public function __construct(Dbh $dbh)
        {
            $this->dbh = $dbh;
        }
        // Получаем все позциии из БД и возвращаем их в массиве $output если записей больше нуля
        public function getAllPositions()
        {
            return $this->dbh->selectAll('SELECT * FROM positions');
        }
        protected function addPosition($content)
        {
            $count = $this->dbh->selectCell('SELECT count(*) FROM positions');
            if ($count < 10) {
                $this->dbh->preparedQuery("INSERT INTO positions (content) VALUES (?)", [$content]);
            }
        }
        protected function deletePosition($id)
        {
            $this->dbh->preparedQuery("DELETE FROM positions WHERE id = ?", [$id]);
        }
        //Поиск позиций в БД по столбцу content
        protected function searchPosition($content)
        {
            $content = "%$content%";
            return $this->dbh->selectAll('SELECT * FROM positions WHERE content LIKE ?',[$content]);
        }
    }

    config.php
    return [
          'db' => [
              'host' => '127.0.0.1',
              'username' => '',
              'password' => '',
              'dbname' => '',
              'port' => 3306,
          ],
      ];


    handler.php

    $config = require 'config.php';
    $dbh = new Dbh($config['db']);
    $position = new Position($dbh);
    
    switch ($_GET['action']) {
        case 'getpositions':
            $output = $position->getAllPositions();
            echo json_encode($output);
            break;
        case 'addposition':
            $content = $_GET['content'];
            $position->addPosition($content);
            break;
        case 'getsearchpositions':
            $content = $_GET['content'];
            $output = $position->searchPosition($content);
            echo json_encode($output);
            break;
        case 'deleteposition':
            $id = $_GET['id'];
            $position->deletePosition($id);
            break;
        default:
            header("HTTP/1.0 400 Bad Request");
    }
    Ответ написан
    2 комментария
  • Как на развернуть весь сайт в index.php?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Сейчас в этом коде все поставлено с ног на голову.
    Я так понимаю, что всё затевается ради того, что "Шапка и футер сайта у меня везде одинаковые"
    И сначала идет шапка, потом этот матч, а потом футер.
    То есть у нас код начинается с вывода HTML, в то время как это должно быть самое последнее, что происходит в скрипте.
    А всё должно быть строго наоборот - сначала должна выполняться обработка данных РНР кодом, и только потом начинаться вывод HTML.

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

    Для начала надо сделать вот так, phpfaq.ru/tech/tpl#example

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

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    В цикле.
    Все операции над массивами делаются в цикле.

    Если ты не знаешь, как перебрать в цикле массив чисел, тебе надо учить циклы, а не ООП.
    Ответ написан
    Комментировать
  • Как запретить вывод ошибок 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 используется стандартная обработка запросов, которая входит по умолчанию в любой веб-сервер (в том числе апач)
    Ответ написан
    Комментировать