PHP 于小项目:从鉴权说起

news2024/12/23 9:40:37

PHP 于小项目:从鉴权说起

在当今这个开发技术多样化的时代,选择合适的开发语言和框架常常决定了项目的效率与成败。对于个人开发者,特别是那些进行小型、短期项目的人来说,PHP 是一种特别友好的选择。本文将通过介绍 PHP 实现鉴权(登录)的方式,探讨为何它如此适合个人开发者的临时小项目。

为什么选择 PHP?

1. 易于部署:即开即用

PHP 的核心优势之一便是它极其简单的部署方式。你几乎可以在任何支持 HTTP 的服务器上运行 PHP,无需复杂的配置。对于那些快速验证想法或开发小型项目的个人开发者来说,这意味着你可以省去繁琐的设置工作,把精力更多地放在功能实现上。

试想一下,你想要快速上线一个简单的网站或工具,选择 PHP 意味着你不必去学习额外的工具链,也不必安装复杂的运行环境。将 PHP 文件放在服务器上即可运行,真是再轻便不过了。

2. 资源占用小:应对低访问量的理想选择

相比于许多其他后端语言,PHP 对于少量并发请求的处理效率非常高,这使得它在资源占用方面表现优异。当你进行一个小型项目,用户数量少或者访问量不高时,PHP 几乎不占用多少系统资源,而你不必担心它的性能瓶颈。

在这个场景下,PHP 就像是一辆小型的燃油车,而其他语言如 Node.js、Java 等则可能是高速跑车。虽然跑车在赛道上速度更快,但日常使用、资源有限的情况下,小车反而更适合,性价比更高。


鉴权(登录)的常见实现

让我们通过鉴权功能来进一步说明 PHP 的便利性。鉴权是任何涉及用户系统的项目中必不可少的部分,而 PHP 提供了简单高效的工具来实现这一功能。

鉴权流程概览

  1. 用户访问登录页面:用户通过表单输入用户名和密码。
  2. 验证用户信息:系统接受用户输入的信息,并在数据库中查找对应的记录。通过对比数据库中的散列密码与用户输入的密码,确认用户身份。
  3. 生成会话:一旦身份验证成功,系统为用户生成一个唯一的会话 ID(session),并将该会话保存在服务器端。
  4. 跳转至用户主页:最后,用户被重定向到受保护的用户主页,可以进行相应的操作。

PHP 实现登录鉴权示例

以下是使用 PHP 实现的一个简单的登录鉴权示例:

<?php
// 启动会话
session_start();

// 连接数据库
$conn = new mysqli("localhost", "username", "password", "database");

// 检查是否存在提交的用户名和密码
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // 查询用户信息
    $sql = "SELECT id, password_hash FROM users WHERE username = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("s", $username);
    $stmt->execute();
    $stmt->bind_result($id, $password_hash);
    
    // 检查用户是否存在以及密码是否匹配
    if ($stmt->fetch() && password_verify($password, $password_hash)) {
        // 密码验证成功,设置会话
        $_SESSION['user_id'] = $id;
        header("Location: homepage.php"); // 跳转到主页
    } else {
        echo "用户名或密码错误";
    }
    $stmt->close();
}
?>
解释:
  • 会话管理:通过 session_start(),我们启动了一个会话机制。登录成功后,用户的会话信息会存储在服务器上,而客户端只需保存会话 ID。
  • 密码散列验证:在用户注册时,将密码经过 password_hash() 处理为不可逆的散列值。在登录时,通过 password_verify() 来检查用户输入的密码是否与散列值相匹配。
  • 安全性:密码并非明文存储,散列算法确保即使数据库泄露,攻击者也无法直接获取用户的原始密码。

客户端通常只持有一个 session_id,这个 ID 是服务端和客户端沟通用户会话状态的桥梁。下面我们就深入讲讲 服务端的 session 存储与管理 机制。

1. 什么是 Session?

Session 是一种基于服务器端的会话管理机制,目的是在无状态的 HTTP 请求中保持用户的状态信息。在每次 HTTP 请求中,客户端都会将 session_id 发送给服务器,服务器根据这个 session_id 找到与之对应的用户数据。

打个比方,session_id 就像你去咖啡馆消费时领取的号码牌。每次你去柜台点单,店员都通过你的号码牌确认你的订单信息。而服务端的 session 存储就像是后台存放着的每个顾客的订单数据。

