简体   繁体   中英

How to make a button execute a php script?

How to make a html button execute a php script ?

I am working on a login system where only one user can login and whenever other users try to login, it should give them the warning pop up message saying another user is already logged in - Do you want to take over from them?

  • If userA is already logged in and userB tries to login then it should show on the popup as userA is already logged in, do you want to take over? .
  • Now for userA behind the scene, we will take away write access and show them another popup message that your write access is revoked.

Second point I can handle it later on but as of now I am focus on doing the point one. Below is my code in which I am trying to achieve the first point at LINE A -

if (isset($_POST['user_name'], $_POST['user_pass']) && $_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 && 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";
    }
}

I want to achieve the following tasks but I am confused on how to achieve it -

  • At LINE A , I want to show a pop up message saying "Previous user is logged in. Do you want to take over?" with Ok and Cancel buttons.
  • Once I click on Ok button on that pop up message then I want to execute certain code in php let's say print hello world for now and if I click the cancel button on that pop then I don't want to do anything.

In short, I want to achieve two things:

1. Create a popup message with Ok and Cancel buttons at Line A.
2. On clicking Ok button, I want to execute php script and on clicking Cancel button I don't want anything to happen.

Basic scenario:

  • Store currently authenticated user's unique id and time in a .txt file in the following format (as JSON):
json_encode(['user_id' => 1, 'created_at' => (new DateTime('now'))->format('Y-m-d H:i:s')]);
  • Check the stored user_id and created_at fields in the file when a user attempts to sign in.
  • If the file is empty, log the user in and write user's unique id and time to the file.
  • If the file is not empty and user_id field is same as the id of the user who attempts to log in and created_at field is not older than 12 hours ago (or your custom logic), just update created_at field in the file and log the user in.
  • If the file is not empty and user_id field is same as the id of the user who attempts to log in, but passed more than 12 hours (or your custom logic), ask the user if he/she want to take over another user.
  • If the file is not empty and user_id field is not same as the id of the user who attempts to log in ask the user if he/she want to take over another user.

Basic implementation:

  1. Create a .txt file in your project directory.
  2. Add these helper functions to your project ( helpers.php in my case):
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'] && (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. Create a login page ( login.php in my case):
<?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 && 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) && 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. Check if another user took over currently authenticated user in your pages ( index.php in my case):
<?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 && res.redirect) {
                    location.replace(res.redirect);
                }
            });
        }, 3000);
    });
</script>
</body>
</html>
  1. Implement your check logic ( check.php in my case):
<?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. Finally, create your action/function for the case when user confirms to take over ( confirmed.php in my case):
<?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.',
]);

Tested and works fine. But you should customize it for your needs.

Here the basic concept.

  • You need a central storage where the current active user active_user_id and last_updated is stored (database/file/memcache/redis whatever you want)
  • You need to poll the current active user for each session - if the current user is not the active user he will logged out and notified, so he knows someone else took over.

Flow

  • User loggs in
    • $_SESSION['user_id'] = user_id
    • IF: $_SESSION['user_id'] !== active_user_id (central storage - see above) AND last_updated < 10s
      • TRUE: log in, update active_user_id to $_SESSION['user_id'] ; update last_updated to now; redirect to main-page
      • FALSE: show popup "Take over?" -> ok: same as TRUE from above, abort: close popup
  • While logged-in call check-active.php every 5 seconds

check-active.php (pseudocode):

  • IF: user_id from $_SESSION['user_id'] === active_user_id from storage
    • TRUE: update last_updated in storage ; return 'ok';
    • FALSE: call session_destroy(); return 'failed';

frontend pseudocode (logged in):

  • call check-active.php every 5 seconds
  • handle result
  • IF: result === 'ok'
    • TRUE: do nothing
    • FALSE: redirect to main page like 'main.php?message=' . urlencode('You got replaced')

Why check for last_updated > 10s?

Because someone logged in could just close the browser, so we dont know if the session is still active or not. So we check last_updated (which will be updated every 5 seconds as long as the browser is still open). If last_updated is > 10s we consider it as "noone is currently active" so we dont have to ask to take over.


Working example

Open this - hit "run" (if not running).

Then open this twice. One in a incognito tab, to get a secondary session to kick yourself out.

Disclaimer: This is absolutely experimental.

This Sort Answer is Possible .

You can do with JavaScript and jQuery .

use setInterval userA and userB common users login check php

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

then confirmation from user when click function

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

with confirm call $.ajax function

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

userB try login setInterval send 20 seconds wait for response.

after 20 seconds that userA ip is set logout.

setInterval userA received "logout" then call logout php.

it is basic ip , user and logged information in check php with database.

i just placed which function used for this? not full code.

Note: code below is untested but should give you a basic idea of the way to go.

First of all, you should only be revoking write access from someone who currently has write access, so your first sql should be:

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

Secondly, since you already only selecting users who have 'open' == "true" , then checking again if($row['open'] == "true") { is redundant.

Thirdly, you should put the user name into the session for later manipulation and retrieval of logged-in user data.

Fourthly, you are executing the same query twice consecutively in the code below, so instead of:

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

just put:

if($result1)

Now for a solution to your problem:

To avoid passing the name and password back and forth for a second login attempt after confirmation, we can use a token. Also, at that point I would like to save the user name as I'm going to be using it so at line A put:

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

and we have to have a way of returning that token to the client and then back to the server so somewhere in your script you could have:

if (isset($_SESSION['login_token']) && $_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
}

We also want the PHP script above to handle the session login which will also disconnect the other user so we will add:

if (isset($_POST['login_token'], $_SESSION['login_token']) && $_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();
}

Finally we want a frontend script that checks change in permission: I'm going to use polling + jQuery for this:

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

and check_permissions.php is:

$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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM