Как заставить кнопку выполнять php-скрипт?

#javascript #php #html #ajax #popup

#javascript #php #HTML #ajax #всплывающее окно

Вопрос:

Как заставить html-кнопку выполнять php-скрипт?

Я работаю над системой входа в систему, где только один пользователь может войти в систему, и всякий раз, когда другие пользователи пытаются войти в систему, он должен выдавать им всплывающее сообщение с предупреждением: another user is already logged in - Do you want to take over from them?

  • Если userA уже авторизован и userB пытается войти, то это должно отображаться во всплывающем окне как userA is already logged in, do you want to take over? .
  • Теперь для userA того, что происходит за сценой, мы уберем доступ на запись и покажем им другое всплывающее сообщение о том, что ваш доступ на запись отозван.

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

 if (isset($_POST['user_name'], $_POST['user_pass']) amp;amp; $_POST['user_login'] == 1) {
    //Assigning posted values to variables.
    $username = $_POST['user_name'];
    $password = $_POST['user_pass'];

    //Checking the values are existing in the database or not
    $stmt = $connect->prepare("SELECT user_pass FROM userspanel WHERE user_name=?");
    $stmt->bind_param('s', $username);
    $stmt->execute();
    $result = $stmt->get_result();
    $user_from_db = $result->fetch_object();

    if ($user_from_db amp;amp; password_verify($password, $user_from_db->user_pass)) {

        $_SESSION['user_name'] = $username;

        $sql = "SELECT * FROM trace_users where open='true'";
        $result1 = mysqli_query($connect, $sql);
        if($result1 = mysqli_query($connect, $sql)){
            if(mysqli_num_rows($result1) > 0){
                while($row = mysqli_fetch_array($result1)){
                    if($row['open'] == "true") {
                        if(!isset($_SESSION['pageadmin'])) {
                            $message = "user " . $row['user_name'] . " is logged in. Do you want to take over ?";
                            // LINE A
                            // how to show pop up button which shows $message on it
                            // and add action on ok and cancel button here?
                        }
                        break;
                    }
                }
            } else{
                $_SESSION['pageadmin'] = true;
                $open = "true";
                $read_access = "1";
                $write_access = "1";
                $stmt = $connect->prepare("UPDATE trace_users SET open=?, read_access=?, write_access=? WHERE user_name=?");
                $stmt->bind_param('ssss', $open, $read_access, $write_access, $username);
                $stmt->execute();
            }
        }

    } else {
        echo "Invalid username and password";
    }
}
  

Я хочу выполнить следующие задачи, но я не понимаю, как этого добиться —

  • В LINE A я хочу показать всплывающее сообщение с надписью "Previous user is logged in. Do you want to take over?" с кнопками «Ок» и «Отмена».
  • Как только я нажимаю на Ok кнопку в этом всплывающем сообщении, я хочу выполнить определенный код на php, скажем, на данный момент print hello world , и если я нажму cancel кнопку на этом всплывающем окне, я ничего не хочу делать.

Короче говоря, я хочу добиться двух вещей:

1. Создайте всплывающее сообщение с кнопками Ok и Cancel в строке A.
2. При нажатии кнопки Ok я хочу выполнить php-скрипт, а при нажатии кнопки Отмены я не хочу, чтобы что-то происходило.

Комментарии:

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

2. «Всплывающее окно» звучит несколько расплывчато. Вы имеете в виду JS-модал или HTML / CSS-модал? Независимо от этого, любой метод должен будет отправить форму, которая сообщает серверу, по сути, «войдите в систему этого пользователя и позвольте ему взять верх». Проблема с любым подходом заключается в том, что что, если другой пользователь также находился в том же модальном режиме и отправил его на долю секунды позже? Какой из двух последних пользователей получает приоритет? Конечно, вы всегда можете сделать это простым случаем «короля горы» (последний человек, пришедший, выбивает того, кто там был), но это может не соответствовать вашему намерению. Поведение.