2. Session 的工作流程

  1. 初次请求:当用户首次访问服务器时,客户端还没有会话标识(session_id),服务器会为用户创建一个新的会话,并生成一个唯一的 session_id
  2. **服务器返回 ****session_id**:服务器将这个 session_id 通过 HTTP 响应的 Set-Cookie 头部返回给客户端,客户端将其保存在浏览器的 cookie 中。
  3. 后续请求:客户端在后续请求中,浏览器会自动将这个 session_id 作为 cookie 的一部分发送给服务器。
  4. 服务器查找会话:服务器根据收到的 session_id 查找保存在服务端的 session 数据。
  5. 响应数据:服务器根据会话信息返回相应的用户数据。

3. 服务端 Session 的存储与管理

3.1 默认情况下的文件存储

在 PHP 中,session 的默认存储方式是文件系统。也就是说,服务端会将每个用户的 session 数据存储在服务器的文件系统中。具体来说,当客户端请求生成 session_id 后,服务器会在一个特定的目录下创建一个以该 session_id 为文件名的文件,并将用户的相关信息(如用户 ID、登录状态等)保存到这个文件中。

默认的 session 存储路径通常可以在 PHP 配置文件 php.ini 中找到:

session.save_path = "/var/lib/php/sessions"

每个 session 文件看起来大致如下:

sess_abcd1234efgh5678ijkl9012mnop3456

文件内容可能是一些序列化的 PHP 数据结构,比如:

username|s:8:"JohnDoe";login_time|i:1609459200;

3.2 使用数据库存储

对于大部分生产环境,尤其是需要处理大量并发的场景,文件存储可能会变得不够高效。这时,开发者可以选择将 session 数据存储在数据库中,常见的数据库包括 MySQL、Redis、Memcached 等。使用数据库存储可以更方便地实现数据的持久化、集中化管理和扩展。

  • MySQL 存储:你可以在 php.ini 中配置 PHP 将 session 存储到 MySQL 数据库中,每次请求根据 session_id 查找数据库中对应的记录。 数据表结构类似如下:
CREATE TABLE sessions (
    session_id VARCHAR(255) PRIMARY KEY,
    session_data TEXT,
    last_updated TIMESTAMP
);
  • Redis 或 Memcached:使用 Redis 或 Memcached 等内存数据库存储 session,可以显著提高查询速度,因为数据都存储在内存中。这个方案通常用于大并发、高性能的场景。

3.3 自定义 Session 处理器

PHP 提供了一种灵活的方式,允许开发者自定义 session 存储方式,借助 session_set_save_handler() 函数,开发者可以自己定义存储、读取、更新、销毁 session 的方法。

那么,在php 中,Session 是如何被管理的?我们又能对session进行哪些服务端的设置呢?

Session 的基础管理

在 PHP 中,Session 的管理相当简单,主要通过 session_start() 开启或恢复会话,数据的存储和读取则通过超全局变量 $_SESSION 进行。

基本操作

// 启动或恢复 session
session_start();

// 存储数据到 session 中
$_SESSION['key'] = 'value';

// 读取 session 数据
$value = $_SESSION['key'];

// 删除特定的 session 数据
unset($_SESSION['key']);

// 销毁整个 session
session_destroy();

解释:

  • session_start():启动或恢复现有会话。在每个需要使用 session 的页面上,必须首先调用该函数。
  • $_SESSION:超全局数组,用来存储用户的会话数据。所有与该用户相关的数据都可以存储在这个数组中。
  • unset():删除某个特定会话变量。如果要删除所有数据但不销毁会话,可以使用 $_SESSION = array();
  • session_destroy():销毁当前会话,包括删除服务器端存储的会话数据,但不会删除客户端保存的 session_id

Session 的生命周期

Session 生命周期决定了会话数据在服务器端的有效期。PHP 通过设置 session.gc_maxlifetimesession_set_cookie_params 来控制会话的存续时间。

设置会话有效期为 1 小时的示例:

// 设置 session 有效期为1小时(3600秒)
ini_set('session.gc_maxlifetime', 3600);

// 设置 cookie 的有效期
session_set_cookie_params(3600);

// 启动 session
session_start();

