You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在登录时正确存储设备/应用/浏览器信息(PHP+JS)

Implementing Facebook-like Session Device Tracking with PHP & JavaScript

Hey Rahul, awesome idea! You’re already off to a good start with using $_SERVER variables, but let’s address the limitations of relying solely on HTTP_USER_AGENT and build a robust, accurate device tracking system similar to Facebook’s.

First, Let’s Fix the Core Issues with Your Initial Approach

  • REMOTE_ADDR might not be the real user IP: If your site uses a CDN, reverse proxy, or users are on a VPN/proxy, REMOTE_ADDR will return the proxy’s IP instead of the user’s actual address.
  • HTTP_USER_AGENT is unreliable: It can be easily spoofed, and parsing it manually to get device/browser details is error-prone (different browsers format it differently).
  • Missing context: PHP alone can’t get details like screen resolution, timezone, or exact device model—you’ll need JavaScript to fill those gaps.

Step-by-Step Implementation

1. Get the User’s Real IP Address

Create a helper function to fetch the actual user IP, accounting for proxies. Make sure to whitelist your trusted proxies (like Cloudflare, Nginx) to prevent spoofing:

function getRealUserIp() {
    $ipKeys = [
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_REAL_IP',
        'HTTP_CLIENT_IP',
        'REMOTE_ADDR'
    ];
    
    foreach ($ipKeys as $key) {
        if (!empty($_SERVER[$key])) {
            // Split multiple IPs (comma-separated) and take the first valid one
            $ipList = explode(',', $_SERVER[$key]);
            foreach ($ipList as $ip) {
                $ip = trim($ip);
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    // Add your trusted proxy IPs here to skip them
                    $trustedProxies = ['192.168.1.1', '10.0.0.1'];
                    if (!in_array($ip, $trustedProxies)) {
                        return $ip;
                    }
                }
            }
        }
    }
    return $_SERVER['REMOTE_ADDR'] ?? 'Unknown';
}

2. Parse User Agent into Useful Details

Instead of parsing HTTP_USER_AGENT manually, use a dedicated library to get accurate device/browser info. Two great options:

  • Mobile_Detect: Lightweight, focused on mobile devices
  • ua-parser-php: More comprehensive, covers browsers, OS, and devices

Here’s an example with Mobile_Detect:

require_once 'Mobile_Detect.php';
$detect = new Mobile_Detect();

$deviceInfo = [
    'is_mobile' => $detect->isMobile(),
    'is_tablet' => $detect->isTablet(),
    'browser' => $detect->browser() . ' ' . $detect->version($detect->browser()),
    'os' => $detect->operatingSystem() . ' ' . $detect->version($detect->operatingSystem()),
    'device' => $detect->getDeviceName() ?? 'Unknown Device'
];

3. Fetch Additional Details with JavaScript

Use JS to grab details PHP can’t access, then send them to your backend on login:

// Get device/context details
const deviceDetails = {
    screen_resolution: `${screen.width}x${screen.height}`,
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    language: navigator.language,
    is_touch_enabled: 'ontouchstart' in window
};

// Send to PHP via AJAX (or include in login form as hidden fields)
fetch('/save-device-details.php', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content // Add CSRF protection!
    },
    body: JSON.stringify({
        session_id: '<?php echo session_id(); ?>', // Pass current session ID
        user_id: '<?php echo $_SESSION['user_id']; ?>',
        details: deviceDetails
    })
});

4. Database Schema for Storing Device Sessions

Create a table to track each login session’s device info:

CREATE TABLE user_sessions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    session_id VARCHAR(255) NOT NULL,
    ip_address VARCHAR(45) NOT NULL, -- IPv6 support
    user_agent TEXT NOT NULL, -- Store raw UA for fallback
    parsed_device JSON NOT NULL, -- Store parsed device/browser info
    additional_details JSON NOT NULL, -- Store JS-fetched details
    login_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
    last_activity DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    is_active BOOLEAN DEFAULT TRUE,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

5. Save Device Info on Successful Login

When the user logs in, save all the collected data to the database:

// After successful authentication
session_start();
$userId = $_SESSION['user_id'];
$sessionId = session_id();
$realIp = getRealUserIp();
$rawUserAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';

// Combine parsed device info and JS details (fetch JS details from POST if using form submission)
$fullDeviceData = [
    'parsed' => $deviceInfo,
    'additional' => $_POST['device_details'] ?? []
];

// Insert into database
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$stmt = $pdo->prepare("INSERT INTO user_sessions (user_id, session_id, ip_address, user_agent, parsed_device, additional_details) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([
    $userId,
    $sessionId,
    $realIp,
    $rawUserAgent,
    json_encode($fullDeviceData['parsed']),
    json_encode($fullDeviceData['additional'])
]);

6. Display the Device List to Users

Create a page where users can view their active sessions, similar to Facebook’s settings:

// Fetch active sessions for the logged-in user
$stmt = $pdo->prepare("SELECT * FROM user_sessions WHERE user_id = ? AND is_active = TRUE ORDER BY login_timestamp DESC");
$stmt->execute([$userId]);
$sessions = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<h2>Your Active Sessions</h2>
<ul>
    <?php foreach ($sessions as $session): ?>
        <?php $parsed = json_decode($session['parsed_device'], true); ?>
        <?php $additional = json_decode($session['additional_details'], true); ?>
        <li>
            <strong><?php echo $parsed['device']; ?></strong> (<?php echo $parsed['browser']; ?> on <?php echo $parsed['os']; ?>)<br>
            IP: <?php echo $session['ip_address']; ?><br>
            Last active: <?php echo date('F j, Y g:i a', strtotime($session['last_activity'])); ?><br>
            <?php if (!empty($additional['timezone'])): ?>
                Timezone: <?php echo $additional['timezone']; ?><br>
            <?php endif; ?>
            <button onclick="logoutSession('<?php echo $session['session_id']; ?>')">Log out this device</button>
        </li>
    <?php endforeach; ?>
</ul>

<script>
function logoutSession(sessionId) {
    fetch('/logout-session.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
        },
        body: JSON.stringify({session_id: sessionId})
    }).then(() => window.location.reload());
}
</script>

7. Add "Log Out This Device" Functionality

Create the backend endpoint to invalidate a session:

session_start();
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');

$data = json_decode(file_get_contents('php://input'), true);
$sessionId = $data['session_id'];
$userId = $_SESSION['user_id'];

// Mark session as inactive
$stmt = $pdo->prepare("UPDATE user_sessions SET is_active = FALSE WHERE session_id = ? AND user_id = ?");
$stmt->execute([$sessionId, $userId]);

// Optional: Destroy the session if it's the current one
if ($sessionId === session_id()) {
    session_destroy();
    echo json_encode(['success' => true, 'redirect' => '/login']);
} else {
    echo json_encode(['success' => true]);
}

Key Security & Privacy Notes

  • CSRF Protection: Always include CSRF tokens in AJAX requests and form submissions to prevent cross-site request forgery.
  • Privacy Compliance: Make sure to disclose this tracking in your privacy policy—users have a right to know what data you’re collecting and why (it’s for account security, after all).
  • Limit Data Retention: Don’t keep old session data forever—set a cleanup cron job to delete inactive sessions after 30-90 days.
  • Avoid Overcollecting: Only store what you need for security purposes—no unnecessary data.

内容的提问来源于stack exchange,提问作者Rahul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:32:14