3. @kmoser JS модальный или HTML / CSS модальный оба будут работать. Я думаю, что несколько пользователей, обращающихся к форме одновременно, являются проблемой, но у нас есть только 5-6 пользователей (не слишком много), обращающихся к этой форме, поэтому мы можем подумать об этом позже, возможно. При нажатии кнопки ok я хочу выполнить определенный php-код, а при нажатии кнопки отмена я ничего не хочу делать.

4. Привет, спасибо, что проконсультировали меня 🙂 Вы действительно хотите, чтобы в систему входил только один пользователь, или вы хотите, чтобы в систему входил только один администратор? И должен ли пользователь, получающий удар, получать сообщение типа «кто-то взял верх»?

5. Заставить кнопку выполнить PHP-код можно двумя способами: либо заставить кнопку отправить форму, где action находится ваш PHP-скрипт, либо заставить кнопку выполнить AJAX-вызов PHP-скрипта.

Ответ №1:

Базовый сценарий:

  • Сохраняйте уникальный идентификатор пользователя, прошедшего проверку подлинности, и время в .txt файле в следующем формате (как JSON):
 json_encode(['user_id' => 1, 'created_at' => (new DateTime('now'))->format('Y-m-d H:i:s')]);
  
  • Проверяйте сохраненные поля user_id и created_at в файле, когда пользователь пытается войти в систему.
  • Если файл пуст, войдите в систему пользователя и запишите уникальный идентификатор пользователя и время в файл.
  • Если файл не пуст, а user_id поле совпадает с id полем пользователя, который пытается войти в систему, и created_at поле не старше 12 часов назад (или по вашей пользовательской логике), просто обновите created_at поле в файле и войдите в систему пользователя.
  • Если файл не пуст, а user_id поле совпадает с id полем пользователя, который пытается войти в систему, но прошло более 12 часов (или ваша пользовательская логика), спросите пользователя, хочет ли он / она заменить другого пользователя.
  • Если файл не пуст, а user_id поле не совпадает с id полем пользователя, который пытается войти в систему, спросите пользователя, хочет ли он / она принять другого пользователя.

Базовая реализация:

  1. Создайте .txt файл в каталоге вашего проекта.
  2. Добавьте эти вспомогательные функции в свой проект ( helpers.php в моем случае):
 if (! function_exists('check_auth')) {
    function check_auth(): bool
    {
        if (! isset($_SESSION['user_id'])) {
            return false;
        }

        if (! file_exists('current_user.txt') || filesize('current_user.txt') === 0) {
            return true;
        }

        $trace = json_decode(file_get_contents('current_user.txt'));

        // You can write your own logic here.
        return (int) $trace->user_id === $_SESSION['user_id'] amp;amp; (new DateTime($trace->created_at))->modify(' 12 hours') > new Datetime('now');
    }
}

if (! function_exists('logout'))
{
    function logout()
    {
        if (isset($_SESSION['user_id'])) {
            $trace = json_decode(file_get_contents('current_user.txt'));

            if ((int) $trace->user_id === $_SESSION['user_id']) {
                file_put_contents('current_user.txt', '');
            }

            unset($_SESSION['user_id']);
        }
    }
}

if (! function_exists('redirect')) {
    function redirect(string $url, int $status_code = 303): void
    {
        header('Location: ' . $url, true, $status_code);
        die();
    }
}
  
  1. Создайте страницу входа ( login.php в моем случае):
 <?php

declare(strict_types=1);

// Start session.
session_start();

// Include helper functions.
require_once 'helpers.php';