解释:

  • session.gc_maxlifetime:控制 session 数据的存活时间,单位为秒。即在用户不访问的情况下,Session 数据在服务器上保存的时间。
  • session_set_cookie_params():控制客户端 cookie 的生命周期。它决定了浏览器何时清除客户端的 session_id

通过这两个参数,你可以灵活地控制用户的会话存续时间,确保会话的安全性和用户体验。

安全考虑

Session 是非常安全和高效的会话管理方式,但如果不采取额外的安全措施,仍可能面临一些常见攻击。以下是几种常见的安全问题及其防范措施。

1. 防止 Session 劫持

Session 劫持是指攻击者通过拦截网络流量,获取用户的 session_id,从而伪装成合法用户进行操作。为了防止这种情况,我们可以采取以下措施:

  • 使用 HTTPS:通过 HTTPS 加密传输,确保 session_id 不会被中间人攻击截获。

2. 防止 Session 固定攻击

Session 固定攻击是指攻击者在用户登录前,向用户预设一个已知的 session_id,然后在用户登录后利用该会话。这种攻击通过固定会话 ID 来冒充用户。

  • 重新生成 session ID:在用户登录成功后,强制生成新的 session_id,从而防止旧的 session_id 被攻击者利用。
// 登录成功后,重新生成 session ID
session_regenerate_id(true);

session_regenerate_id(true) 可以确保在登录后生成一个新的 session ID,并销毁旧的 session 数据,有效防止 session 固定攻击。

3. 敏感数据加密

在某些情况下,你可能会在 Session 中存储敏感信息,如用户的个人身份信息或认证凭据。为确保这些数据的安全性,建议对其进行加密处理。

// 使用加密函数对敏感数据进行加密存储
$_SESSION['sensitive_data'] = encrypt($sensitive_data);

加密与解密功能可以根据你的应用需求自行定义,但一定要保证加密算法的强度和安全性。

完整的 Session 管理示例

下面我们通过一个完整的例子,展示如何在用户登录成功后,管理和使用 PHP 的 Session,同时考虑安全性问题。

<?php
// 启动 session
session_start();

// 假设用户登录成功
$login_successful = true;
$user_id = 12345;
$username = 'JohnDoe';
$sensitive_data = 'ThisIsSensitiveData';

if ($login_successful) {
    // 防止 session 固定攻击:重新生成 session ID
    session_regenerate_id(true);
    
    // 存储用户数据到 session
    $_SESSION['user_id'] = $user_id;
    $_SESSION['username'] = $username;
    $_SESSION['login_time'] = time();

    // 加密并存储敏感数据
    $_SESSION['sensitive_data'] = encrypt($sensitive_data);
}

// 读取 session 数据
if (isset($_SESSION['user_id'])) {
    echo "欢迎回来, " . $_SESSION['username'] . "<br>";
    echo "您的上次登录时间是: " . date('Y-m-d H:i:s', $_SESSION['login_time']) . "<br>";
}

// 注销时,销毁 session
if ($logout) {
    session_destroy();
    echo "您已成功登出。";
}
?>

代码说明:

  1. 重新生成 session ID:登录成功后,我们通过 session_regenerate_id(true) 生成一个新的会话 ID,从而防止 session 固定攻击。
  2. 加密敏感数据:将用户的敏感数据加密后存储在 session 中,避免明文暴露可能带来的风险。
  3. 销毁 session:当用户选择注销时,调用 session_destroy() 彻底销毁会话。

服务端Session 生命周期配置

PHP 的 session 并不会永久保存,服务器会根据配置文件中的设置定期清理过期的 session 数据。这些配置通常可以在 php.ini 中找到,例如:

session.gc_maxlifetime = 1440   ; session 数据的有效时间(秒)
session.gc_probability = 1      ; 垃圾回收器的触发概率
session.gc_divisor = 1000       ; 垃圾回收器概率的分母

在上面的设置中,每次有 1/1000 的概率触发垃圾回收机制,删除超过 1440 秒(24 分钟)没有访问过的 session。

总结

  • **客户端只存储 ****session_id**:这只是一个唯一标识,真正的用户数据都存储在服务器端。
  • 服务端通过文件或数据库管理 session 数据:PHP 默认将 session 存储在文件系统中,但在高并发场景中,开发者可以选择数据库或内存数据库(如 Redis)来存储 session。
  • 灵活性与安全性:PHP 提供了高度灵活的自定义 session 存储方案,确保你可以根据项目需求调整会话管理方式,同时通过散列密码、 HTTPS 等方式保障安全性。

