Задать вопрос
  • Могу ли я прогнать через password_hash пароли в бд, которые md5, чтобы не сломалась авторизация?

    @alexalexes
    Смену способа хеширования пароля вы можете провернуть только при участии каждого пользователя, в два этапа.
    1 этап.
    Делаете патч в функцию авторизации.
    Когда пользователь авторизуется, проверяете, что заполнено поле по хешу новой функции.
    Если оно заполнено по новой функции, то все проверки верности пароля проводите с ней, поле старой функции игнорируете.

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

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

    402d
    @402d
    начинал с бейсика на УКНЦ в 1988
    <?php
    $mysecret = 'supersecret';

    Минимальный совет из "PHP Правильный путь" звучит как храните свои конфиги хотя бы в виде php файлов.
    Предположим, что мы сохранили такой скрипт в корне www.
    При правильной настройке сервера посетитель увидит пустой экран по урлу //your.site/script.php
    так как в нашем файле нет команд вывода.
    В первой строке полный синтаксис, в варианте "<?" может случиться ситуация показа исходного текста, если сшорт таги отключены. И остается риск того, что php отвалиться и будет показываться исходный код.

    Обще принятой практикой сейчас считается подход, когда все исходные файлы лежат выше диретории www рут.
    В самой директории только один скрипт точки входа (index.php)

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

    Вы используете eval c данными от пользователя или на сайте можно загружать через форму файлы.
    На шаред хостинге ошиблись с разделением прав для ftp.

    У Вас используются системы контроля версий кода и конфиги не добавлены в игнорируемые.
    Ответ написан
  • Как мне защитить файл подключения к бд?

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

    Никакой проблемы в том, что "на этот файл можно попасть с помощью обычной ссылки" нет. Надо забыть про эти нелепые страхи, и начать защищаться от "инъекций", которые представляют реальную опасность, а не выдуманную. Тем более что сделать это несложно.
    Ответ написан
    1 комментарий
  • Как добавить данные в бд с помощью php sqlsrv?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Самое главное, чему надо научиться - это правильно формулировать свои проблемы.
    Судя по приведённому коду, вы прекрасно знаете, как добавлять данные. Но почему-то всё равно спрашиваете, как это сделать. "Где логика, где разум?"
    Судя по тексту вопроса, проблема ваша формулируется совсем по-другому: не "как добавить", а "почему не добавляется". Это два совершенно разных вопроса.

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

    1. Убедиться, что в РНР включён вывод ошибок. Проверить можно тупо допустив ошибку синтаксиса. Если она выведется - очень хорошо, значит вы видите ошибки. Если нет, то включить, хотя бы через ini_set.
    1.2. Для древних, как гуано мамонта расширений, таких как sqsrv, надо проверять ошибки запросов вручную. Но делать это надо с умом, а не как в соседнем ответе. Ошибку SQL надо не тупо вываливать на экран вручную, а превратить в ошибку РНР, чтобы она выводилась так же и туда же, куда и остальные ошибки. Это можно сделать простым кодом вида
    if( $stmt === false ) {
        throw new Exception(print_r( sqlsrv_errors(), true));
    }

    2. Упростить свой код. Всегда проверять что-то одно. Вы что хотите проверить? Выполнение запроса на вставку? А зачем вам тогда форма вообще? Сделайте скрипт, который при обращении к нему просто записывает данные в БД, без всяких форм и прочего.
    Работает? Очень хорошо, переходите к формам. И если что-то не будет работать, то и вопрос будет совсем другой, "у меня не работает форма", который к "как сделать запрос" уже совсем никакого отношения не имеет.
    Не работает? Разбирайтесь с запросом, без всяких форм. Если вы проверяете что-то одно, то у вас и не работает что-то одно. А не десять разных потенциальных точек отказа.
    3. Контролировать ход выполнения своего кода.
    Например, вот вы разобрались с запросом, и перешли к обработке формы. И вот у вас есть условие, if (isset($_POST['signInButton'])). А вы проверили, оно хоть выполнилось? Если нет, то в базу никогда ничего не добавится, хоть обперегружайся. Поэтому добавляете временный вывод отладочной информации:
    echo "проверяем нажатие кнопки\n";
    if (isset($_POST['signInButton'])) {
        echo "проверка прошла успешно\n";
        createAccount($conn, $email, $password, $keepSignIn);
    }

    Если "проверка прошла успешно" не вывелось - значит никакого $_POST['signInButton']) в вашем скрипте нет, и надо разбираться - почему. Например, в форме не указан метод, или кнопка называется совсем по-другому. Чтобы разобраться с этим, надо
    3.1 Выводить содержимое используемых переменных. Делаете
    var_dump($_POST);
    после отправки формы, и смотрите. Если там совсем пусто, значит никакую форму методом POST вы не отправляли. Если там что-то есть - то смотрите, что именно, и насколько это соответствует вашим ожиданиям.

    Вот и всё. Эта нехитрая инструкция позволяет быстро решить любые проблемы с кодом. Главное потом не забыть удалить все отладочные сообщения. или научиться пользоваться пошаговой отладкой в IDE
    Ответ написан
    1 комментарий
  • Как отследить кнопку "назад" на телефонах?

    Опишу только принцип, реализацию уже сделаете сами, либо попросите AI.

    Кнопка "назад" работает просто: переводит браузер на предыдущий урл.

    Это можно использовать. Вы же, наверняка, используете history API в вашем приложении.
    Так вот, при открытии модального окна добавляйте хэш к адресу в history.

    https://example.com/page // окна нет
    https://example.com/page#modal1 // окно открыто


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

    Ваша программа должна добавлять к текущему адресу хэш при открытии окна, и закрывать окно, когда хэш из адреса убирается.
    Ответ написан
    Комментировать
  • Как сделать отправку OTP-код по почте через mailtrap.io?

    @Everything_is_bad
    Для диплома не нужен реальный SMS, пиши эмуляцию или шли на почту. А еще лучше сделай TOTP-код через гугл аутентификатор или другой подобный софт.
    Ответ написан
  • Изучение php с нуля для верстальщика?

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

    Лучше потратьтесь на книжку, Джон Дакетт, PHP&MySQL. Там очень толково, на примерах даётся не только язык, но и все важные аспекты программирования - обработка ошибок, отладка, рефакторинг, структура приложения, SQL, обработка изображений, и куча всего остального. В последних главах весь материал даётся на примере создания простой но рабочей социальной сети.
    Ответ написан
    1 комментарий
  • Как будет правильно создать блоки в виде треугольников в шапке?

    Ответ написан
    Комментировать
  • Как сделать правильную табуляцию в html?

    Ситуация следующая: нет никаких официальных стандартов оформления HTML. Это в документации HTML нигде не прописано. Потому что для экономии трафика вообще нежелательно, чтобы в передаваемом body были лишние символы, не несущие никакой функциональности. Лишние пробелы между тегами вообще не учитываются браузером.

    Исходя из этого можно заключить, что любые style guides, которых придерживаются программисты, - это просто соглашение, действующее в рамках какой-то одной организации либо сообщества. Вы устраиваетесь на работу и там вам дадут документ либо конфигурационный файл, в котором будут перечислены все правила, которых придерживаются в данной организации: 2, 4, 8 пробелов, символ табуляции, полное отсутствие пробелов между тегами. И вот этих правил надо придерживаться.

    Таким образом, в вашей ситуации случилось одно из двух:
    • преподаватель изначально дал вам список всех правил, но вы просто забыли об этом либо пропустили это занятие. Тогда преподаватель прав, и вам надо уточнить у него весь этот список правил и сказать, что больше так не будете.
    • преподаватель не дал вам этот список, поэтому, если у вас во всём проекте одинаковое количество пробелов в отступах в HTML, то правы вы, и вы можете потребовать от преподавателя предоставить вам список правил, которые он требует, и вежливо пояснить ему, что он не прав, критикуя вас за выбор количества пробелов без предварительного предоставления подробных style guides.
    Ответ написан
  • Чем отличается функция от конструктора и где применять то или это?

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

    И вот в один момент разработчики спецификации ECMA-script решили, а давайте мы всё же оправдаем первые 4 буквы в названии языка, а именно "Java", и дадим пользователям сахарок, нарисованный над нашим прототипным наследованием, чтобы они могли везде писать class, extends и implements, как и все остальные ООП-динозавры. И сделали это.

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

    class ClassWithPrivate {
      #privateField;
      publicField;
    
      constructor() {
        this.#privateField = "Доступ только изнутри класса";
      }
    }
    
    const instance = new ClassWithPrivate();
    
    instance.publicField = "Доступ извне класса";
    instance.#privateField; // Ошибка: SyntaxError: Private field '#privateField' must be declared in an enclosing class


    Еще одной особенностью конструктора является то, что он активно используется при наследовании (крестится и плюётся через левое плечо от отвращения). Если в дочернем классе не описан свой конструктор, то будет использован конструктор родителя. Это упрощает ООП.

    class Animal {
    
      constructor(name) {
        this.speed = 0;
        this.name = name;
      }
    
      run(speed) {
        this.speed = speed;
        alert(`${this.name} бежит со скоростью ${this.speed}.`);
      }
    
      stop() {
        this.speed = 0;
        alert(`${this.name} стоит.`);
      }
    
    }
    
    class Rabbit extends Animal {
      hide() {
        alert(`${this.name} прячется!`);
      }
    
      stop() {
        super.stop(); // вызываем родительский метод stop
        this.hide(); // и затем hide
      }
    }
    
    let rabbit = new Rabbit("Белый кролик"); // используется конструктор родителя
    
    rabbit.run(5); // Белый кролик бежит со скоростью 5.
    rabbit.stop(); // Белый кролик стоит. Белый кролик прячется!


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

    Wispik
    @Wispik
    Как сделать такое же окно

    для этого нужно использовать html+css+js
    Ответ написан
    Комментировать
  • Как сделать окно, как на скрине?

    Steel_Balls
    @Steel_Balls
    для этого нужно использовать html+css+js + AJAX -> backend (Golang, C#, PHP, NodeJS...)
    Ответ написан
    Комментировать
  • Почему метод не работает?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Во втором случае функцию в data вы не вызываете:
    data().init
    Ответ написан
    2 комментария
  • Как кучу файлов с дампами таблиц соединить в один?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Эх, молодёжь...
    copy *.sql fulldump.sql
    Ещё во времена MS-DOS можно было
    Ответ написан
    1 комментарий
  • Почему в ответе скрипта появляется закрывающий тег РНР?

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

    Человек с адекватным восприятием реальности сделает очень простое умозаключение: если в ответе появляются посторонние символы, то это значит, что они присутствуют в скрипте. После этого найдет эти символы и удалит. Тупо проверив все файлы, которые участвуют в обработке запроса.
    А для неразрешимой проблемы "почему на локалке посторонних символов нету" найдет простое рациональное объяснение: файлы "на локалке" и "не на локалке" отличаются.

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

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

    файл init.php
    <?php
    $conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASSWORD);  
    $conn -> setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 
    
    set_exception_handler(function ($e)
    {
        http_response_code(500);
        error_log($e);
        echo json_encode([
                'code' => 'error',
                'message' => 'Internal server error'
        ]);
    });

    файл с кодом
    <?php
    // Подключаемся к базе данных
    require 'init.php';
    
    // Получаем данные
    $list = get_list($conn);
    
    echo json_encode([
        'code' => 'success',
        'data' => $list
    ]);


    Без всей этой кропотливой возни и самоповторов.
    Отсутствие данных ошибкой не является. В JS можно проверить массив data и вывести сообщение, что он пустой. Никакой специальный код для этого передавать не нужно.
    А настоящие ошибки надо обрабатывать единообразно, в одном месте. А не писать обработку после каждой строчки, причем каждый раз по-разному.
    Ответ написан
    3 комментария
  • Как правильно задать запрос UPDATE где название столбца переменная?

    Anastasia2306
    @Anastasia2306
    PHP-разработчик.
    Как насчет оператора CASE?

    $sql = "UPDATE `list` 
            SET count1 = CASE WHEN id = ? AND ? = 1 THEN count1 - ? ELSE count1 END,
                count2 = CASE WHEN id = ? AND ? = 2 THEN count2 - ? ELSE count2 END,
                count3 = CASE WHEN id = ? AND ? = 3 THEN count3 - ? ELSE count3 END
            WHERE id = ?";
    
    $stmt = $conn->prepare($sql);
    
    foreach ($data as $id => $value) {
        $idParts = explode("-", $id);
        $count = $value['count'];
        $stmt->execute([$idParts[0], $idParts[1], $count, $idParts[0], $idParts[1], $count, $idParts[0], $idParts[1], $count, $idParts[0]]);
    }


    Здесь используется оператор CASE для обновления нужного столбца в зависимости от значения $idParts[1]. Если $idParts[1] не соответствует ни одному из условий, то значение столбца остается неизменным. Ну и не забываем про подготовленный запрос prepare чтобы избежать возможной инъекции
    Ответ написан
    7 комментариев
  • Как распознавать в php слова (типо систем компьютерной алгебры)?

    @alexalexes
    Берете любую вузовскую методичку по дисциплине "Теория языков программирования и методов трансляции".
    Изучаете, с чем едят грамматики формальных языков, строите лексический анализатор, синтаксический анализатор, транслятор в свой машинный код, исполнитель машинного кода.
    На выходе у вас должна получиться вот такая штука:
    https://studfile.net/preview/937093/
    Ответ написан
    Комментировать
  • Dadata - как получить ближайший город?

    yesbro
    @yesbro
    Думаю, помогаю думать
    Тебе от дадата возвращается полная информация об выбранном объекте. Из него ты можешь получить информацию об области/крае и вывести ее/выбрать.

    https://dadata.ru/api/suggest/address/

    region_with_type - название области/края/региона

    А это уникальные ID которые можно использовать для группировки объявлений

    data.region_fias_id	ФИАС-код региона
    data.region_kladr_id	КЛАДР-код региона
    data.region_iso_code	ISO-код региона
    Ответ написан
    Комментировать
  • Запрос mysql, как объединить сообщения в чаты?

    @alvi31182v
    GROUP BY GROUP_CONCAT для объединения сообщений в одну строку, упорядоченную по времени т.е если у тебя есть поле timestamp или msg_time если ты не хочешь использовать chat_id, то можно попробовать сделать следующий запрос

    GROUP BY chat_id - таким образом, строки с одинаковым chat_id будут объединены в одну группу

    "Функция LEAST выбирает минимальное из значений. Значениями могут выступать поля, а также строки и числа"
    "Функция GREATEST выбирает максимальное из значений / помогает упорядочивать пары пользователей"

    Комбинация LEAST и GREATEST гарантирует уникальность групировки чатов игнорируя порядок пар пользоваталей чатов.
    Вобщем есть набросок, дальше можно уже самому накидать и поиграться.
    $sql = "
        SELECT 
            MIN(from_user_id) as user1,
            MAX(from_user_id) as user2,
            chat_id,
            GROUP_CONCAT(msg ORDER BY msg_time) as messages
        FROM
            class_chat
        WHERE
            (from_user_id = :user1 AND to_user_id = :user2)
            OR
            (to_user_id = :user1 AND from_user_id = :user2)
            OR
            (from_user_id = :user3 AND to_user_id = :user4)
            OR
            (to_user_id = :user3 AND from_user_id = :user4)
        GROUP BY
            chat_id, LEAST(from_user_id, to_user_id), GREATEST(from_user_id, to_user_id)
    ";
    
    $stmt = $pdo->prepare($sql);
    
    $stmt->execute([
        ':user1' => 111, // тут айдишники пользаков
        ':user2' => 222,
        ':user3' => 333,
        ':user4' => 444,
    ]);
    
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        // Обработка результата
        echo "Chat ID: " . $row['chat_id'] . "\n";
        echo "User 1: " . $row['user1'] . "\n";
        echo "User 2: " . $row['user2'] . "\n";
        echo "Messages: " . $row['messages'] . "\n";
        echo "-----------------\n";
    }
    Ответ написан
    Комментировать
  • В чем может быть проблема?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Должен вернуть одну строку с id 10 (последняя строка в выборке на скриншоте)
    Кому должен? Программа должна делать только то, что вы в ней написали. Строки по колонке mentions отсортированы, десятая строка выбрана. То, что нет других правил сортировки означает, что строки с одинаковым значением mentions можно выдавать в любом порядке.
    Ответ написан
    Комментировать