// Redirect user to homepage/dashboard if authenticated.
if (check_auth()) {
    redirect('index.php');
    return;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $pdo = new PDO('mysql:host=[DB_HOST];dbname=[DB_NAME];charset=utf8mb4', '[DB_USERNAME]', '[DB_PASSWORD]', [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ]);
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
    $stmt->execute([$_POST['email']]);
    $user = $stmt->fetch();

    if (! ($user amp;amp; password_verify($_POST['password'], $user->password))) {
        echo json_encode([
            'success' => false,
            'message' => 'These credentials don't match our records.',
        ]);
        return;
    }

    // Log user in if another is not authenticated.
    if (filesize('current_user.txt') === 0) {
        file_put_contents('current_user.txt', json_encode([
            'user_id'    => $user->id,
            'created_at' => (new DateTime('now'))->format('Y-m-d H:i:s'),
        ]));

        $_SESSION['user_id'] = $user->id;

        echo json_encode([
            'success' => true,
        ]);

        return;
    }

    $trace = json_decode(file_get_contents('current_user.txt'));

    // Log user in if the last authenticated user is himself/herself.
    if ((int) $trace->user_id === $user->id) {
        $trace->created_at = (new DateTime('now'))->format('Y-m-d H:i:s');

        file_put_contents('current_user.txt', json_encode($trace));

        $_SESSION['user_id'] = $user->id;

        echo json_encode([
            'success' => true,
        ]);

        return;
    }

    // Ask user if he/she wants to take over.
    echo json_encode([
        'success'  => false,
        'takeover' => true,
        'message'  => 'Another user is logged in. Do you want to take over?',
    ]);

    return;
}

?>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Login</title>
</head>
<body>
    <form method="post" id="form">
        <div>
            <label for="email">Email:</label>
            <input type="email" id="email" name="email" placeholder="Email" required>
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" placeholder="Password">
        </div>
        <div>
            <span id="message" style="color: red;"></span>
        </div>
        <button>Log in</button>
    </form>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script>
        $(function () {
            $('#form').submit(function (e) {
                e.preventDefault();
                $('#message').text('');

                $.post('login.php', $(this).serialize(), function (response) {
                    const res = JSON.parse(response);

                    if (res.takeover) {
                        // Ask user if he/she wants to take over. If user confirms, run `confirmed()` function.
                        confirm(res.message) amp;amp; confirmed();
                        return;
                    }

                    if (res.success) {
                        // Login is successful. Reload or redirect user to another page.
                        location.reload();
                    } else {
                        // Login failed. Incorrect email or password entered.
                        $('#message').text(res.message || '');
                    }
                });
            });

            function confirmed() {
                $.post('confirmed.php', function (response) {
                    const res = JSON.parse(response);
                    console.log(res.data);
                });
            }
        });
    </script>
</body>
</html>
  
  1. Проверьте, не взял ли другой пользователь на себя управление текущим аутентифицированным пользователем на ваших страницах ( index.php в моем случае):
 <?php

declare(strict_types=1);

// Start session.
session_start();

// Include helper functions.
require_once 'helpers.php';

?>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Home</title>
</head>
<body>
<?php if (check_auth()): ?>
    Welcome friend.
<?php else: ?>
    <a href="/login.php">Log in</a>
<?php endif; ?>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
    $(function () {
        // Check if another user took over currently authenticated user in every 3 seconds.
        setInterval(function () {
            $.post('check.php', function (response) {
                let res = JSON.parse(response);
                if (! res.auth amp;amp; res.redirect) {
                    location.replace(res.redirect);
                }
            });
        }, 3000);
    });
</script>
</body>
</html>
  
  1. Реализуйте свою логику проверки ( check.php в моем случае):
 <?php

declare(strict_types=1);

// Start session.
session_start();

// Include helper functions.
require_once 'helpers.php';

if (! check_auth()) {
    logout();

    echo json_encode([
        'auth'     => false,
        'redirect' => 'login.php',
    ]);

    return;
}

echo json_encode([
    'auth' => true,
]);

  
  1. Наконец, создайте свое действие / функцию для случая, когда пользователь подтвердит переход ( confirmed.php в моем случае):
 <?php

declare(strict_types=1);

// Start session.
session_start();

// Include helper functions.
require_once 'helpers.php';

/**
 * Run your action here if user confirms to take over another user.
 */
echo json_encode([
    'data' => 'User confirmed to take over another user.',
]);
  

Протестировано и работает нормально. Но вы должны настроить его под свои нужды.