对于小型个人项目,PHP 默认的文件 session 存储已足够轻量且高效。而对于复杂项目,自定义 session 存储可以让你在性能和扩展性上实现更好的平衡。


是否要试试php?

PHP 由于其简单易用资源占用低高效的会话管理,非常适合个人开发者的小型项目。特别是在实现登录鉴权时,PHP 提供了极其简便的工具,帮助开发者快速完成用户验证的流程。

对于那些不需要处理大规模并发请求、只需简单鉴权功能的小项目来说,PHP 无疑是最佳选择之一。正如我们常说的,选择合适的工具远比选择最热门的工具更重要。在某些特定场景下,PHP 这种“经典的燃油车”可能会比“电动超跑”更符合需求。

如果你是一名个人开发者,正打算启动一个小项目,不妨试试 PHP。或许你会惊讶于它的简便和高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2168886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv9改进,YOLOv9主干网络替换为GhostNetV3(2024年华为提出的轻量化架构,全网首发),助力涨点

摘要 GhostNetV3 是由华为诺亚方舟实验室的团队发布的,于2024年4月发布。 摘要:紧凑型神经网络专为边缘设备上的应用设计,具备更快的推理速度,但性能相对适中。然而,紧凑型模型的训练策略目前借鉴自传统模型,这忽略了它们在模型容量上的差异,可能阻碍紧凑型模型的性能…

仓库场景物品检测分类系统源码分享

仓库场景物品检测分类检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comp…

显示adb报错,uniapp安装自定义基座

uni-app,uniCloud,serverless,真机运行常见问题,第1步 HX中没有运行到手机的菜单,第2步 电脑是否能检测到手机,第3步 电脑与手机是否建立信任调试关系,3.1 Android设备信任,3.2 iOS设备信任,第4步 HBuilderX检测手机,4.1 检测Android手https://uniapp.dcloud.net.cn/tutorial/r…

PHP爬虫APP程序:打造智能化数据抓取工具

在信息爆炸的时代&#xff0c;数据的重要性日益凸显。PHP作为一种广泛使用的服务器端脚本语言&#xff0c;因其强大的功能和灵活性&#xff0c;成为开发爬虫程序的理想选择。本文将探讨如何使用PHP构建一个爬虫APP程序&#xff0c;以及其背后的思维逻辑和实现步骤。 什么是PHP爬…

【高分系列卫星简介——高分七号卫星(GF-7)】

高分七号卫星&#xff08;GF-7&#xff09; 高分七号&#xff08;GF-7&#xff09;卫星是中国高分辨率对地观测系统&#xff08;高分专项&#xff09;的重要组成部分&#xff0c;具有显著的技术突破和广泛的应用价值。以下是对高分七号卫星的详细介绍&#xff1a; 一、基本信息…

word2vector训练代码详解

目录 1.代码实现 2.知识点 1.代码实现 #导包 import math import torch from torch import nn import dltools #加载PTB数据集 &#xff0c;需要把PTB数据集的文件夹放在代码上一级目录的data文件中&#xff0c;不用解压 #批次大小、窗口大小、噪声词大小 batch_size, ma…

堆的数组实现

目录 一、堆 二叉树的顺序结构 堆的概念及结构 1.概念 2.堆的分类 (1)大堆 (2)小堆 二、利用数组(顺序结构)实现堆的过程 1.利用数组实现堆的思路 2.堆是用数组实现的&#xff0c;在数组中通过双亲找自己左右孩子、通过左右孩子找自己双亲的思路 2.1.思路 2.2.孩子与…

认知杂谈84《菜鸟的自我修炼:知易行难与行难知易》

内容摘要&#xff1a; 理解与行动之间的差距是日常生活的常见挑战。"知易行难"体现在理解简单但执行困难&#xff0c;例如知道蔬菜有益但难以坚持食用。而"行难知易"则是开始时困难但后来容易的任务&#xff0c;如学习骑自行车。 这种差异源于心理惰性和习…

使用 Llama-index 实现的 Agentic RAG-Router Query Engine

前言 你是否也厌倦了我在博文中经常提到的老式 RAG(Retrieval Augmented Generation | 检索增强生成) 系统&#xff1f;反正我是对此感到厌倦了。但我们可以做一些有趣的事情&#xff0c;让它更上一层楼。接下来就跟我一起将 agents 概念引入传统的 RAG 工作流&#xff0c;重新…

