• Как загрузить файл по sftp в php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Мне нетрудно скопировать пример из документации
    <?php
    $connection = ssh2_connect('shell.example.com', 22);
    ssh2_auth_password($connection, 'username', 'password');
    
    ssh2_scp_send($connection, '/local/filename', '/remote/filename', 0644);

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

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Странно, какой разительный контраст с кодом из удаленного вопроса.
    Я уж хотел вспомнить молодость, поумиляться глубокомысленному коду $post = !empty($_POST) ? true : false;...
    Но с другой стороны, в удаленном коде было непонятно, почему вообще письмо уходит, а здесь уже гораздо ближе к реальности.
    обратить внимание надо, во-первых, на тег
    <form action="#" id="form_body" class="form">
    и посмотреть в примерах, что туда пишут.
    После этого вывести результат var_dump($_POST); и внимательно его изучить.
    После этого снова вернуться к форме и подумать, чего в ней не хватает

    Ну и разумеется выкинуть часть с else if ( $method === 'GET' ) {
    Ответ написан
    9 комментариев
  • Код php в другом блоке не отображает переменную из текущего блока?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    • Открываем исходный код страницы по Ctrl-U и с удивлением видим там свое <? $a=1; ?> прямо в браузере.
    • После этого вспоминаем, что простой открывающий тег РНР (в отличие от сокращенного echo) пишется как <?php
    • Исправляем первый блок
    • Всё работает


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

    чтобы значение переменной было видно внутри функции, её надо передать в виде параметра
    function myfunc($a) {
        echo $a;
    }
    $a = 1;
    myfunc($a);


    Ну или присвоение значения переменной происходит внутри условия, которое не выполняется.

    Если выкладываете не реальный код, который у вас не работает, а какие-то каракули от балды, то всегда сначала протестируйте, сохраняется ли в этих каракулях ваша проблема
    Но лучше всегда выкладывать реальный код.
    Ответ написан
  • Как экранировать sql запрос внутри texarea?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это очень просто сделать.
    Надо всего лишь освоить подготовленные выражения.
    Например, почитав вот тут https://habr.com/ru/articles/662523/

    И все запросы, в которых участвуют переменные, выполнять только таким образом.
    А texarea там, или tinymce - это уже без разницы.
    Ответ написан
    1 комментарий
  • Телеграм бот, inline_keyboard - не отправляет запроса webhook на сервер?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    На чистом РНР (если закрыть все скобки в этом огрызке кода), все прекрасно отображается и отправляется.
    $resp = [
                'chat_id' => $chat_id,
                'text' => 'Вы находитесь в главном меню',
                'reply_markup' => json_encode([
                    'inline_keyboard' => [
                        [
                            [
                                'text' => 'refresh',
                                'callback_data' => 'LALALALA'
                            ]
                        ],
                        [
                            [
                                'text' => 'LALALALA',
                                'callback_data' => 'LALALALA'
                            ]
                        ]
                    ]])];
    $url = "https://api.telegram.org/bot$bot_token/sendMessage?".http_build_query($resp);
    file_get_contents($url);

    При условии, разумеется, что передается корректный chat_id. Но если будет неправильный chat id, то тогда клавиатура вообще не отобразится, и тогда именно это было бы проблемой, а не вебхук.

    Попробуйте сначала сформулировать, с чего вы взяли, что "не отправляет запроса вебхук на сервер".

    Но в целом, я предполагаю что главная ваша проблема, конечно же - в отсутствии логирования.
    Я не представляю, как вообще люди берутся писать ботов без базового логирования, которое включает
    1. Сырой инпут, который пришел на вебхук.
    2. Сырой запрос, отправленный в телегу
    3. Разумеется, все ошибки РНР.
    4. Разное другое отладочное логирование.
    Ответ написан
    9 комментариев
  • Почему кириллица неправильно отображается?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    В заголовке Content-Type надо также указывать и кодировку.
    Разумеется, в Питоне указывать любую кодировку кроме UTF-8 совершенно бессмысленно.
    Соответственно, заголовок должен быть
    Content-Type: text/html; charset=utf-8
    Плюс в первом принте лишние символы.
    Я не очень понимаю, какой софт используется, но в целом вот такой код выведет в нужном порядке - заголовок, пустая строка, две строки одна под другой
    print("Content-Type: text/html; charset=utf-8\r\n")
    
    print("Hello world!<br>")
    print('Привет мир!')
    Ответ написан
    1 комментарий
  • Как осуществить поиск слов из БД со стороны пользователя?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Понимаете, ваш вопрос звучит так: "Я тут надеваю ботинки. Как осуществить завязывание шнурков?"
    Работа с БД - это 99% кода любого сайта. Тем более такие простые запросы.
    Получается, что вы в принципе не понимаете, как разрабатывать сайты, и вам надо учиться делать именно это.
    То есть, вам надо взять учебник или какое-нибудь руководство. И учиться разрабатывать сайты. А не спрашивать, "как осуществить поиск слов".

    Но чисто для примера, для всех современных версий РНР, будет работать такой код

    <?php
    $word = $_GET['word'] ?? '';
    
    if ($word) {
        require 'db.php';
        $sql = "select * from dictionary where word=?";
        $stmt = $db->prepare($sql);
        $stmt->execute([$word]);
        $row = $stmt->fetch_assoc(); //  для PDO  будет просто fetch()
        echo $row['translation'];
    }


    в db.php, соответственно, код подключения к БД. Взять можно, например, отсюда https://habr.com/ru/articles/662523/

    Чтобы в РНР появилась переменная $_GET['word'], надо сделать форму в HTML. Хотя бы про это, я надеюсь, вам не надо рассказывать?
    Ответ написан
    Комментировать
  • Функция move_uploaded_file выдает ошибку 0, что делать?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    0 - это не ошибка, а какая-то фигня.
    Ошибка - это Warning, который генерирует эта функция, если не может выполнить свою работу.
    Чтобы увидеть эту ошибку на экране, надо включить вывод ошибок РНР на экран, display_errors
    Если ошибки выводить на экран нельзя, то их надо смотреть в логе.

    Чтобы узнать, что делать, надо прочесть сообщение об ошибке
    Ответ написан
  • Почему при удалении куки возникает ошибка Warning: Cannot modify header information?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Чтобы решить эту проблему, надо научиться пользоваться интернетом.
    В частности, освоить такой сложный навык, как взять сообщение об ошибке, вставить в адресную строку своего браузера, и нажать enter
    И после этого с удивлением обнаружить, что объяснений этой ошибки существует несколько миллионов.
    Например https://ru.stackoverflow.com/questions/284578/

    И заодно не помешает научиться задавать вопросы. Чтобы не спрашивать про то, что вы и так знаете.
    Ответ написан
    4 комментария
  • Как хранить условия в БД?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Хранить виде json, в котором предусмотрены поля для всех возможных критериев. Например weekday.
    При отображении считывать это поле и по нему вычислять скидку.
    Для поиска периодически производить перерасчет
    Пример не вижу смысла писать.
    Ответ написан
    Комментировать
  • Как закодировать 5-6 значное число в 3х символьную буквенно-числовую последовательность и с обратным декодированием?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ну, три символа - это вы "очень много кушать", а 4 - без проблем
    php.net/base_convert
    Ответ написан
    Комментировать
  • Что делать если не работает редирект header?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Сначала надо включить отображение ошибок (или научиться искать их в логах сервера)
    Затем собственно увидеть сообщение об ошибке и прочитать его
    Затем, поскольку оно довольно непонятное, найти любое из существующих объяснений этой ошибки, благо их понаписали уже десятки миллионов.
    Далее надо прочитать это объяснение и постараться понять, что такое НТТР заголовки и как с ними работать

    Cannot modify header information.... Как исправить?
    https://phpfaq.ru/newbie/headers
    https://ru.stackoverflow.com/questions/284578/cann...
    Ответ написан
    2 комментария
  • Как корректно обработать строку запроса типа catalog/aloe/aaaa, если третий параметр в роутинге не предусмотрен (только /)?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    "отображается без стилей" потому что надо всегда использовать абсолютные пути, а не относительные.
    Хотя странно, в этом случае должно косячить либо с одним параметром в урл, либо с двумя.
    Но абсолютные пути от корня сайта вместо всех этих точечек в HTML надо в любом случае прописать. Почитать что это такое можно здесь https://phpfaq.ru/newbie/paths
    Ответ написан
    1 комментарий
  • Ошибка при JSON.parse как исправить?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    А вы можете объяснить, зачем вам здесь вообще JSON.parse?
    И почему нельзя написать просто
    var dataJSONArray = <?= json_encode($u,JSON_UNESCAPED_UNICODE) ?>;
    Ответ написан
    1 комментарий
  • Файл конфига php?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Очень хороший вопрос, только вы путаете файл с настройками и файл первоначальной настройки приложения.
    Вам нужны оба.
    1. файл c настройками
    Их должно быть два.
    Первый файл называется config.sample.php, он содержит только один массив, который заполняется пустыми/дефолтными значениями и может содержать не только настройки БД но и содержать другие секции:
    <?php
    return [
      'db' => [
        'hostname' => '',
        'username' => '',
        'password' => '',
        'database' => '',
      ],
    ];

    Этот файл добавляется в репозиторий.

    Второй файл называется config.php и он создается руками каждый раз при установке CMS на новом сервере. В него пишутся актуальные настройки для каждого сервера.
    Этот файл не добавляется в репозиторий (а добавляется, соответственно, в .gitignore).

    2. Файл первоначальной настройки приложения.
    В него идут команды, которые пишутся на любой странице: подключение к БД, старт сессии, всякие инклюды и прочее. Кроме того, в этом файле должен быть код
    if (!file_exists('config.php'))
     {
         $msg = 'Создайте файл config.php на основе config.sample.php и внесите в него настройки';
         throw new RuntimeException($msg);
     }


    Таким образом система будет помогать программисту, если он забыл создать config.php с актуальными для конкретного сервера настройками.

    И вот этот файл, назовем его init.php, уже и подключаем во все остальные файлы.

    Кстати, начиная с 8 версии РНР можно писать просто
    $conn = mysqli_connect(...$config['db']);
    В этом случае ключи массива $config['db'] будут использоваться в качестве имен параметров функции - очень удобно
    Ответ написан
    Комментировать
  • Как сформировать AJAX запрос для базы данных?

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

    Сначала надо добавить одну запись в БД руками.
    Потом так же в БД учиться писать запрос SELECT
    потом учиться выполнять SQL запросы в РНР.
    потом учиться получать результат SQL запроса в массив.
    потом учиться выводить многомерный массив
    потом учиться выводить многомерный массив в виде требуемого HTML, чтобы получить свою таблицу
    после этого можно сесть и отдохнуть.

    И после хорошего отдыха начать учиться работать с формами в HTML
    и как их обрабатывать в РНР
    написав в итоге код для добавления данных формы в БД

    и только после этого, если силы останутся, навешивать рюшечки в виде запроса и обновления аяксом
    Ответ написан
  • Как перенаправлять пользователя, если возникла ошибка 500?

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

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

    Поэтому куда проще (и удобнее) настроить обработчик ошибок в РНР, и для 99.99% ошибок он будет показывать нужный HTML сам.
    Для этого понадобятся функции set_exception_handler() и register_shutdown_function()
    примеров реализации море, например здесь: https://phpdelusions.net/articles/error_reporting#code
    Только error handler на самом деле не нужен, потому что не фатальные ошибки не вызывают 500-ю ошибку и могут просто логироваться автоматом, без всякого хендлера.
    Ответ написан
  • PHP header('Content-Disposition: inline - почему не работает?

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

    Собака зарыта в том, что Content-Disposition: inline не имеет смысла с filename=file.htm, Никакое имя в адресной строке этот заголовок не поменяет и никогда не делал ничего даже близко к этому.

    Изменить адрес во время обращения сервер уже не может. Можно или сообщить клиенту, чтобы он запросил другой адрес (что делает совсем другой заголовок - Location), но в этом случае скрипт ничего не может вывести, или клиент должен был сразу запрашивать file.htm, а сервер при этом будет выполнять script.php
    Ответ написан
  • Почему шифруются данные в БД mysql?

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

    1. ini_set('display_setup_errors', 1); надо убрать вообще, это бессмысленный карго-культ
    2. ini_set('error_reporting', E_ALL); и ini_set('display_errors', 1); надо вынести в общий файл, который инклюдится во все остальные. Иначе на бою придется редактировать в каждом файле, чтобы заменить 1 на 0.
    3. empty после trim надо убрать, проверять на существование заведомо существующее значение не имеет смысла. То есть, переписать так
      if(trim($_POST['user_name']) && trim($_POST['user_email']) && trim($_POST['user_password']))

      Но и это будет неправильно, поскольку trim не применяется к добавляемым в БД значениям
      То есть, потримать отдельно в переменные, а потом проверить просто
      if($user_name && $user_email && $user_password)

    4. проверка if(isset($_SESSION['user_data'])) явно не на месте. А если форма запрошена не постом? Показывать её уже авторизованному пользователю? Зачем?
    5. после header('Location: '); всегда должен идти exit. в данном случае не принципиально, но это должно делаться на автомате.
    6. _once из require_once надо убрать вообще, это бессмысленный карго-культ
    7. require('database/ChatUser.php'); - это стыдоба. Сделайте простенький автозагрузчик, это три строчки. Например
      spl_autoload_register(function ($className) {
          $ds = DIRECTORY_SEPARATOR;
          $className = str_replace('\\', $ds, $className);
          $filename = __DIR__ . "{$ds}..{$ds}database{$ds}$className.php";
          require($filename);
      });
      автозагрузчик тоже кладется в общий подключаемый файл.

    8. проверку if($user->saveData()) надо убрать вообще, это бессмысленный карго-культ, и - вдобавок - ошибка. Если POST запрос был обработан без ошибок, то после него всегда должен быть редирект, без всяких success_message. А "Something went wrong" выводится совсем другим кодом. Я ещё посмотрю в database, но если что, то исправлять надо будет там
    9. вывод сообщений об ошибках в хтмл части лучше сделать в едином стиле
      <? if($errors !== ''): ?>
          <?=htmlspecialchars($errors) ?><br><br>
      <? endif ?>

    10. хорошим тоном считается при ошибке выводить пользователю уже введенные значения (кроме пароля, разумеется)
      <input type="text" name="user_name" value="<?= htmlspecialchars($user_name ?? '') ?>">



    Так, в database более серьезные ошибки.
    В целом неплохой ActiveRecord, но в конструкторе прям всё очень плохо.
    1. В обязательном порядке переделать
      • Во-первых, require в коде класса - это сразу профнепригодность. Всю необходимую информацию класс должен получать только через методы.
      • Во-вторых, new DatabaseConnection в каждом конструкторе - это совсем детская ошибка. Давно TOO MANY CONNECTIONS от mysql не получали?

      Этот класс должен принимать уже созданное соединение, через параметр конструктора.

    2. createAvatar я бы вынес в отдельный класс
    3. Непонятно, зачем вам вообще понадобился цикл foreach ($params as $key => $value), если проще и удобнее написать $statement->execute($params); Для кого специально этот функционал создатели PDO писали?
    4. return $user_data; после условия - это логическая ошибка. Будет undefined variable $user_data если условие не выполнится. Но главное, что здесь все неправильно изначально. Никаких проверок быть в принципе быть не должно.


    DatabaseConnection

    Тут две основные ошибки, не буду уж нумеровать

    • Во-первых, данные для подключения к БД (как и другие, отличающиеся для разных окружений настройки) пишутся в отдельном файле, который не добавляется в систему контроля версий (пишется в .gitignore). И, соответственно, никаких констант, а обычные параметры конструктора. И в этом контексте становится непонятно, зачем вообще нужен класс DatabaseConnection, если все что он делает - это создает инстанс PDO? Правильно, он становится совершенно не нужен
    • Во-вторых, и самое главное - в PDO не включен режим информирования программиста об ошибках. Я даже не представляю, у какого инфоцыгана вы брали этот код - уже, вроде бы, даже до самых тупых из них дошло, что оставлять программиста без сообщений об ошибках - это садизм. Поэтому при создании инстанса ПДО надо в обязательном порядке включать режим информирования об ошибках. Для этого добавить еще один параметр в виде массива, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]; и пока оставить так. А потом, со временем, добавить к проекту централизованный вывод сообщения "что-то пошло не так"

    Ответ написан
    Комментировать
  • Как в bahs скопировать данные ответа программы, вставив часть его в следующий шаг?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Непонятно что здесь непонятно и почему стоит сложность высокая.
    "Скопировать данные ответа программы" это стандартно OTVET=$(programma)
    "взять часть его" - это grep или там cut
    Ответ написан