Комментарии:

1. Спасибо за ваше подробное предложение. Я пробовал вашу идею, и когда я запускаю ее локально на своем конце, я вижу проблему после ввода правильного пользователя и пароля. Когда я вхожу в систему в первый раз, она работает нормально, но когда я пытаюсь войти во второй раз, это выдает ошибку как Trying to get property 'user_id' of non-object in /opt/lampp/htdocs/testlogin/helpers.php on line 18 . Не уверен, почему я это понимаю. Есть мысли?

2. Я думаю, проблема в том, что во второй раз, когда он входит в систему current_user.txt , в файле есть две записи объекта json в одной строке, поэтому, возможно, после этого его невозможно правильно проанализировать?

Ответ №2:

Вот основная концепция.

  • Вам нужно центральное хранилище, где хранится текущий активный пользователь active_user_id и last_updated (база данных / файл / memcache / redis, что вы хотите)
  • Вам нужно опрашивать текущего активного пользователя для каждого сеанса — если текущий пользователь не является активным пользователем, он выйдет из системы и получит уведомление, чтобы он знал, что кто-то другой взял верх.

Поток

  • Пользователь входит в систему
    • $_SESSION['user_id'] = user_id
    • ЕСЛИ: $_SESSION['user_id'] !== active_user_id (центральное хранилище — см. Выше) И last_updated < 10 секунд
      • ВЕРНО: войдите в систему, обновите active_user_id до $_SESSION['user_id'] ; обновите last_updated до сейчас; перенаправьте на главную страницу
      • FALSE: показать всплывающее окно «Взять верх?» -> ok: то же, что и TRUE сверху, прервать: закрыть всплывающее окно
  • При входе в систему вызывайте check-active.php каждые 5 секунд

check-active.php (псевдокод):

  • ЕСЛИ: идентификатор пользователя из $_SESSION['user_id'] === active_user_id из storage
    • TRUE: обновить last_updated в storage ; вернуть ‘ok’;
    • FALSE: вызов session_destroy(); возвращает ‘сбой’;

frontend псевдокод (авторизован):

  • вызывайте check-active.php каждые 5 секунд
  • обрабатывать результат
  • ЕСЛИ: результат === ‘ok’
    • ВЕРНО: ничего не делать
    • FALSE: перенаправление на главную страницу типа ‘main.php?message=’ . urlencode(‘Вас заменили’)

Зачем проверять last_updated > 10 секунд?

Потому что кто-то, вошедший в систему, мог просто закрыть браузер, поэтому мы не знаем, активен ли сеанс еще или нет. Итак, мы проверяем last_updated (который будет обновляться каждые 5 секунд, пока браузер все еще открыт). Если last_updated > 10 секунд, мы рассматриваем это как «никто в данный момент не активен», поэтому нам не нужно просить взять управление на себя.


Рабочий пример

Откройте это — нажмите «выполнить» (если не запущено).

Затем откройте это дважды. Один на вкладке инкогнито, чтобы получить дополнительный сеанс, чтобы выгнать себя.

Отказ от ответственности: Это абсолютно экспериментально.

Комментарии:

1. В целом, мне больше всего нравятся идеи в этой. Примечание внизу также очень важно для OP. Никогда не предполагайте, что кто-то собирается выйти из системы, всегда проводите опрос в такой системе, как эта. Также для OP убедитесь, что ваша система поддерживает несколько окон / вкладок для пользователя, чтобы вы не выводили систему из строя, если / когда это произойдет.

2. @Pilan Извините, что меня не было некоторое время. Как вы думаете, вы можете привести пример на php с вашим вышеупомянутым предложением? Это будет мне очень полезно.

3. @user1950349 добавил рабочий пример — экспериментальный

4. @Pilan Я посмотрю. Спасибо за вашу помощь, хотя.

5. @Pilan Я попытался нажать «Выполнить», но это ничего не дает. Есть идеи, почему? Я вижу справа это сообщение Hmmmm.... We Couldn't Reach Your Repl.....