OnlyOffice 打开文档时提示下载失败

OnlyOffice 下载失败问题 问题概述 OnlyOffice前端界面出现“下载失败” 问题定位&#xff08;0&#xff1a;docker内不能够访问&#xff09; 很常见的一种情况是后端服务地址错误&#xff0c;在docker内无法访问。 请在docker容器中确定这个地址是可以访问的&#xff0c;鉴…

electron 设置界面右下角打开

功能需求场景 写一个可以下载各种平台的小工具&#xff0c;需要右下角打开方便做其它事情 实现基础 要在屏幕的右下角设置窗口&#xff0c;可以调整mainWindow的创建参数&#xff0c;特别是通过使用x和y坐标来定位窗口 &#xff1b; 需要获取屏幕的尺寸&#xff0c;并据此计算…

不透明物体的投射和接收阴影

1、Fallback的作用 新建一个材质球&#xff0c;将其的Shader设置为之前编写的多种光源综合实现Shader 并将该材质球赋值给较大的立方体使用&#xff0c;我们会发现该立方体不再投射阴影也不再接受阴影 &#xff08;1&#xff09;不投射阴影的原因 该Shader中没有LightMo…

Rust编程的if选择语句

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 Rust语言实现选择结构时&#xff0c;根据某种条件的成立与否而采用不同的程序段进行…

【Kubernetes】日志平台EFK+Logstash+Kafka【实战】

一&#xff0c;环境准备 &#xff08;1&#xff09;下载镜像包&#xff08;共3个&#xff09;&#xff1a; elasticsearch-7-12-1.tar.gz fluentd-containerd.tar.gz kibana-7-12-1.tar.gz &#xff08;2&#xff09;在node节点导入镜像&#xff1a; ctr -nk8s.io images i…

解决sortablejs+el-table表格内限制回撤和拖拽回撤失败问题

应用场景&#xff1a; table内同一类型可拖拽&#xff0c;不支持不同类型拖拽&#xff08;主演可拖拽交换位置&#xff0c;非主演和主演不可交换位置&#xff09;,类型不同拖拽效果需还原&#xff0c;试了好几次el-table数据更新了&#xff0c;但是表格样式和数据不能及时保持…

Java面试题之JVM面试题

JVM 的主要作用是什么&#xff1f; JVM 就是 Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM 屏蔽了与具体操作系统平台相关的信息&#xff0c;使 Java 程序只需生成在 Java 虚拟机上运行的目标代码 &#xff08;字节码&#xff09;&#xff0…

uniapp 常用高度状态栏,导航栏,tab栏,底部安全高度

实际效果 使用 //使用 let posConfig this.getPosConfig(); // 传false返回值为 px大小 console.log(posConfig.safeBottomH) // 入参 是否转换为rpxgetPosConfig(toRpx true) {const systemInfo uni.getSystemInfoSync();// #ifdef MPconst menuButtonInfo uni.getMenuBu…

Hello Algorithm:Capture 1,2 初识算法

大家好 :) 自学完sklearn的基本使用后&#xff0c;颇感无趣。虽有阅文几篇&#xff0c;却无所获。遂于24年9月26日决习hello algorithm。 &#xff1a;&#xff09; 好了&#xff0c;不开玩笑了。其实开设这篇专栏我也不知道有没有什么意义。其实是因为最近在读TaskWeaver&…

关于最小二乘法

最小二乘法的核心思想简单而优雅&#xff1a;我们希望找到一条最佳的曲线&#xff0c;使其尽可能贴近所有的数据点。想象一下&#xff0c;当你在画布上描绘一条线&#xff0c;目标是让这条线与点的距离最小。数学上&#xff0c;这可以表示为&#xff1a; 在这个公式中&#xff…

Eclipse Memory Analyzer (MAT)提示No java virtual machine was found ...解决办法

1&#xff0c;下载mat后安装&#xff0c;打开时提示 jdk版本低&#xff0c;需要升级到jdk17及以上版本&#xff0c;无奈就下载了jdk17&#xff0c;结果安装后提示没有jre环境&#xff0c;然后手动生成jre目录&#xff0c;命令如下&#xff1a; 进入jdk17目录&#xff1a;执行&…