Ответ №3:

Ответ такого рода Possible .

Вы можете сделать с JavaScript и jQuery .

используйте setInterval UserA и UserB для входа в систему обычных пользователей проверьте php

 setInterval(function() {
    // codes here
},5000); // for 5 seconds
  

затем подтверждение от пользователя при нажатии функции

 $('#submit').on('click', function()
  

с помощью функции confirm вызова $.ajax

 if(confirm("Are you sure ?")) {
    // $.ajax codes here
}return false;
  

Пользователь пытается войти setInterval , отправляет 20 секунд ожидания ответа.

через 20 секунд для этого пользователя ip устанавливается выход из системы.

setInterval Пользователь получил «выход», затем вызывает logout php.

это базовый ip, пользователь и зарегистрированная информация в check php с базой данных.

я только что разместил, какая функция использовалась для этого? не полный код.

Ответ №4:

Примечание: приведенный ниже код не протестирован, но должен дать вам общее представление о том, как действовать.

Прежде всего, вы должны отменять доступ на запись только у того, у кого в настоящее время есть доступ на запись, поэтому ваш первый sql должен быть:

 $sql = "SELECT * FROM trace_users where open='true' amp;amp; write_access = '1'";
  

Во-вторых, поскольку вы уже выбираете только тех пользователей, у которых есть 'open' == "true" , повторная проверка if($row['open'] == "true") { является избыточной.

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

В-четвертых, вы выполняете один и тот же запрос дважды подряд в приведенном ниже коде, поэтому вместо:

 if($result1 = mysqli_query($connect, $sql))
  

просто поместите:

 if($result1)
  

Теперь о решении вашей проблемы:

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

 $_SESSION['login_token'] = sha1(time());
$_SESSION['user_name'] = $username;
  

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

 if (isset($_SESSION['login_token']) amp;amp; $_SESSION['login_token']) {
?>
<form id="confirm_form" action="login_script.php" method="POST">
    <input type="hidden" name="login_token" value="<?= $_SESSION['login_token'] ?>">
</form>
<script>
// And the popup:
if (confirm('<?= addcslashes($message, "'/") ?>')) {
    document.getElementById('confirm_form').submit();
}
</script>
<?php
}
  

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

 if (isset($_POST['login_token'], $_SESSION['login_token']) amp;amp; $_POST['login_token'] === $_SESSION['login_token']) {
    // block access to any write_access user
    // I am going to make an assumption here - that your write_access column can take the value "-1"
    // I am going to use it as a flag that means that this user needs to be told that his access has been revoked
    mysqli_query($connect, "UPDATE trace_users SET write_access = '-1' where open='true'");

    $_SESSION['pageadmin'] = true;
    $_SESSION['login_token'] = null;
    $open = "true";
    $read_access = "1";
    $write_access = "1";
    $stmt = $connect->prepare("UPDATE trace_users SET open=?, read_access=?, write_access=? WHERE user_name=?");
    $stmt->bind_param('ssss', $open, $read_access, $write_access, $username);
    $stmt->execute();
}
  

Наконец, нам нужен скрипт интерфейса, который проверяет изменение разрешения:
Я собираюсь использовать для этого опрос jQuery:

 <script>
setInterval(function() {
    $.get('check_permissions.php', function(data) {
        if (data == '-1') {
            alert('your write access is revoked');
        }
    });
}, 5000);
</script>
  

и check_permissions.php является:

 $stmt = $connect->prepare("SELECT write_access FROM trace_users WHERE user_name = ?");
$stmt->bind_param('s', $_SESSION['user_name']);
$stmt->execute();
$stmt->bind_result($status);
$stmt->fetch();
echo $status;

if ($status == -1) {
    // and update status of this user that he has no write permissions but no longer needs to be warned
    $stmt = $connect->prepare("UPDATE trace_users SET write_access = 0 WHERE user_name = ?");
    $stmt->bind_param('s', $_SESSION['user_name']);
    $stmt->execute();
}