web渗透

不吆 · 2026-11-07

这是一份系统性的Web渗透测试学习笔记,涵盖前端基础、后端开发、数据库操作等核心知识。通过理论与实践相结合的方式,帮助初学者建立完整的Web安全知识体系。

顺序阅读,先理解前端基础,再学习后端逻辑,最后掌握数据库操作。

课件地址:https://git\.inmind\-lab\.com/aaronxu/security\-book

笔记地址: https://notes\.iproute\.cn/s/065a4c88


1.1 网络安全


网络安全是保障公司业务正常运行,软件及其运行系统中的数据不因偶然的或者恶意原因来遭到破坏,更改和泄露,系统能够连续的可靠的正常运行,网络服务不中断。

1.2 网络安全从业者

(待补充)

1.3 作用

(待补充)

1.4 从业方向

(待补充)


01.初始前端

1. Web、网页、浏览器

HTML 基础结构:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!-- 如果出现乱码,查看是否是格式问题,可能为"ASCII" -->
  <meta http-equiv="refresh" content="30">
  <!-- 每隔30秒来刷新网页 -->
  <meta http-equiv="refresh" content="30;url=https://www.baidu.com">
  <!-- 每隔30秒,刷新网页并跳转到百度的网站 -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我是标题</title>
</head>
<body>
  我是正文内容
</body>
</html>

常用标签:

标题标签:

<h1>我是一级标题</h1>
<h2>我是二级标题</h2>
<h3>我是三级标题</h3>
<h4>我是四级标题</h4>
<h5>我是五级标题</h5>

表格:

<table>
  <tr>
    <th>姓名</th>
    <th>年龄</th>
    <th>性别</th>
  </tr>
  <tr>
    <td>王厅长</td>
    <td rowspan="3">20</td>   <!-- 合并单元行 -->
    <td colspan="2">男</td>    <!-- 合并单元列 -->
    <td>爱好</td>
  </tr>
  <tr>
    <td>王厅长</td>
    <td>20</td>
    <td>男</td>
  </tr>
  <tr>
    <td>王厅长</td>
    <td>20</td>
    <td>男</td>
  </tr>
</table>

设计登录页面

前端 HTML:

<h1 style="text-shadow: 2px 2px 5px blue">欢迎登录</h1>
<form action="login.php" method="post">
  <!-- 将数据提交到后端的php文件中 -->
  <input type="text" placeholder="请输入用户名">
  <input type="password" placeholder="请输入密码">
  <input type="submit" value="登录">
</form>

后端 PHP:

<?php
header("Content-type:text/html;charset=utf-8");

// 接受用户输入
// $_REQUEST 是全局变量,可以接受用户输入
// 当网页进行跳转后,用户输入的数据会保存到$_REQUEST中
// $_REQUEST是一个数组,可以通过下标访问数组中的元素

$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

if ($username == "admin" && $password == "1") {
    echo "登录成功";
} else if ($username == "user01" && $password == "2") {
    echo "登录成功";
} else {
    echo "登录失败";
}
?>

优化版登录页面(完整代码)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>欢迎登录</title>
    <style>
        :root{--primary:#6366f1;--primary-hover:#818cf8;--primary-dark:#4f46e5;--purple:#7c3aed;--success:#22c55e;--error:#ef4444;--glass:rgba(255,255,255,.04);--border:rgba(255,255,255,.08);--border-h:rgba(255,255,255,.15);--t1:#f1f5f9;--t2:#94a3b8;--t3:#475569;--ease:cubic-bezier(.16,1,.3,1);--spring:cubic-bezier(.34,1.56,.64,1)}
        *,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
        html{-webkit-font-smoothing:antialiased}
        body{font-family:'Segoe UI',system-ui,sans-serif;min-height:100vh;display:flex;justify-content:center;align-items:center;background:#020617;color:var(--t1);overflow:hidden;position:relative}
        .bg{position:fixed;inset:0;z-index:0;pointer-events:none}
        .bg-g{position:absolute;inset:0;background:radial-gradient(ellipse 80% 50% at 50% -20%,rgba(99,102,241,.25),transparent),radial-gradient(ellipse 60% 40% at 100% 0%,rgba(139,92,246,.18),transparent),radial-gradient(ellipse 50% 80% at 0% 50%,rgba(59,130,246,.12),transparent)}
        .bg-grid{position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,.025) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.025) 1px,transparent 1px);background-size:60px 60px;mask-image:radial-gradient(ellipse 80% 50% at 50% 0%,black,transparent);-webkit-mask-image:radial-gradient(ellipse 80% 50% at 50% 0%,black,transparent)}
        .glow{position:fixed;border-radius:50%;filter:blur(80px);pointer-events:none;z-index:1;opacity:.35}
        .g1{width:400px;height:400px;top:-100px;right:-100px;background:var(--primary);animation:o1 20s ease-in-out infinite}
        .g2{width:350px;height:350px;bottom:-80px;left:-80px;background:var(--purple);animation:o2 25s ease-in-out infinite}
        @keyframes o1{0%,100%{transform:translate(0,0) scale(1)}25%{transform:translate(-50px,80px) scale(1.1)}50%{transform:translate(-100px,20px) scale(.9)}75%{transform:translate(-30px,-50px) scale(1.05)}}
        @keyframes o2{0%,100%{transform:translate(0,0) scale(1)}25%{transform:translate(60px,-40px) scale(1.1)}50%{transform:translate(30px,-80px) scale(.95)}75%{transform:translate(-40px,-20px) scale(1.08)}}
        .particles{position:fixed;inset:0;z-index:2;overflow:hidden;pointer-events:none}
        .particle{position:absolute;border-radius:50%;background:rgba(255,255,255,.25);animation:float var(--d) var(--dl) infinite linear}
        @keyframes float{0%{transform:translateY(100vh);opacity:0}10%{opacity:1}90%{opacity:1}100%{transform:translateY(-100vh);opacity:0}}
        .wrapper{position:relative;z-index:10;width:100%;max-width:440px;padding:20px;animation:slideUp .8s var(--ease) forwards;opacity:0}
        @keyframes slideUp{from{opacity:0;transform:translateY(60px) scale(.95);filter:blur(10px)}to{opacity:1;transform:translateY(0) scale(1);filter:blur(0)}}
        .card{background:var(--glass);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border:1px solid var(--border);border-radius:1.5rem;padding:48px 40px;position:relative;overflow:hidden;transition:all .3s ease}
        .card::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent)}
        .card::after{content:'';position:absolute;inset:0;border-radius:inherit;background:radial-gradient(circle at 50% 0%,rgba(99,102,241,.08),transparent 60%);pointer-events:none}
        .card:hover{border-color:var(--border-h);box-shadow:0 0 40px rgba(99,102,241,.12);transform:translateY(-2px)}
        .logo{width:56px;height:56px;margin:0 auto 20px;background:linear-gradient(135deg,var(--primary),var(--purple));border-radius:1rem;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(99,102,241,.3);animation:logoF 6s ease-in-out infinite}
        .logo svg{width:28px;height:28px;fill:#fff}
        @keyframes logoF{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
        .header{text-align:center;margin-bottom:36px}
        .header h1{font-size:26px;font-weight:700;margin-bottom:8px;letter-spacing:-.02em}
        .header p{font-size:14px;color:var(--t2);letter-spacing:.05em}
        .group{margin-bottom:20px}
        .label{display:block;font-size:13px;font-weight:500;color:var(--t2);margin-bottom:8px;transition:color .2s}
        .group:focus-within .label{color:var(--primary-hover)}
        .input-wrap{position:relative;display:flex;align-items:center}
        .input-icon{position:absolute;left:16px;width:20px;height:20px;color:var(--t3);pointer-events:none;transition:all .2s;z-index:2}
        .group:focus-within .input-icon{color:var(--primary-hover);transform:scale(1.1)}
        .input{width:100%;height:52px;padding:0 18px 0 48px;background:rgba(255,255,255,.05);border:1.5px solid rgba(255,255,255,.1);border-radius:.75rem;font-size:15px;font-family:inherit;color:var(--t1);transition:all .2s;outline:none}
        .input::placeholder{color:var(--t3);transition:all .2s}
        .input:hover{border-color:rgba(255,255,255,.2);background:rgba(255,255,255,.07)}
        .input:focus{border-color:var(--primary);background:rgba(255,255,255,.08);box-shadow:0 0 0 4px rgba(99,102,241,.15),0 4px 16px rgba(0,0,0,.2);transform:translateY(-1px)}
        .input:focus::placeholder{color:var(--t2);transform:translateX(4px)}
        .input.error{border-color:var(--error);box-shadow:0 0 0 4px rgba(239,68,68,.15)}
        .pw-toggle{position:absolute;right:16px;width:20px;height:20px;color:var(--t3);cursor:pointer;background:none;border:none;padding:4px;transition:all .2s;z-index:2;display:flex;align-items:center;justify-content:center}
        .pw-toggle:hover{color:var(--t2);transform:scale(1.1)}
        .pw-toggle svg{width:100%;height:100%}
        .pw-toggle .icon-hide{display:none}
        .pw-toggle.active .icon-show{display:none}
        .pw-toggle.active .icon-hide{display:block}
        .err-msg{display:none;font-size:12px;color:var(--error);margin-top:6px;padding-left:4px}
        .err-msg.show{display:block;animation:shake .3s ease-in-out}
        @keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-5px)}75%{transform:translateX(5px)}}
        .options{display:flex;justify-content:space-between;align-items:center;margin-bottom:28px;flex-wrap:wrap;gap:8px}
        .chk{display:flex;align-items:center;gap:8px;cursor:pointer}
        .chk input{display:none}
        .chk-box{width:18px;height:18px;border:1.5px solid #475569;border-radius:4px;display:flex;align-items:center;justify-content:center;transition:all .15s;background:transparent}
        .chk-box svg{width:12px;height:12px;fill:#fff;opacity:0;transform:scale(0);transition:all .15s}
        .chk input:checked+.chk-box{background:var(--primary);border-color:var(--primary)}
        .chk input:checked+.chk-box svg{opacity:1;transform:scale(1)}
        .chk-label{font-size:13px;color:var(--t2);user-select:none}
        .forgot{font-size:13px;color:var(--primary-hover);text-decoration:none;transition:all .2s;position:relative}
        .forgot::after{content:'';position:absolute;bottom:-2px;left:0;width:0;height:1.5px;background:var(--primary-hover);transition:width .2s}
        .forgot:hover{color:#a5b4fc}
        .forgot:hover::after{width:100%}
        .btn{width:100%;height:52px;background:linear-gradient(135deg,var(--primary-dark),var(--purple));color:#fff;border:none;border-radius:.75rem;font-size:15px;font-weight:600;font-family:inherit;letter-spacing:.05em;cursor:pointer;position:relative;overflow:hidden;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px}
        .btn::before{content:'';position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);transition:left .5s ease}
        .btn:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(99,102,241,.4),0 4px 8px rgba(0,0,0,.2)}
        .btn:hover::before{left:100%}
        .btn:active{transform:translateY(0)}
        .btn:disabled{opacity:.7;cursor:not-allowed;transform:none;box-shadow:none}
        .btn-text{transition:all .2s}
        .btn-loader{position:absolute;width:24px;height:24px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;opacity:0;transition:opacity .2s}
        .btn.loading .btn-text{opacity:0;transform:scale(.8)}
        .btn.loading .btn-loader{opacity:1;animation:spin .8s linear infinite}
        @keyframes spin{to{transform:rotate(360deg)}}
        .divider{display:flex;align-items:center;gap:16px;margin:28px 0;color:#475569;font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.1em}
        .divider::before,.divider::after{content:'';flex:1;height:1px;background:linear-gradient(90deg,transparent,#1e293b,transparent)}
        .socials{display:flex;gap:12px}
        .social-btn{flex:1;height:48px;display:flex;align-items:center;justify-content:center;gap:8px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:.75rem;color:var(--t2);font-size:14px;font-family:inherit;font-weight:500;cursor:pointer;transition:all .2s}
        .social-btn:hover{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.2);transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,.2)}
        .social-btn:active{transform:translateY(0)}
        .social-btn svg{width:20px;height:20px}
        .footer{text-align:center;margin-top:28px;font-size:14px;color:var(--t2)}
        .footer a{color:var(--primary-hover);text-decoration:none;font-weight:500;transition:all .2s;position:relative}
        .footer a::after{content:'';position:absolute;bottom:-2px;left:0;width:0;height:1.5px;background:var(--primary-hover);transition:width .2s}
        .footer a:hover{color:#a5b4fc}
        .footer a:hover::after{width:100%}
        .toast{position:fixed;top:24px;right:24px;z-index:1000;padding:14px 22px;background:rgba(30,41,59,.95);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);border-radius:.75rem;color:var(--t1);font-size:14px;box-shadow:0 20px 25px -5px rgba(0,0,0,.3);transform:translateX(120%);transition:transform .5s var(--spring);display:flex;align-items:center;gap:10px}
        .toast.show{transform:translateX(0)}
        .toast.success{border-left:4px solid var(--success)}
        .toast.error{border-left:4px solid var(--error)}
        .toast svg{width:18px;height:18px;flex-shrink:0}
        .toast.success svg{color:var(--success)}
        .toast.error svg{color:var(--error)}
        .input:focus-visible,.btn:focus-visible,.social-btn:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
        @media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}
        @media(max-width:480px){.wrapper{padding:16px}.card{padding:36px 24px}.header h1{font-size:22px}.input,.btn{height:48px}.socials{flex-direction:column}.glow{opacity:.2}.g1{width:250px;height:250px}.g2{width:200px;height:200px}}
        @media(max-width:360px){.card{padding:28px 20px}.header{margin-bottom:28px}.options{flex-direction:column;align-items:flex-start;gap:12px}}
    </style>
</head>
<body>
    <div class="bg"><div class="bg-g"></div><div class="bg-grid"></div></div>
    <div class="glow g1"></div>
    <div class="glow g2"></div>
    <div class="particles" id="particles"></div>
    <div class="toast" id="toast">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 12l2 2 4-4"/><circle cx="12" cy="12" r="10"/></svg>
        <span id="toastMsg"></span>
    </div>
    <div class="wrapper">
        <div class="card">
            <div class="header">
                <div class="logo">
                    <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
                </div>
                <h1>欢迎回来</h1>
                <p>请登录您的账户</p>
            </div>
            <form id="loginForm" action="login.php" method="post" novalidate>
                <div class="group">
                    <label class="label" for="username">用户名</label>
                    <div class="input-wrap">
                        <svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
                        <input type="text" id="username" name="username" class="input" placeholder="请输入用户名" autocomplete="username" required>
                    </div>
                    <div class="err-msg" id="usernameError">请输入用户名</div>
                </div>
                <div class="group">
                    <label class="label" for="password">密码</label>
                    <div class="input-wrap">
                        <svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
                        <input type="password" id="password" name="password" class="input" placeholder="请输入密码" autocomplete="current-password" required>
                        <button type="button" class="pw-toggle" id="pwToggle" aria-label="显示密码">
                            <svg class="icon-show" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
                            <svg class="icon-hide" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
                        </button>
                    </div>
                    <div class="err-msg" id="passwordError">请输入密码</div>
                </div>
                <div class="options">
                    <label class="chk" tabindex="0">
                        <input type="checkbox" name="remember">
                        <span class="chk-box"><svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg></span>
                        <span class="chk-label">记住我</span>
                    </label>
                    <a href="#" class="forgot">忘记密码?</a>
                </div>
                <button type="submit" class="btn" id="submitBtn">
                    <span class="btn-text">登 录</span>
                    <span class="btn-loader"></span>
                </button>
            </form>
            <div class="divider">或</div>
            <div class="socials">
                <button type="button" class="social-btn" onclick="showToast('微信登录开发中','error')">
                    <svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.045c.133 0 .241-.108.241-.245 0-.06-.024-.118-.04-.177l-.325-1.233a.492.492 0 0 1 .177-.553C23.21 18.308 24 16.704 24 14.896c0-3.418-3.021-5.961-7.062-6.038zM14.5 13.93c.535 0 .969.44.969.983a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.983.97-.983zm4.844 0c.535 0 .969.44.969.983a.976.976 0 0 1-.97.983.976.976 0 0 1-.968-.983c0-.542.434-.983.969-.983z"/></svg>
                    微信
                </button>
                <button type="button" class="social-btn" onclick="showToast('QQ登录开发中','error')">
                    <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.003 2c-2.265 0-6.29 1.364-6.29 7.325v1.195S3.55 14.96 3.55 17.474c0 .665.17 1.025.281 1.025.114 0 .902-.484 1.748-2.072 0 0-.18 2.197 1.904 3.967 0 0-1.77.495-1.77 1.182 0 .686 4.078.43 6.29.43 2.239 0 6.29.256 6.29-.43 0-.687-1.77-1.182-1.77-1.182 2.085-1.77 1.905-3.967 1.905-3.967.845 1.588 1.634 2.072 1.746 2.072.111 0 .283-.36.283-1.025 0-2.514-2.166-6.954-2.166-6.954V9.325C18.29 3.364 14.268 2 12.003 2z"/></svg>
                    QQ
                </button>
            </div>
            <div class="footer">
                还没有账号?<a href="register.html">立即注册</a>
            </div>
        </div>
    </div>
    <script>
        (function(){
            var c=document.getElementById('particles'),n=window.innerWidth<480?15:30;
            for(var i=0;i<n;i++){var p=document.createElement('div');p.className='particle';var s=Math.random()*4+2;p.style.cssText='width:'+s+'px;height:'+s+'px;left:'+Math.random()*100+'%;--d:'+(Math.random()*15+10)+'s;--dl:'+Math.random()*10+'s;opacity:'+Math.random()*.3;c.appendChild(p)}
        })();
        function showToast(msg,type){var t=document.getElementById('toast'),m=document.getElementById('toastMsg');t.className='toast '+type;m.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show')},3000)}
        (function(){var btn=document.getElementById('pwToggle'),inp=document.getElementById('password');btn.addEventListener('click',function(){var is=inp.type==='password';inp.type=is?'text':'password';btn.classList.toggle('active');btn.setAttribute('aria-label',is?'隐藏密码':'显示密码')})})();
        document.querySelectorAll('.input').forEach(function(el){el.addEventListener('focus',function(){var e=this.parentElement.parentElement.querySelector('.err-msg');if(e){e.classList.remove('show')}this.classList.remove('error')})});
        (function(){var form=document.getElementById('loginForm'),btn=document.getElementById('submitBtn');form.addEventListener('submit',function(e){var ok=true;var u=document.getElementById('username'),p=document.getElementById('password');if(!u.value.trim()){document.getElementById('usernameError').classList.add('show');u.classList.add('error');ok=false}else{document.getElementById('usernameError').classList.remove('show');u.classList.remove('error')}if(!p.value){document.getElementById('passwordError').classList.add('show');p.classList.add('error');ok=false}else{document.getElementById('passwordError').classList.remove('show');p.classList.remove('error')}if(!ok){e.preventDefault();return}btn.classList.add('loading');btn.disabled=true})})();
    </script>
</body>
</html>

02.后端设计与应用

PHP 简述

通用开源脚本语言。在一个 php 文件中可以包括以下内容:

PHP 的使用:

  1. PHP 可以生成动态页面内容

  2. PHP 可以创建、打开、读取、写入、关闭服务器上的文件

  3. PHP 可以收集表单数据

  4. PHP 可以发送和接收 cookies

  5. PHP 可以添加、删除、修改您的数据库中的数据

  6. PHP 可以限制用户访问您的网站上的一些页面

  7. PHP 可以加密数据

下载并解压 usbwebserver:

(请自行下载 usbwebserver 并解压,截图略)

PHP 变量与请求示例:


<?
// 定义变量
$a = "hello world";
echo $a;

// 接受用户输入
// $_REQUEST 是全局变量,可以接受用户输入
// 当网页进行跳转后,用户输入的数据会保存到$_REQUEST中
// $_REQUEST是一个数组,可以通过下标访问数组中的元素
// 数组是一个数据类型,可以包含多个数据
// php的数组都是以key,value的形式存储数据
// key是字符串,value是任意类型
// key是唯一的,value可以重复

// $_REQUEST['username'] 获取用户名
// $_REQUEST['password'] 获取密码

$res = $_REQUEST;
?>

简单登录判断代码

<?php
header("Content-type:text/html;charset=utf-8");   //这行代码设置 HTTP 响应头,告诉浏览器返回的内容是什么类型。Content-type:text/html — 告诉浏览器这是 HTML 页面charset=utf-8 — 指定字符编码为 UTF-8,确保中文不会乱码没有这行的话,浏览器可能把中文显示成乱码或问号。

$username = isset($_POST['username']) ? $_POST['username'] : "";
$password = isset($_POST['password']) ? $_POST['password'] : "";

if ($username == "admin" && $password == "123456") {
    echo "登录成功";
} else {
    echo "登录失败";
}
?>
  1. `mysqli_fetch_assoc()` 每次从结果集取一行

→ 返回关联数组: `["username"=>"admin", "password"=>"123456", "email"=>"admin@163.com", ...]`

→ 赋值给 `$row`,while 条件为 true → 进入循环体

→ `?>` 退出 PHP → 输出纯 HTML(用 `<?php echo $row["xxx"]?>` 插入值)→ `<?php` 回到 PHP

→ 循环 → 再取下一行 → 直到所有行取完,返回 null → while 条件为 false → 循环结束

  1. 将从数据库中的数据再次使用 PHP 语言输出到前端:
<td><?php echo $row["username"]; ?></td>
<td><?php echo $row["password"]; ?></td>
<td><?php echo $row["email"]; ?></td>

**4. 编辑用户管理模块**

<td>
    <div class="action-links">
        <a href="user_edit.php?id=<?php echo $row['id']; ?>" class="action-link edit">
            编辑
        </a>
        <a href="?action=delete&id=<?php echo $row['id']; ?>" class="action-link delete">
            删除
        </a>
    </div>
</td>

数据库的连接与使用

作用

后端连接数据库

用于博客的登录以及文章的储存

数据库创建流程

1.单击 PHPMyAdmin

image\.png

2.创建数据库,并在数据库中,创建表格

image\.png

image\.png

Int 是 整型 id 不可重复,所以作为主键 索引为 : Primary

Varchar 是可变字符串 用来作为名称,密码,以及电子邮箱

向数据库中插入数据

image\.png

连接数据库并实现登录注册的代码以及实例

<?php
header("Content-type:text/html;charset=utf-8");

$username = $_REQUEST["username"];
$password = $_REQUEST["password"];

// 连接数据库mysql
$host = "127.0.0.1";
$dbuser = "root";
$dbpassword = "usbw";
$database = "lyqblog";
$conn = mysqli_connect($host, $dbuser, $dbpassword, $database);
// 第1行 $conn = mysqli_connect(...)连接 MySQL 数据库,传入服务器地址、用户名、密码、数据库名,返回连接对象 $conn。相当于"打开数据库大门"。
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
}
// 查询数据库中的users表 , 并将$username和$password 作为条件查询
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $sql);
//第2行 $result = mysqli_query($conn, $sql)
//用已建立的连接 $conn 执行 SQL 查询语句 $sql,返回查询结果集 $result。相当于"向数据库提问并拿到答案"。
if (!$result){
    echo "查询失败: " . mysqli_error($conn);
    exit;
}
// 如果查询结果为空,则提示用户名或密码错误
if (mysqli_num_rows($result) == 0) {
    echo "用户名或密码错误< a href = "login.html">返回登陆页面</a>";
    exit;
} else {
    echo "登录成功";
}
?>

会出现的bug: 在账户界面输入: ' or 1=1#

会出现万能密码的bug,因为MySQL的语句为 "SELECT * FROM users WHERE username = '$username' AND password = '$password'" 拼接过后是:

"SELECT * FROM users WHERE username = '$username' or 1=1 #' AND password = '$password'"

会执行 or 语句 , 判断 1=1 并且将密码的判断注释掉。会导致出现万能密码的情况。

<input type="hidden" name="login" value="1">
<button type="submit" class="btn" id="submitBtn">登 录</button>  
// 使用input标记,通过使用name,提交login标记
<div class="fs"><input type="hidden" name="register" value="1"><button type="submit" class="btn" id="submitBtn"><span class="bt" id="btnText">注 册</span></button></div>
//使用同样方法,进行name,的register标记

完成登录和注册

<?php
header("Content-type:text/html;charset=utf-8");
// 连接数据库mysql
$host = "127.0.0.1";
$dbuser = "root";
$dbpassword = "usbw";
$database = "lyqblog";
$conn = mysqli_connect($host, $dbuser, $dbpassword, $database);
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
    exit;
}
if (isset($_REQUEST["login"])){
    //从前端接受用户名和密码,并进行查询操作
    $username = $_REQUEST["username"];
    $password = $_REQUEST["password"];
    $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
    $result = mysqli_query($conn, $sql);
    if (!$result){
        echo "查询失败: " . mysqli_error($conn);
        exit;
    }
// 如果查询结果为空,则提示用户名或密码错误
    if (mysqli_num_rows($result) == 0) {
        echo "用户名或密码错误<a href='login.html'>返回登录页面</a>";
        exit;
    } else {
        echo "登录成功";
    }

}else if (isset($_REQUEST["register"])){
    //判断用户名是否存在,或者邮箱是否存在
    $username = $_REQUEST["username"];
    $email = $_REQUEST["email"];
    $sql = "SELECT * FROM users WHERE username = '$username' OR email = '$email'";
    $result = mysqli_query($conn, $sql);
    if (!$result){
        echo "查询失败: " . mysqli_error($conn);
        exit;
    }
    if (mysqli_num_rows($result) > 0) {
        echo "用户名或邮箱已存在<a href='register.html'>返回注册页面</a>";
        exit;
    }
    $password = $_REQUEST["password"];
    $sql = "INSERT INTO users (username, password,email) VALUES ('$username', '$password','$email')";
    $result = mysqli_query($conn, $sql);
    if (!$result){
        echo "注册失败: " . mysqli_error($conn);
        exit;
    }
    echo "注册成功";

}else{
    echo "操作错误";    
}

// // 查询数据库中的users表 , 并将$username和$password 作为条件查询
// $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
// $result = mysqli_query($conn, $sql);
// if (!$result){
//     echo "查询失败: " . mysqli_error($conn);
//     exit;
// }
// // 如果查询结果为空,则提示用户名或密码错误
// if (mysqli_num_rows($result) == 0) {
//     echo "用户名或密码错误<a href='login.html'>返回登录页面</a>";
//     exit;
// } else {
//     echo "登录成功";
// }
?>

完成主页功能

服务器信息:

用户管理:

1.创建users_list.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网站后台管理-用户列表</title>
</head>
<body>
    <table>
        <tr>
            <th>ID</th>
            <th>用户名</th>
            <th>密码</th>
            <th>邮箱</th>
            <th>注册时间</th>
            <th>操作</th>
        </tr>
        <tr>
            <td>admin </td>
            <td>123456</td>
            <td><EMAIL></td>
            <td><a href="user_edit.php?id=1">编辑</a> | <a href="?action=delete&id=1">删除</a><td>
        </tr>
    </table>
</body>
</html>

<a href="/user_edit.php?id=1">编辑</a> | <a href="/?action=delete&id=1">删除</a>

// 这段代码意思为: 编辑两个选项,对不同的网页输入不同的值

user_edit.php?id=1 网页地址 ? 值

action=delete&id=1 当前网页&输入值

2.添加连接数据库功能,并将查询结果进行打印:

<?php
header("Content-type:text/html;charset=utf-8");
// 连接数据库mysql
$host = "127.0.0.1";
$dbuser = "root";
$dbpassword = "usbw";
$database = "lyqblog";
$conn = mysqli_connect($host, $dbuser, $dbpassword, $database);
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
    exit;   
}
//获取users表中的所有数据
$sql = "SELECT * FROM users";
$result = mysqli_query($conn, $sql);
if (!$result) {
    echo "查询失败: " . mysqli_error($conn);
    exit;
}
//将查询的数据一行行进行输出
//mysql_fetch_assoc函数是将查询的数据以关联数组的形式返回,数组的key是字段名,value是字段值
while ($row = mysqli_fetch_assoc($result)) {
    echo "<p>".$row["username"].":".$row["email"].":".$row["password"]."</p>";
}
//关闭数据库连接
mysqli_close($conn);

结果:

image\.png

3.将此模块添加到main.php

代码段实例:

<tbody>
                        <?php
        
                        // 连接数据库mysql
                        $host = "127.0.0.1";
                        $dbuser = "root";
                        $dbpassword = "usbw";
                        $database = "lyqblog";
                        $conn = mysqli_connect($host, $dbuser, $dbpassword, $database);
                        if (!$conn) {
                            die("连接失败: " . mysqli_connect_error());
                            exit;
                        }
                        //获取users表中的所有数据
                        $sql = "SELECT * FROM users";
                        $result = mysqli_query($conn, $sql);
                        if (!$result) {
                            echo "查询失败: " . mysqli_error($conn);
                            exit;
                        }
                        //将查询的数据一行行进行输出
                        //mysql_fetch_assoc函数是将查询的数据以关联数组的形式返回,数组的key是字段名,value是字段值
                        while ($row = mysqli_fetch_assoc($result)) {
                        ?>
                    
                        <tr>
                            <td><?php echo $row["username"]; ?></td>
                            <td><?php echo $row["password"]; ?></td>
                            <td><?php echo $row["email"]; ?></td>
                
                            <td>
                                <div class="action-links">
                                    <a href="user_edit.php?id=1" class="action-link edit">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                                            <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                                        </svg>
                                        编辑
                                    </a>
                                    <a href="?action=delete&id=1" class="action-link delete">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <polyline points="3 6 5 6 21 6"></polyline>
                                            <path
                                                d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
                                            </path>
                                            <line x1="10" y1="11" x2="10" y2="17"></line>
                                            <line x1="14" y1="11" x2="14" y2="17"></line>
                                        </svg>
                                        删除
                                    </a>
                                </div>
                            </td>
                        </tr>
                        <?php
                        }
                        ?>
                    </tbody>

1.mysqli_fetch_assoc() 每次从结果集取一行

↓

返回关联数组: ["username"=>"admin", "password"=>"123456", "email"=>"admin@163.com", ...]

↓

赋值给 $row,while 条件为 true → 进入循环体

↓

?> 退出PHP → 输出纯HTML(用<?php echo $row["xxx"]?>插入值) → <?php回到PHP

↓

循环 → 再取下一行 → 直到所有行取完,返回 null → while 条件为 false → 循环结束

2. <td><?php echo $row["username"]; ?></td> <td><?php echo $row["password"]; ?></td> <td><?php echo $row["email"]; ?></td>

// 将从数据库中的数据再次使用php语言输出到前端。

4.编辑用管理模块

<td>
                                <div class="action-links">
                                    <a href="user_edit.php?id=<?php echo $row["id"]; ?>" class="action-link edit">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                                            <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                                        </svg>
                                        编辑
                                    </a>
                                    <a href="?action=delete&id=<?php echo $row["id"]; ?>" class="action-link delete">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <polyline points="3 6 5 6 21 6"></polyline>
                                            <path
                                                d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
                                            </path>
                                            <line x1="10" y1="11" x2="10" y2="17"></line>
                                            <line x1="14" y1="11" x2="14" y2="17"></line>
                                        </svg>
                                        删除
                                    </a>
                                </div>
                            </td>

同样通过php语句将按键的id传入<a href="/user_edit.php?id=<?php echo $row["id"]; ?>" class="action-link edit">

image\.png

完成用户列表

创建db.php

<?php
//连接数据库
header("Content-type:text/html;charset=utf-8");
// 连接数据库mysql
$host = "127.0.0.1";
$dbuser = "root";
$dbpassword = "usbw";
$database = "lyqblog";
$conn = mysqli_connect($host, $dbuser, $dbpassword, $database);
if (!$conn) {
    die("连接失败: " . mysqli_connect_error());
    exit;
}
// 模块化使用,方便直接从数据库中调用数据。

创建users_list.php

<?php include("db.php"); ?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网站后台管理-用户列表</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
    <style>
        :root {
            --indigo: #6366f1; --indigo-l: #818cf8; --violet: #8b5cf6;
            --cyan: #22d3ee; --emerald: #34d399; --rose: #fb7185;
            --bg0: #050810; --bg1: #0a0e1a;
            --sf1: rgba(255,255,255,0.018); --sf2: rgba(255,255,255,0.035);
            --t1: #f0f4ff; --t2: #c4ccdf; --t3: #7a86a1; --t4: #4a5568;
            --edge: rgba(255,255,255,0.06); --edge-h: rgba(255,255,255,0.12);
            --r: 16px; --rl: 22px;
            --ease: cubic-bezier(0.22,1,0.36,1);
            --bounce: cubic-bezier(0.34,1.56,0.64,1);
        }
        * { margin:0; padding:0; box-sizing:border-box; }
        html { scroll-behavior:smooth; overflow-x:hidden; }
        body {
            font-family:'Inter',system-ui,-apple-system,sans-serif;
            background:var(--bg0); color:var(--t1);
            min-height:100vh; display:flex; flex-direction:column;
            -webkit-font-smoothing:antialiased; overflow-x:hidden;
        }

        /* Ambient */
        .ambient { position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
        .orb { position:absolute; border-radius:50%; filter:blur(120px); opacity:0.3; will-change:transform; }
        .orb:nth-child(1) { width:600px; height:600px; background:var(--indigo); top:-20%; left:-10%; animation:od1 18s ease-in-out infinite alternate; }
        .orb:nth-child(2) { width:500px; height:500px; background:var(--cyan); bottom:-15%; right:-8%; animation:od2 22s ease-in-out infinite alternate; }
        .orb:nth-child(3) { width:350px; height:350px; background:var(--violet); top:40%; left:50%; opacity:0.15; animation:od3 15s ease-in-out infinite alternate; }
        @keyframes od1 { to { transform:translate(120px,80px) scale(1.1); } }
        @keyframes od2 { to { transform:translate(-100px,-60px) scale(0.9); } }
        @keyframes od3 { to { transform:translate(-80px,60px) scale(1.15); } }
        .ambient::after {
            content:''; position:absolute; inset:0;
            background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(/%23n)' opacity='0.03'/%3E%3C/svg%3E");
            background-size:256px; opacity:0.4; mix-blend-mode:overlay;
        }
        .grid-bg {
            position:absolute; inset:0;
            background-image:linear-gradient(rgba(255,255,255,0.015) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.015) 1px,transparent 1px);
            background-size:60px 60px;
            mask-image:radial-gradient(ellipse 70% 50% at 50% 30%,black,transparent);
        }

        /* Header */
        .header {
            position:sticky; top:0; z-index:100; height:58px; padding:0 28px;
            display:flex; align-items:center; justify-content:space-between;
            background:linear-gradient(180deg,rgba(15,20,35,0.92),rgba(10,14,26,0.88));
            backdrop-filter:blur(30px) saturate(1.4) brightness(1.1);
            border-bottom:1px solid var(--edge);
            box-shadow:0 1px 0 rgba(255,255,255,0.03) inset,0 4px 24px rgba(0,0,0,0.3);
        }
        .header-title { font-size:14px; font-weight:600; display:flex; align-items:center; gap:10px; }
        .beacon {
            width:7px; height:7px; border-radius:50%; background:var(--emerald);
            box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3);
            animation:bpulse 2.5s ease-in-out infinite;
        }
        @keyframes bpulse { 0%,100%{box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3)} 50%{box-shadow:0 0 10px var(--emerald),0 0 28px rgba(52,211,153,0.5)} }
        .header-user { display:flex; align-items:center; gap:10px; }
        .avatar {
            width:30px; height:30px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            display:flex; align-items:center; justify-content:center;
            font-weight:700; font-size:11px; color:#fff; cursor:pointer; position:relative;
            transition:transform 0.4s var(--bounce);
        }
        .avatar::after {
            content:''; position:absolute; inset:-2px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            z-index:-1; opacity:0; filter:blur(6px); transition:opacity 0.4s;
        }
        .avatar:hover { transform:scale(1.12); }
        .avatar:hover::after { opacity:0.6; }
        .user-name { font-size:12px; font-weight:500; color:var(--t2); }
        .logout-btn {
            width:30px; height:30px; border-radius:8px; border:1px solid var(--edge);
            background:rgba(255,255,255,0.03); color:var(--t3); cursor:pointer;
            display:flex; align-items:center; justify-content:center;
            transition:all 0.3s var(--ease); padding:0; margin-left:6px;
        }
        .logout-btn svg { width:14px; height:14px; }
        .logout-btn:hover { background:rgba(251,113,133,0.1); border-color:rgba(251,113,133,0.3); color:var(--rose); transform:translateY(-1px); }
        .logout-btn:active { transform:translateY(0); }

        /* Layout */
        .main-container { display:flex; flex:1; min-height:calc(100vh - 58px); position:relative; z-index:1; }

        /* Sidebar */
        .sidebar {
            width:230px; flex-shrink:0;
            background:linear-gradient(180deg,rgba(12,16,28,0.85),rgba(8,11,20,0.9));
            backdrop-filter:blur(24px); border-right:1px solid var(--edge);
            padding:20px 0; display:flex; flex-direction:column; position:relative;
        }
        .sidebar::after {
            content:''; position:absolute; top:0; right:0; width:1px; height:100%;
            background:linear-gradient(180deg,rgba(99,102,241,0.15),transparent 50%,rgba(34,211,238,0.1));
        }
        .nav-section { margin-bottom:24px; }
        .nav-title { font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:0.14em; color:var(--t4); padding:0 16px; margin-bottom:10px; }
        .nav-links { display:flex; flex-direction:column; gap:2px; padding:0 6px; }
        .nav-link {
            display:flex; align-items:center; gap:10px; padding:10px 12px;
            color:var(--t3); text-decoration:none; font-size:13px; font-weight:500;
            border-radius:10px; transition:all 0.3s var(--ease); position:relative; overflow:hidden;
        }
        .nav-link::before {
            content:''; position:absolute; inset:0;
            background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,0.04) 50%,transparent 60%);
            transform:translateX(-100%); transition:transform 0.6s var(--ease);
        }
        .nav-link:hover::before { transform:translateX(100%); }
        .nav-link:hover { background:var(--sf2); color:var(--t1); }
        .nav-link.active {
            background:linear-gradient(135deg,rgba(99,102,241,0.12),rgba(139,92,246,0.08));
            color:var(--indigo-l); box-shadow:0 0 0 1px rgba(99,102,241,0.15) inset;
        }
        .nav-link.active::after {
            content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
            width:3px; height:18px; border-radius:0 3px 3px 0;
            background:linear-gradient(180deg,var(--indigo),var(--violet));
            box-shadow:0 0 10px rgba(99,102,241,0.4);
            animation:igrow 0.35s var(--bounce);
        }
        @keyframes igrow { from{height:0;opacity:0} to{height:18px;opacity:1} }
        .nav-link svg { width:16px; height:16px; flex-shrink:0; opacity:0.6; transition:all 0.3s var(--ease); }
        .nav-link:hover svg, .nav-link.active svg { opacity:1; }
        .nav-link.active svg { filter:drop-shadow(0 0 4px rgba(99,102,241,0.4)); }

        /* Content */
        .content { flex:1; padding:36px 40px; overflow-y:auto; }
        .content-header { margin-bottom:32px; opacity:0; animation:rup 0.7s var(--ease) 0.1s forwards; }
        .content-title {
            font-size:28px; font-weight:800; letter-spacing:-0.03em;
            background:linear-gradient(135deg,var(--t1) 30%,var(--indigo-l));
            -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text;
            margin-bottom:6px;
        }
        .content-subtitle { font-size:13px; color:var(--t3); }

        /* Table Container */
        .table-container {
            background:linear-gradient(165deg,rgba(255,255,255,0.04),rgba(255,255,255,0.01));
            border:1px solid var(--edge); border-radius:var(--rl); padding:28px;
            position:relative; overflow:hidden; opacity:0;
            animation:creveal 0.7s var(--ease) 0.2s forwards;
        }
        .table-container::before {
            content:''; position:absolute; top:0; left:0; right:0; height:1px;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.08) 20%,var(--indigo) 50%,rgba(255,255,255,0.08) 80%,transparent);
            opacity:0; transition:opacity 0.5s;
        }
        .table-container::after {
            content:''; position:absolute; inset:0;
            background:radial-gradient(600px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,0.04),transparent 40%);
            opacity:0; transition:opacity 0.4s; pointer-events:none; border-radius:inherit;
        }
        .table-container:hover::before, .table-container:hover::after { opacity:1; }
        .table-container:hover {
            border-color:var(--edge-h);
            box-shadow:0 8px 32px -8px rgba(0,0,0,0.5),0 0 0 1px rgba(255,255,255,0.04);
        }

        .table-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:24px; position:relative; z-index:1; }
        .table-title { font-size:18px; font-weight:700; color:var(--t1); letter-spacing:-0.02em; }
        .table-desc { font-size:12px; color:var(--t3); margin-top:4px; }

        /* Table */
        .data-table { width:100%; border-collapse:collapse; position:relative; z-index:1; }
        .data-table th {
            font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.08em;
            color:var(--indigo-l); text-align:left; padding:14px 18px;
            border-bottom:1px solid var(--edge); background:rgba(99,102,241,0.06);
        }
        .data-table th:first-child { border-radius:10px 0 0 0; }
        .data-table th:last-child { border-radius:0 10px 0 0; }
        .data-table td {
            padding:14px 18px; border-bottom:1px solid var(--edge);
            font-size:13px; color:var(--t2); transition:all 0.25s var(--ease);
        }
        .data-table tr { transition:all 0.25s var(--ease); }
        .data-table tbody tr:hover {
            background:linear-gradient(90deg,rgba(99,102,241,0.04),transparent);
        }
        .data-table tbody tr:hover td { color:var(--t1); }
        .data-table tr:last-child td { border-bottom:none; }

        /* Action Links */
        .action-links { display:flex; gap:8px; }
        .action-link {
            display:inline-flex; align-items:center; gap:5px; padding:6px 14px;
            border-radius:8px; font-size:12px; font-weight:500; text-decoration:none;
            transition:all 0.3s var(--ease); border:1px solid transparent;
        }
        .action-link.edit {
            background:rgba(99,102,241,0.08); color:var(--indigo-l);
            border-color:rgba(99,102,241,0.15);
        }
        .action-link.edit:hover {
            background:rgba(99,102,241,0.18); border-color:rgba(99,102,241,0.3);
            transform:translateY(-1px); box-shadow:0 4px 12px rgba(99,102,241,0.15);
        }
        .action-link.delete {
            background:rgba(251,113,133,0.08); color:var(--rose);
            border-color:rgba(251,113,133,0.15);
        }
        .action-link.delete:hover {
            background:rgba(251,113,133,0.18); border-color:rgba(251,113,133,0.3);
            transform:translateY(-1px); box-shadow:0 4px 12px rgba(251,113,133,0.15);
        }
        .action-link svg { width:13px; height:13px; }

        /* Add User Button */
        .add-user-btn {
            display:inline-flex; align-items:center; gap:8px; padding:10px 20px;
            background:linear-gradient(135deg,rgba(52,211,153,0.15),rgba(52,211,153,0.08));
            border:1px solid rgba(52,211,153,0.25); border-radius:10px;
            color:var(--emerald); font-size:13px; font-weight:600; text-decoration:none;
            transition:all 0.35s var(--ease); position:relative; overflow:hidden;
        }
        .add-user-btn::before {
            content:''; position:absolute; top:0; left:-100%; width:100%; height:100%;
            background:linear-gradient(90deg,transparent,rgba(52,211,153,0.15),transparent);
            transition:left 0.6s var(--ease);
        }
        .add-user-btn:hover {
            background:linear-gradient(135deg,rgba(52,211,153,0.25),rgba(52,211,153,0.15));
            border-color:rgba(52,211,153,0.4); transform:translateY(-2px);
            box-shadow:0 6px 20px rgba(52,211,153,0.2);
        }
        .add-user-btn:hover::before { left:100%; }
        .add-user-btn:active { transform:translateY(0); transition-duration:0.1s; }
        .add-user-btn svg { width:16px; height:16px; }

        /* Animations */
        @keyframes rup { from{opacity:0;transform:translateY(20px)} to{opacity:1;transform:translateY(0)} }
        @keyframes creveal { from{opacity:0;transform:translateY(24px) scale(0.96);filter:blur(4px)} to{opacity:1;transform:translateY(0) scale(1);filter:blur(0)} }

        /* Scrollbar */
        ::-webkit-scrollbar { width:5px; }
        ::-webkit-scrollbar-track { background:transparent; }
        ::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.08); border-radius:3px; }
        ::-webkit-scrollbar-thumb:hover { background:rgba(255,255,255,0.14); }

        /* Responsive */
        @media(max-width:1100px) { .content{padding:28px 24px} }
        @media(max-width:960px) { .sidebar{width:200px} }
        @media(max-width:768px) {
            .main-container{flex-direction:column}
            .sidebar{width:100%;border-right:none;border-bottom:1px solid var(--edge);padding:10px 0}
            .sidebar::after{display:none}
            .nav-links{flex-direction:row;overflow-x:auto;padding:0 10px;gap:4px;-webkit-overflow-scrolling:touch}
            .nav-link{padding:8px 14px;white-space:nowrap;font-size:12px;border-radius:8px}
            .nav-link.active::after{display:none}
            .content{padding:24px 18px}
            .table-container{padding:16px}
            .data-table{display:block;overflow-x:auto}
            .content-title{font-size:22px}
            .orb{opacity:0.2}
        }
        @media(max-width:480px) {
            .header{padding:0 16px;height:52px}
            .content{padding:18px 14px}
            .table-header{flex-direction:column;align-items:flex-start;gap:8px}
            .action-links{flex-direction:column;gap:6px}
            .action-link{width:100%;justify-content:center}
        }
        /* Auth-gated elements: hidden by default, shown via JS when logged in */
        .action-link, .add-user-btn { opacity:0; pointer-events:none; transition:opacity 0.3s var(--ease); }
        @media(prefers-reduced-motion:reduce) { *,*::before,*::after{animation-duration:0.01ms!important;animation-delay:0ms!important;transition-duration:0.01ms!important} .orb{animation:none!important} }
    </style>
</head>
<body>
    <div class="ambient">
        <div class="orb"></div><div class="orb"></div><div class="orb"></div>
        <div class="grid-bg"></div>
    </div>

    <header class="header">
        <div class="header-title"><span class="beacon"></span>网站后台管理</div>
        <div class="header-user">
            <div class="avatar" id="headerAvatar">A</div>
            <div class="user-name" id="headerUserName">管理员</div>
            <button class="logout-btn" id="logoutBtn" title="退出登录">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
            </button>
        </div>
    </header>

    <div class="main-container">
        <aside class="sidebar">
            <div class="nav-section">
                <div class="nav-title">导航菜单</div>
                <div class="nav-links">
                    <a href="main.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
                        网站信息
                    </a>
                    <a href="articles.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
                        文章管理
                    </a>
                    <a href="users_list.php" class="nav-link active">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
                        用户管理
                    </a>
                </div>
            </div>
        </aside>

        <main class="content">
            <div class="content-header">
                <h1 class="content-title">用户管理</h1>
                <p class="content-subtitle">管理系统中的所有用户账户</p>
            </div>

            <div class="table-container">
                <div class="table-header">
                    <div>
                        <div class="table-title">用户列表</div>
                        <div class="table-desc">显示所有注册用户的信息</div>
                    </div>
                    <a href="users_add.php" class="add-user-btn">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
                        添加用户
                    </a>
                </div>

                <table class="data-table">
                    <thead>
                        <tr>
                            <th>ID</th>
                            <th>用户名</th>
                            <th>密码</th>
                            <th>邮箱</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php
                        //获取users表中的所有数据
                        $sql = "SELECT * FROM users";
                        $result = mysqli_query($conn, $sql);
                        if (!$result) {
                            echo "查询失败: " . mysqli_error($conn);
                            exit;
                        }
                        //将查询的数据一行行进行输出
                        //mysql_fetch_assoc函数是将查询的数据以关联数组的形式返回,数组的key是字段名,value是字段值
                        while ($row = mysqli_fetch_assoc($result)) {
                        ?>
                    
                        <tr>
                            <td><?php echo $row["id"]; ?></td>
                            <td><?php echo $row["username"]; ?></td>
                            <td><?php echo $row["password"]; ?></td>
                            <td><?php echo $row["email"]; ?></td>
                            
                            <td>
                                <div class="action-links">
                                
                                    <a href="users_edit.php?id=<?php echo $row["id"]; ?>" class="action-link edit">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                                            <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                                        </svg>
                                        编辑
                                    </a>
                                   <a href="users.php?del&id=<?php echo $row["id"]; ?>" class="action-link delete">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                                            stroke-linecap="round" stroke-linejoin="round">
                                            <polyline points="3 6 5 6 21 6"></polyline>
                                            <path
                                                d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
                                            </path>
                                            <line x1="10" y1="11" x2="10" y2="17"></line>
                                            <line x1="14" y1="11" x2="14" y2="17"></line>
                                        </svg>
                                        删除
                                    </a>
                                    

                                </div>
                            </td>
                        </tr>
                        <?php
                        }
                        ?>
                    </tbody>
                </table>
            </div>
        </main>
    </div>

    <script>
        // ── 前端登录状态检查与权限控制 ──
        (function(){
            var auth = localStorage.getItem('admin_auth');
            if(!auth){
                window.location.href = 'login.php';
                return;
            }
            try{
                var data = JSON.parse(auth);
                var avatar = document.getElementById('headerAvatar');
                var nameEl = document.getElementById('headerUserName');
                if(data.username){
                    avatar.textContent = data.username.charAt(0).toUpperCase();
                    nameEl.textContent = data.username;
                }
                // 仅管理员(lyq)可见管理操作
                if(data.username === 'lyq'){
                    document.querySelectorAll('.action-link, .add-user-btn').forEach(function(el){
                        el.style.opacity = '1';
                        el.style.pointerEvents = 'auto';
                    });
                }
            }catch(e){}

            document.getElementById('logoutBtn').addEventListener('click', function(){
                localStorage.removeItem('admin_auth');
                window.location.href = 'login.php';
            });
        })();

        // 3D light reflection tracking
        document.querySelector('.table-container').addEventListener('mousemove', e => {
            const r = e.currentTarget.getBoundingClientRect();
            e.currentTarget.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
            e.currentTarget.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
        });

        // Scroll parallax
        let ticking = false;
        const orbs = document.querySelectorAll('.orb');
        window.addEventListener('scroll', () => {
            if (!ticking) {
                requestAnimationFrame(() => {
                    const y = window.scrollY;
                    orbs[0].style.transform = `translate(${y*0.02}px,${y*0.03}px)`;
                    orbs[1].style.transform = `translate(${-y*0.015}px,${-y*0.025}px)`;
                    orbs[2].style.transform = `translate(${y*0.01}px,${y*0.02}px)`;
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });
    </script>
</body>
</html>

创建users_add.php

<?php include("db.php");?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网站后台管理-用户添加</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
    <style>
        :root {
            --indigo: #6366f1; --indigo-l: #818cf8; --violet: #8b5cf6;
            --cyan: #22d3ee; --emerald: #34d399; --rose: #fb7185;
            --bg0: #050810; --bg1: #0a0e1a;
            --sf1: rgba(255,255,255,0.018); --sf2: rgba(255,255,255,0.035);
            --t1: #f0f4ff; --t2: #c4ccdf; --t3: #7a86a1; --t4: #4a5568;
            --edge: rgba(255,255,255,0.06); --edge-h: rgba(255,255,255,0.12);
            --r: 16px; --rl: 22px;
            --ease: cubic-bezier(0.22,1,0.36,1);
            --bounce: cubic-bezier(0.34,1.56,0.64,1);
        }
        * { margin:0; padding:0; box-sizing:border-box; }
        html { scroll-behavior:smooth; overflow-x:hidden; }
        body {
            font-family:'Inter',system-ui,-apple-system,sans-serif;
            background:var(--bg0); color:var(--t1);
            min-height:100vh; display:flex; flex-direction:column;
            -webkit-font-smoothing:antialiased; overflow-x:hidden;
        }

        /* Ambient */
        .ambient { position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
        .orb { position:absolute; border-radius:50%; filter:blur(120px); opacity:0.3; will-change:transform; }
        .orb:nth-child(1) { width:600px; height:600px; background:var(--indigo); top:-20%; left:-10%; animation:od1 18s ease-in-out infinite alternate; }
        .orb:nth-child(2) { width:500px; height:500px; background:var(--cyan); bottom:-15%; right:-8%; animation:od2 22s ease-in-out infinite alternate; }
        .orb:nth-child(3) { width:350px; height:350px; background:var(--violet); top:40%; left:50%; opacity:0.15; animation:od3 15s ease-in-out infinite alternate; }
        @keyframes od1 { to { transform:translate(120px,80px) scale(1.1); } }
        @keyframes od2 { to { transform:translate(-100px,-60px) scale(0.9); } }
        @keyframes od3 { to { transform:translate(-80px,60px) scale(1.15); } }
        .ambient::after {
            content:''; position:absolute; inset:0;
            background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(/%23n)' opacity='0.03'/%3E%3C/svg%3E");
            background-size:256px; opacity:0.4; mix-blend-mode:overlay;
        }
        .grid-bg {
            position:absolute; inset:0;
            background-image:linear-gradient(rgba(255,255,255,0.015) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.015) 1px,transparent 1px);
            background-size:60px 60px;
            mask-image:radial-gradient(ellipse 70% 50% at 50% 30%,black,transparent);
        }

        /* Header */
        .header {
            position:sticky; top:0; z-index:100; height:58px; padding:0 28px;
            display:flex; align-items:center; justify-content:space-between;
            background:linear-gradient(180deg,rgba(15,20,35,0.92),rgba(10,14,26,0.88));
            backdrop-filter:blur(30px) saturate(1.4) brightness(1.1);
            border-bottom:1px solid var(--edge);
            box-shadow:0 1px 0 rgba(255,255,255,0.03) inset,0 4px 24px rgba(0,0,0,0.3);
        }
        .header-title { font-size:14px; font-weight:600; display:flex; align-items:center; gap:10px; }
        .beacon {
            width:7px; height:7px; border-radius:50%; background:var(--emerald);
            box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3);
            animation:bpulse 2.5s ease-in-out infinite;
        }
        @keyframes bpulse { 0%,100%{box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3)} 50%{box-shadow:0 0 10px var(--emerald),0 0 28px rgba(52,211,153,0.5)} }
        .header-user { display:flex; align-items:center; gap:10px; }
        .avatar {
            width:30px; height:30px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            display:flex; align-items:center; justify-content:center;
            font-weight:700; font-size:11px; color:#fff; cursor:pointer; position:relative;
            transition:transform 0.4s var(--bounce);
        }
        .avatar::after {
            content:''; position:absolute; inset:-2px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            z-index:-1; opacity:0; filter:blur(6px); transition:opacity 0.4s;
        }
        .avatar:hover { transform:scale(1.12); }
        .avatar:hover::after { opacity:0.6; }
        .user-name { font-size:12px; font-weight:500; color:var(--t2); }
        .logout-btn {
            width:30px; height:30px; border-radius:8px; border:1px solid var(--edge);
            background:rgba(255,255,255,0.03); color:var(--t3); cursor:pointer;
            display:flex; align-items:center; justify-content:center;
            transition:all 0.3s var(--ease); padding:0; margin-left:6px;
        }
        .logout-btn svg { width:14px; height:14px; }
        .logout-btn:hover { background:rgba(251,113,133,0.1); border-color:rgba(251,113,133,0.3); color:var(--rose); transform:translateY(-1px); }
        .logout-btn:active { transform:translateY(0); }

        /* Layout */
        .main-container { display:flex; flex:1; min-height:calc(100vh - 58px); position:relative; z-index:1; }

        /* Sidebar */
        .sidebar {
            width:230px; flex-shrink:0;
            background:linear-gradient(180deg,rgba(12,16,28,0.85),rgba(8,11,20,0.9));
            backdrop-filter:blur(24px); border-right:1px solid var(--edge);
            padding:20px 0; display:flex; flex-direction:column; position:relative;
        }
        .sidebar::after {
            content:''; position:absolute; top:0; right:0; width:1px; height:100%;
            background:linear-gradient(180deg,rgba(99,102,241,0.15),transparent 50%,rgba(34,211,238,0.1));
        }
        .nav-section { margin-bottom:24px; }
        .nav-title { font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:0.14em; color:var(--t4); padding:0 16px; margin-bottom:10px; }
        .nav-links { display:flex; flex-direction:column; gap:2px; padding:0 6px; }
        .nav-link {
            display:flex; align-items:center; gap:10px; padding:10px 12px;
            color:var(--t3); text-decoration:none; font-size:13px; font-weight:500;
            border-radius:10px; transition:all 0.3s var(--ease); position:relative; overflow:hidden;
        }
        .nav-link::before {
            content:''; position:absolute; inset:0;
            background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,0.04) 50%,transparent 60%);
            transform:translateX(-100%); transition:transform 0.6s var(--ease);
        }
        .nav-link:hover::before { transform:translateX(100%); }
        .nav-link:hover { background:var(--sf2); color:var(--t1); }
        .nav-link.active {
            background:linear-gradient(135deg,rgba(99,102,241,0.12),rgba(139,92,246,0.08));
            color:var(--indigo-l); box-shadow:0 0 0 1px rgba(99,102,241,0.15) inset;
        }
        .nav-link.active::after {
            content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
            width:3px; height:18px; border-radius:0 3px 3px 0;
            background:linear-gradient(180deg,var(--indigo),var(--violet));
            box-shadow:0 0 10px rgba(99,102,241,0.4);
            animation:igrow 0.35s var(--bounce);
        }
        @keyframes igrow { from{height:0;opacity:0} to{height:18px;opacity:1} }
        .nav-link svg { width:16px; height:16px; flex-shrink:0; opacity:0.6; transition:all 0.3s var(--ease); }
        .nav-link:hover svg, .nav-link.active svg { opacity:1; }
        .nav-link.active svg { filter:drop-shadow(0 0 4px rgba(99,102,241,0.4)); }

        /* Content */
        .content { flex:1; padding:36px 40px; overflow-y:auto; display:flex; justify-content:center; }
        .content-inner { width:100%; max-width:600px; }
        .content-header { margin-bottom:32px; opacity:0; animation:rup 0.7s var(--ease) 0.1s forwards; }
        .content-title {
            font-size:28px; font-weight:800; letter-spacing:-0.03em;
            background:linear-gradient(135deg,var(--t1) 30%,var(--indigo-l));
            -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text;
            margin-bottom:6px;
        }
        .content-subtitle { font-size:13px; color:var(--t3); }

        /* Form Card */
        .form-card {
            background:linear-gradient(165deg,rgba(255,255,255,0.04),rgba(255,255,255,0.01));
            border:1px solid var(--edge); border-radius:var(--rl); padding:32px;
            position:relative; overflow:hidden; opacity:0;
            animation:creveal 0.7s var(--ease) 0.2s forwards;
        }
        .form-card::before {
            content:''; position:absolute; top:0; left:0; right:0; height:1px;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.08) 20%,var(--indigo) 50%,rgba(255,255,255,0.08) 80%,transparent);
            opacity:0; transition:opacity 0.5s;
        }
        .form-card::after {
            content:''; position:absolute; inset:0;
            background:radial-gradient(600px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,0.04),transparent 40%);
            opacity:0; transition:opacity 0.4s; pointer-events:none; border-radius:inherit;
        }
        .form-card:hover::before, .form-card:hover::after { opacity:1; }
        .form-card:hover { border-color:var(--edge-h); box-shadow:0 8px 32px -8px rgba(0,0,0,0.5); }

        /* Form Elements */
        .form-group { margin-bottom:20px; position:relative; z-index:1; }
        .form-label {
            display:block; font-size:11px; font-weight:600; text-transform:uppercase;
            letter-spacing:0.08em; color:var(--t3); margin-bottom:8px;
        }
        .form-input {
            width:100%; padding:12px 16px; font-size:14px; font-family:inherit;
            color:var(--t1); background:rgba(255,255,255,0.03);
            border:1px solid var(--edge); border-radius:10px;
            outline:none; transition:all 0.3s var(--ease);
        }
        .form-input::placeholder { color:var(--t4); }
        .form-input:focus {
            border-color:rgba(99,102,241,0.4);
            background:rgba(99,102,241,0.04);
            box-shadow:0 0 0 3px rgba(99,102,241,0.08);
        }
        .form-input:hover:not(:focus) {
            border-color:var(--edge-h);
            background:rgba(255,255,255,0.04);
        }
        .form-hint {
            font-size:11px; color:var(--t4); margin-top:6px; display:flex;
            align-items:center; gap:4px;
        }
        .form-hint svg { width:12px; height:12px; opacity:0.6; }

        /* Section Divider */
        .form-divider {
            height:1px; background:var(--edge); margin:24px 0; position:relative; z-index:1;
        }
        .form-section-title {
            font-size:10px; font-weight:600; text-transform:uppercase;
            letter-spacing:0.1em; color:var(--indigo-l); margin-bottom:16px;
            position:relative; z-index:1;
        }

        /* Submit Button */
        .btn-submit {
            width:100%; padding:14px 24px; font-size:14px; font-weight:600;
            font-family:inherit; color:#fff; border:none; border-radius:10px;
            cursor:pointer; position:relative; z-index:1; overflow:hidden;
            background:linear-gradient(135deg,var(--indigo),var(--violet));
            transition:all 0.3s var(--ease);
            box-shadow:0 4px 16px rgba(99,102,241,0.25);
        }
        .btn-submit::before {
            content:''; position:absolute; top:0; left:-100%; width:100%; height:100%;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);
            transition:left 0.5s var(--ease);
        }
        .btn-submit:hover {
            transform:translateY(-2px);
            box-shadow:0 8px 24px rgba(99,102,241,0.35);
        }
        .btn-submit:hover::before { left:100%; }
        .btn-submit:active { transform:translateY(0); }

        /* Button Group */
        .btn-group {
            margin-top:24px; position:relative; z-index:1;
        }
        .btn-primary {
            width:100%; padding:14px 24px; font-size:14px; font-weight:600;
            font-family:inherit; color:#fff; border:none; border-radius:10px;
            cursor:pointer; position:relative; overflow:hidden;
            background:linear-gradient(135deg,var(--indigo),var(--violet));
            transition:all 0.3s var(--ease);
            box-shadow:0 4px 16px rgba(99,102,241,0.25);
        }
        .btn-primary::before {
            content:''; position:absolute; top:0; left:-100%; width:100%; height:100%;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);
            transition:left 0.5s var(--ease);
        }
        .btn-primary:hover {
            transform:translateY(-2px);
            box-shadow:0 8px 24px rgba(99,102,241,0.35);
        }
        .btn-primary:hover::before { left:100%; }
        .btn-primary:active { transform:translateY(0); }
        .btn-primary:active::after {
            content:''; position:absolute; inset:0; border-radius:inherit;
            background:radial-gradient(circle at 50% 50%,rgba(255,255,255,0.2),transparent 60%);
            animation:ripple 0.4s var(--ease);
        }

        /* Back Link */
        .back-link {
            display:inline-flex; align-items:center; gap:6px; margin-top:16px;
            font-size:12px; color:var(--t3); text-decoration:none;
            transition:all 0.3s var(--ease); position:relative; z-index:1;
        }
        .back-link:hover { color:var(--indigo-l); transform:translateX(-2px); }
        .back-link svg { width:14px; height:14px; }

        /* Animations */
        @keyframes rup { from{opacity:0;transform:translateY(20px)} to{opacity:1;transform:translateY(0)} }
        @keyframes creveal { from{opacity:0;transform:translateY(24px) scale(0.96);filter:blur(4px)} to{opacity:1;transform:translateY(0) scale(1);filter:blur(0)} }
        @keyframes ripple { from{transform:scale(0);opacity:1} to{transform:scale(2.5);opacity:0} }

        /* Scrollbar */
        ::-webkit-scrollbar { width:5px; }
        ::-webkit-scrollbar-track { background:transparent; }
        ::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.08); border-radius:3px; }
        ::-webkit-scrollbar-thumb:hover { background:rgba(255,255,255,0.14); }

        /* Responsive */
        @media(max-width:1100px) { .content{padding:28px 24px} }
        @media(max-width:960px) { .sidebar{width:200px} }
        @media(max-width:768px) {
            .main-container{flex-direction:column}
            .sidebar{width:100%;border-right:none;border-bottom:1px solid var(--edge);padding:10px 0}
            .sidebar::after{display:none}
            .nav-links{flex-direction:row;overflow-x:auto;padding:0 10px;gap:4px;-webkit-overflow-scrolling:touch}
            .nav-link{padding:8px 14px;white-space:nowrap;font-size:12px;border-radius:8px}
            .nav-link.active::after{display:none}
            .content{padding:24px 18px}
            .form-card{padding:24px}
            .content-title{font-size:22px}
            .orb{opacity:0.2}
        }
        @media(max-width:480px) { .header{padding:0 16px;height:52px} .content{padding:18px 14px} }
        @media(prefers-reduced-motion:reduce) { *,*::before,*::after{animation-duration:0.01ms!important;animation-delay:0ms!important;transition-duration:0.01ms!important} .orb{animation:none!important} }
    </style>
</head>
<body>
    <div class="ambient">
        <div class="orb"></div><div class="orb"></div><div class="orb"></div>
        <div class="grid-bg"></div>
    </div>

    <header class="header">
        <div class="header-title"><span class="beacon"></span>网站后台管理</div>
        <div class="header-user">
            <div class="avatar" id="headerAvatar">A</div>
            <div class="user-name" id="headerUserName">管理员</div>
            <button class="logout-btn" id="logoutBtn" title="退出登录">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
            </button>
        </div>
    </header>

    <div class="main-container">
        <aside class="sidebar">
            <div class="nav-section">
                <div class="nav-title">导航菜单</div>
                <div class="nav-links">
                    <a href="main.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
                        网站信息
                    </a>
                    <a href="articles.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
                        文章管理
                    </a>
                    <a href="users_list.php" class="nav-link active">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
                        用户管理
                    </a>
                </div>
            </div>
        </aside>

        <main class="content">
            <div class="content-inner">
                <div class="content-header">
                    <h1 class="content-title">添加用户</h1>
                    <p class="content-subtitle">添加用户账户信息</p>
                </div>

                <?php
                // 添加用户页面不需要查询现有用户信息
                // 表单字段为空,由用户输入新数据
                ?>

                <div class="form-card">
                    <form action="users.php" method="post">
                        <input type="hidden" name="register" value="1">
                        <div class="form-section-title">基本信息</div>

                        <div class="form-group">
                            <label class="form-label" for="username">用户名</label>
                            <input class="form-input" type="text" id="username" name="username" placeholder="请输入用户名"  required>
                        </div>

                        <div class="form-group">
                            <label class="form-label" for="email">邮箱</label>
                            <input class="form-input" type="email" id="email" name="email" placeholder="请输入邮箱" required>
                        </div>

                        <div class="form-divider"></div>
                        <div class="form-section-title">密码设置</div>

                        <div class="form-group">
                            <label class="form-label" for="password">密码</label>
                            <input class="form-input" type="password" id="password" name="password" placeholder="请输入密码" required>
                        </div>

                        <div class="form-group">
                            <label class="form-label" for="repassword">确认密码</label>
                            <input class="form-input" type="password" id="repassword" name="repassword" placeholder="请再次确认密码" required>
                        </div>

                        <div class="btn-group">
                            <input type="submit" class="btn btn-primary" value="添加" name="add">
                        </div>
                       
                    </form>
                </div>

                <a href="users_list.php" class="back-link">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
                    返回用户列表
                </a>
            </div>
        </main>
    </div>

    <script>
        // ── 前端登录状态检查 ──
        (function(){
            var auth = localStorage.getItem('admin_auth');
            if(!auth){ window.location.href = 'login.php'; return; }
            try{
                var data = JSON.parse(auth);
                var avatar = document.getElementById('headerAvatar');
                var nameEl = document.getElementById('headerUserName');
                if(data.username){
                    avatar.textContent = data.username.charAt(0).toUpperCase();
                    nameEl.textContent = data.username;
                }
                // 仅管理员(lyq)可访问此页面
                if(data.username !== 'lyq'){
                    window.location.href = 'main.php';
                    return;
                }
            }catch(e){}
            document.getElementById('logoutBtn').addEventListener('click', function(){
                localStorage.removeItem('admin_auth');
                window.location.href = 'login.php';
            });
        })();

        // 3D light reflection
        document.querySelector('.form-card').addEventListener('mousemove', e => {
            const r = e.currentTarget.getBoundingClientRect();
            e.currentTarget.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
            e.currentTarget.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
        });

        // Scroll parallax
        let ticking = false;
        const orbs = document.querySelectorAll('.orb');
        window.addEventListener('scroll', () => {
            if (!ticking) {
                requestAnimationFrame(() => {
                    const y = window.scrollY;
                    orbs[0].style.transform = `translate(${y*0.02}px,${y*0.03}px)`;
                    orbs[1].style.transform = `translate(${-y*0.015}px,${-y*0.025}px)`;
                    orbs[2].style.transform = `translate(${y*0.01}px,${y*0.02}px)`;
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });

        // Input focus ripple
        document.querySelectorAll('.form-input').forEach(input => {
            input.addEventListener('focus', () => {
                input.parentElement.style.transform = 'translateX(2px)';
                setTimeout(() => input.parentElement.style.transform = '', 150);
            });
        });

        // Button hover light tracking
        const btn = document.querySelector('.btn-primary');
        if (btn) {
            btn.addEventListener('mousemove', e => {
                const rect = btn.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                btn.style.background = `radial-gradient(circle at ${x}px ${y}px, rgba(255,255,255,0.15), transparent 50%), linear-gradient(135deg, var(--indigo), var(--violet))`;
            });
            btn.addEventListener('mouseleave', () => {
                btn.style.background = 'linear-gradient(135deg, var(--indigo), var(--violet))';
            });
            
            // Form submission loading state
            btn.closest('form').addEventListener('submit', function() {
                btn.style.transform = 'scale(0.95)';
                btn.style.opacity = '0.8';
                btn.value = '保存中...';
                setTimeout(() => {
                    btn.style.transform = '';
                    btn.style.opacity = '';
                    btn.value = '保存';
                }, 1500);
            });
        }
    </script>
</body>
</html>

创建users_edit

<?php include("db.php");?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网站后台管理-用户编辑</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
    <style>
        :root {
            --indigo: #6366f1; --indigo-l: #818cf8; --violet: #8b5cf6;
            --cyan: #22d3ee; --emerald: #34d399; --rose: #fb7185;
            --bg0: #050810; --bg1: #0a0e1a;
            --sf1: rgba(255,255,255,0.018); --sf2: rgba(255,255,255,0.035);
            --t1: #f0f4ff; --t2: #c4ccdf; --t3: #7a86a1; --t4: #4a5568;
            --edge: rgba(255,255,255,0.06); --edge-h: rgba(255,255,255,0.12);
            --r: 16px; --rl: 22px;
            --ease: cubic-bezier(0.22,1,0.36,1);
            --bounce: cubic-bezier(0.34,1.56,0.64,1);
        }
        * { margin:0; padding:0; box-sizing:border-box; }
        html { scroll-behavior:smooth; overflow-x:hidden; }
        body {
            font-family:'Inter',system-ui,-apple-system,sans-serif;
            background:var(--bg0); color:var(--t1);
            min-height:100vh; display:flex; flex-direction:column;
            -webkit-font-smoothing:antialiased; overflow-x:hidden;
        }

        /* Ambient */
        .ambient { position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
        .orb { position:absolute; border-radius:50%; filter:blur(120px); opacity:0.3; will-change:transform; }
        .orb:nth-child(1) { width:600px; height:600px; background:var(--indigo); top:-20%; left:-10%; animation:od1 18s ease-in-out infinite alternate; }
        .orb:nth-child(2) { width:500px; height:500px; background:var(--cyan); bottom:-15%; right:-8%; animation:od2 22s ease-in-out infinite alternate; }
        .orb:nth-child(3) { width:350px; height:350px; background:var(--violet); top:40%; left:50%; opacity:0.15; animation:od3 15s ease-in-out infinite alternate; }
        @keyframes od1 { to { transform:translate(120px,80px) scale(1.1); } }
        @keyframes od2 { to { transform:translate(-100px,-60px) scale(0.9); } }
        @keyframes od3 { to { transform:translate(-80px,60px) scale(1.15); } }
        .ambient::after {
            content:''; position:absolute; inset:0;
            background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(/%23n)' opacity='0.03'/%3E%3C/svg%3E");
            background-size:256px; opacity:0.4; mix-blend-mode:overlay;
        }
        .grid-bg {
            position:absolute; inset:0;
            background-image:linear-gradient(rgba(255,255,255,0.015) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.015) 1px,transparent 1px);
            background-size:60px 60px;
            mask-image:radial-gradient(ellipse 70% 50% at 50% 30%,black,transparent);
        }

        /* Header */
        .header {
            position:sticky; top:0; z-index:100; height:58px; padding:0 28px;
            display:flex; align-items:center; justify-content:space-between;
            background:linear-gradient(180deg,rgba(15,20,35,0.92),rgba(10,14,26,0.88));
            backdrop-filter:blur(30px) saturate(1.4) brightness(1.1);
            border-bottom:1px solid var(--edge);
            box-shadow:0 1px 0 rgba(255,255,255,0.03) inset,0 4px 24px rgba(0,0,0,0.3);
        }
        .header-title { font-size:14px; font-weight:600; display:flex; align-items:center; gap:10px; }
        .beacon {
            width:7px; height:7px; border-radius:50%; background:var(--emerald);
            box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3);
            animation:bpulse 2.5s ease-in-out infinite;
        }
        @keyframes bpulse { 0%,100%{box-shadow:0 0 6px var(--emerald),0 0 16px rgba(52,211,153,0.3)} 50%{box-shadow:0 0 10px var(--emerald),0 0 28px rgba(52,211,153,0.5)} }
        .header-user { display:flex; align-items:center; gap:10px; }
        .avatar {
            width:30px; height:30px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            display:flex; align-items:center; justify-content:center;
            font-weight:700; font-size:11px; color:#fff; cursor:pointer; position:relative;
            transition:transform 0.4s var(--bounce);
        }
        .avatar::after {
            content:''; position:absolute; inset:-2px; border-radius:50%;
            background:conic-gradient(from 45deg,var(--indigo),var(--violet),var(--cyan),var(--indigo));
            z-index:-1; opacity:0; filter:blur(6px); transition:opacity 0.4s;
        }
        .avatar:hover { transform:scale(1.12); }
        .avatar:hover::after { opacity:0.6; }
        .user-name { font-size:12px; font-weight:500; color:var(--t2); }
        .logout-btn {
            width:30px; height:30px; border-radius:8px; border:1px solid var(--edge);
            background:rgba(255,255,255,0.03); color:var(--t3); cursor:pointer;
            display:flex; align-items:center; justify-content:center;
            transition:all 0.3s var(--ease); padding:0; margin-left:6px;
        }
        .logout-btn svg { width:14px; height:14px; }
        .logout-btn:hover { background:rgba(251,113,133,0.1); border-color:rgba(251,113,133,0.3); color:var(--rose); transform:translateY(-1px); }
        .logout-btn:active { transform:translateY(0); }

        /* Layout */
        .main-container { display:flex; flex:1; min-height:calc(100vh - 58px); position:relative; z-index:1; }

        /* Sidebar */
        .sidebar {
            width:230px; flex-shrink:0;
            background:linear-gradient(180deg,rgba(12,16,28,0.85),rgba(8,11,20,0.9));
            backdrop-filter:blur(24px); border-right:1px solid var(--edge);
            padding:20px 0; display:flex; flex-direction:column; position:relative;
        }
        .sidebar::after {
            content:''; position:absolute; top:0; right:0; width:1px; height:100%;
            background:linear-gradient(180deg,rgba(99,102,241,0.15),transparent 50%,rgba(34,211,238,0.1));
        }
        .nav-section { margin-bottom:24px; }
        .nav-title { font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:0.14em; color:var(--t4); padding:0 16px; margin-bottom:10px; }
        .nav-links { display:flex; flex-direction:column; gap:2px; padding:0 6px; }
        .nav-link {
            display:flex; align-items:center; gap:10px; padding:10px 12px;
            color:var(--t3); text-decoration:none; font-size:13px; font-weight:500;
            border-radius:10px; transition:all 0.3s var(--ease); position:relative; overflow:hidden;
        }
        .nav-link::before {
            content:''; position:absolute; inset:0;
            background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,0.04) 50%,transparent 60%);
            transform:translateX(-100%); transition:transform 0.6s var(--ease);
        }
        .nav-link:hover::before { transform:translateX(100%); }
        .nav-link:hover { background:var(--sf2); color:var(--t1); }
        .nav-link.active {
            background:linear-gradient(135deg,rgba(99,102,241,0.12),rgba(139,92,246,0.08));
            color:var(--indigo-l); box-shadow:0 0 0 1px rgba(99,102,241,0.15) inset;
        }
        .nav-link.active::after {
            content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
            width:3px; height:18px; border-radius:0 3px 3px 0;
            background:linear-gradient(180deg,var(--indigo),var(--violet));
            box-shadow:0 0 10px rgba(99,102,241,0.4);
            animation:igrow 0.35s var(--bounce);
        }
        @keyframes igrow { from{height:0;opacity:0} to{height:18px;opacity:1} }
        .nav-link svg { width:16px; height:16px; flex-shrink:0; opacity:0.6; transition:all 0.3s var(--ease); }
        .nav-link:hover svg, .nav-link.active svg { opacity:1; }
        .nav-link.active svg { filter:drop-shadow(0 0 4px rgba(99,102,241,0.4)); }

        /* Content */
        .content { flex:1; padding:36px 40px; overflow-y:auto; display:flex; justify-content:center; }
        .content-inner { width:100%; max-width:600px; }
        .content-header { margin-bottom:32px; opacity:0; animation:rup 0.7s var(--ease) 0.1s forwards; }
        .content-title {
            font-size:28px; font-weight:800; letter-spacing:-0.03em;
            background:linear-gradient(135deg,var(--t1) 30%,var(--indigo-l));
            -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text;
            margin-bottom:6px;
        }
        .content-subtitle { font-size:13px; color:var(--t3); }

        /* Form Card */
        .form-card {
            background:linear-gradient(165deg,rgba(255,255,255,0.04),rgba(255,255,255,0.01));
            border:1px solid var(--edge); border-radius:var(--rl); padding:32px;
            position:relative; overflow:hidden; opacity:0;
            animation:creveal 0.7s var(--ease) 0.2s forwards;
        }
        .form-card::before {
            content:''; position:absolute; top:0; left:0; right:0; height:1px;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.08) 20%,var(--indigo) 50%,rgba(255,255,255,0.08) 80%,transparent);
            opacity:0; transition:opacity 0.5s;
        }
        .form-card::after {
            content:''; position:absolute; inset:0;
            background:radial-gradient(600px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,0.04),transparent 40%);
            opacity:0; transition:opacity 0.4s; pointer-events:none; border-radius:inherit;
        }
        .form-card:hover::before, .form-card:hover::after { opacity:1; }
        .form-card:hover { border-color:var(--edge-h); box-shadow:0 8px 32px -8px rgba(0,0,0,0.5); }

        /* Form Elements */
        .form-group { margin-bottom:20px; position:relative; z-index:1; }
        .form-label {
            display:block; font-size:11px; font-weight:600; text-transform:uppercase;
            letter-spacing:0.08em; color:var(--t3); margin-bottom:8px;
        }
        .form-input {
            width:100%; padding:12px 16px; font-size:14px; font-family:inherit;
            color:var(--t1); background:rgba(255,255,255,0.03);
            border:1px solid var(--edge); border-radius:10px;
            outline:none; transition:all 0.3s var(--ease);
        }
        .form-input::placeholder { color:var(--t4); }
        .form-input:focus {
            border-color:rgba(99,102,241,0.4);
            background:rgba(99,102,241,0.04);
            box-shadow:0 0 0 3px rgba(99,102,241,0.08);
        }
        .form-input:hover:not(:focus) {
            border-color:var(--edge-h);
            background:rgba(255,255,255,0.04);
        }
        .form-hint {
            font-size:11px; color:var(--t4); margin-top:6px; display:flex;
            align-items:center; gap:4px;
        }
        .form-hint svg { width:12px; height:12px; opacity:0.6; }

        /* Section Divider */
        .form-divider {
            height:1px; background:var(--edge); margin:24px 0; position:relative; z-index:1;
        }
        .form-section-title {
            font-size:10px; font-weight:600; text-transform:uppercase;
            letter-spacing:0.1em; color:var(--indigo-l); margin-bottom:16px;
            position:relative; z-index:1;
        }

        /* Submit Button */
        .btn-submit {
            width:100%; padding:14px 24px; font-size:14px; font-weight:600;
            font-family:inherit; color:#fff; border:none; border-radius:10px;
            cursor:pointer; position:relative; z-index:1; overflow:hidden;
            background:linear-gradient(135deg,var(--indigo),var(--violet));
            transition:all 0.3s var(--ease);
            box-shadow:0 4px 16px rgba(99,102,241,0.25);
        }
        .btn-submit::before {
            content:''; position:absolute; top:0; left:-100%; width:100%; height:100%;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);
            transition:left 0.5s var(--ease);
        }
        .btn-submit:hover {
            transform:translateY(-2px);
            box-shadow:0 8px 24px rgba(99,102,241,0.35);
        }
        .btn-submit:hover::before { left:100%; }
        .btn-submit:active { transform:translateY(0); }

        /* Button Group */
        .btn-group {
            margin-top:24px; position:relative; z-index:1;
        }
        .btn-primary {
            width:100%; padding:14px 24px; font-size:14px; font-weight:600;
            font-family:inherit; color:#fff; border:none; border-radius:10px;
            cursor:pointer; position:relative; overflow:hidden;
            background:linear-gradient(135deg,var(--indigo),var(--violet));
            transition:all 0.3s var(--ease);
            box-shadow:0 4px 16px rgba(99,102,241,0.25);
        }
        .btn-primary::before {
            content:''; position:absolute; top:0; left:-100%; width:100%; height:100%;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);
            transition:left 0.5s var(--ease);
        }
        .btn-primary:hover {
            transform:translateY(-2px);
            box-shadow:0 8px 24px rgba(99,102,241,0.35);
        }
        .btn-primary:hover::before { left:100%; }
        .btn-primary:active { transform:translateY(0); }
        .btn-primary:active::after {
            content:''; position:absolute; inset:0; border-radius:inherit;
            background:radial-gradient(circle at 50% 50%,rgba(255,255,255,0.2),transparent 60%);
            animation:ripple 0.4s var(--ease);
        }

        /* Back Link */
        .back-link {
            display:inline-flex; align-items:center; gap:6px; margin-top:16px;
            font-size:12px; color:var(--t3); text-decoration:none;
            transition:all 0.3s var(--ease); position:relative; z-index:1;
        }
        .back-link:hover { color:var(--indigo-l); transform:translateX(-2px); }
        .back-link svg { width:14px; height:14px; }

        /* Animations */
        @keyframes rup { from{opacity:0;transform:translateY(20px)} to{opacity:1;transform:translateY(0)} }
        @keyframes creveal { from{opacity:0;transform:translateY(24px) scale(0.96);filter:blur(4px)} to{opacity:1;transform:translateY(0) scale(1);filter:blur(0)} }
        @keyframes ripple { from{transform:scale(0);opacity:1} to{transform:scale(2.5);opacity:0} }

        /* Scrollbar */
        ::-webkit-scrollbar { width:5px; }
        ::-webkit-scrollbar-track { background:transparent; }
        ::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.08); border-radius:3px; }
        ::-webkit-scrollbar-thumb:hover { background:rgba(255,255,255,0.14); }

        /* Responsive */
        @media(max-width:1100px) { .content{padding:28px 24px} }
        @media(max-width:960px) { .sidebar{width:200px} }
        @media(max-width:768px) {
            .main-container{flex-direction:column}
            .sidebar{width:100%;border-right:none;border-bottom:1px solid var(--edge);padding:10px 0}
            .sidebar::after{display:none}
            .nav-links{flex-direction:row;overflow-x:auto;padding:0 10px;gap:4px;-webkit-overflow-scrolling:touch}
            .nav-link{padding:8px 14px;white-space:nowrap;font-size:12px;border-radius:8px}
            .nav-link.active::after{display:none}
            .content{padding:24px 18px}
            .form-card{padding:24px}
            .content-title{font-size:22px}
            .orb{opacity:0.2}
        }
        @media(max-width:480px) { .header{padding:0 16px;height:52px} .content{padding:18px 14px} }
        @media(prefers-reduced-motion:reduce) { *,*::before,*::after{animation-duration:0.01ms!important;animation-delay:0ms!important;transition-duration:0.01ms!important} .orb{animation:none!important} }
    </style>
</head>
<body>
    <div class="ambient">
        <div class="orb"></div><div class="orb"></div><div class="orb"></div>
        <div class="grid-bg"></div>
    </div>

    <header class="header">
        <div class="header-title"><span class="beacon"></span>网站后台管理</div>
        <div class="header-user">
            <div class="avatar" id="headerAvatar">A</div>
            <div class="user-name" id="headerUserName">管理员</div>
            <button class="logout-btn" id="logoutBtn" title="退出登录">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
            </button>
        </div>
    </header>

    <div class="main-container">
        <aside class="sidebar">
            <div class="nav-section">
                <div class="nav-title">导航菜单</div>
                <div class="nav-links">
                    <a href="main.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
                        网站信息
                    </a>
                    <a href="articles.php" class="nav-link">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
                        文章管理
                    </a>
                    <a href="users_list.php" class="nav-link active">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
                        用户管理
                    </a>
                </div>
            </div>
        </aside>

        <main class="content">
            <div class="content-inner">
                <div class="content-header">
                    <h1 class="content-title">编辑用户</h1>
                    <p class="content-subtitle">修改用户账户信息</p>
                </div>

                <?php
                // 根据传递的id,获取表中的各个信息
                $userid = $_REQUEST["id"];
                $sql = "SELECT * FROM users WHERE id = '$userid'";
                $result = mysqli_query($conn, $sql);
                if (!$result){
                    echo "查询失败: " . mysqli_error($conn);
                    exit;
                }
                $row = mysqli_fetch_assoc($result);
                if ($row) {
                    $username = $row["username"];
                    $email = $row["email"];
                }
                ?>

                <div class="form-card">
                    <form action="users.php" method="post">
                        <div class="form-section-title">基本信息</div>

                        <div class="form-group">
                            <label class="form-label" for="username">用户名</label>
                            <input class="form-input" type="text" id="username" name="username" placeholder="请输入用户名" value="<?php echo htmlspecialchars(isset($username) ? $username : ''); ?>">
                        </div>

                        <div class="form-group">
                            <label class="form-label" for="email">邮箱</label>
                            <input class="form-input" type="email" id="email" name="email" placeholder="请输入邮箱" value="<?php echo htmlspecialchars(isset($email) ? $email : ''); ?>">
                        </div>

                        <div class="form-divider"></div>
                        <div class="form-section-title">密码修改</div>

                       
                        <div class="form-group">
                            <label class="form-label" for="bepassword">原密码</label>
                            <input class="form-input" type="password" id="bepassword" name="bepassword" placeholder="请输入原密码">
                        </div>

                        <div class="form-group">
                            <label class="form-label" for="password">新密码</label>
                            <input class="form-input" type="password" id="password" name="password" placeholder="请输入新密码">
                        </div>

                        <div class="form-group">
                            <label class="form-label" for="repassword">确认密码</label>
                            <input class="form-input" type="password" id="repassword" name="repassword" placeholder="请再次输入新密码">
                        </div>

                        <div class="btn-group">
                            <input type="submit" class="btn btn-primary" value="保存" name="change">
                        </div>
                       
                    </form>
                </div>

                <a href="users_list.php" class="back-link">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
                    返回用户列表
                </a>
            </div>
        </main>
    </div>

    <script>
        // ── 前端登录状态检查 ──
        (function(){
            var auth = localStorage.getItem('admin_auth');
            if(!auth){ window.location.href = 'login.php'; return; }
            try{
                var data = JSON.parse(auth);
                var avatar = document.getElementById('headerAvatar');
                var nameEl = document.getElementById('headerUserName');
                if(data.username){
                    avatar.textContent = data.username.charAt(0).toUpperCase();
                    nameEl.textContent = data.username;
                }
                // 仅管理员(lyq)可访问此页面
                if(data.username !== 'lyq'){
                    window.location.href = 'main.php';
                    return;
                }
            }catch(e){}
            document.getElementById('logoutBtn').addEventListener('click', function(){
                localStorage.removeItem('admin_auth');
                window.location.href = 'login.php';
            });
        })();

        // 3D light reflection
        document.querySelector('.form-card').addEventListener('mousemove', e => {
            const r = e.currentTarget.getBoundingClientRect();
            e.currentTarget.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
            e.currentTarget.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
        });

        // Scroll parallax
        let ticking = false;
        const orbs = document.querySelectorAll('.orb');
        window.addEventListener('scroll', () => {
            if (!ticking) {
                requestAnimationFrame(() => {
                    const y = window.scrollY;
                    orbs[0].style.transform = `translate(${y*0.02}px,${y*0.03}px)`;
                    orbs[1].style.transform = `translate(${-y*0.015}px,${-y*0.025}px)`;
                    orbs[2].style.transform = `translate(${y*0.01}px,${y*0.02}px)`;
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });

        // Input focus ripple
        document.querySelectorAll('.form-input').forEach(input => {
            input.addEventListener('focus', () => {
                input.parentElement.style.transform = 'translateX(2px)';
                setTimeout(() => input.parentElement.style.transform = '', 150);
            });
        });

        // Button hover light tracking
        const btn = document.querySelector('.btn-primary');
        if (btn) {
            btn.addEventListener('mousemove', e => {
                const rect = btn.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                btn.style.background = `radial-gradient(circle at ${x}px ${y}px, rgba(255,255,255,0.15), transparent 50%), linear-gradient(135deg, var(--indigo), var(--violet))`;
            });
            btn.addEventListener('mouseleave', () => {
                btn.style.background = 'linear-gradient(135deg, var(--indigo), var(--violet))';
            });
            
            // Form submission loading state
            btn.closest('form').addEventListener('submit', function() {
                btn.style.transform = 'scale(0.95)';
                btn.style.opacity = '0.8';
                btn.value = '保存中...';
                setTimeout(() => {
                    btn.style.transform = '';
                    btn.style.opacity = '';
                    btn.value = '保存';
                }, 1500);
            });
        }
    </script>
</body>
</html>

完成文章管理功能

渗透阶段

Sql注入

原理:

SQL 注入(SQL Injection)

一句话解释: 攻击者通过在输入框中插入恶意 SQL 代码,欺骗数据库执行非预期操作。


举个例子

假设有个登录查询:

SELECT * FROM users WHERE username = '用户输入' AND password = '用户输入';

正常输入:

用户名: zhangsan
密码: 123456

→ 生成的 SQL:

SELECT * FROM users WHERE username = 'zhangsan' AND password = '123456';

恶意输入:

用户名: ' OR 1=1 --
密码: 随便填

→ 生成的 SQL:

SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = '随便填';

-- 是 SQL 注释,后面的内容被忽略。1=1 永远为真,所以无需密码就能登录任何账号。


常见危害

危害 说明
🔓 绕过登录 无需密码进入系统
📤 窃取数据 导出用户表、密码、敏感信息
🗑️ 删库 DROP TABLE users 清空整张表
🔧 篡改数据 修改价格、余额、权限等
🖥️ 服务器控制 通过数据库执行系统命令(高级攻击)

防御方法

1. 参数化查询(最有效)

# ❌ 危险:字符串拼接
query = f"SELECT * FROM users WHERE username = '{username}'"

# ✅ 安全:参数化
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))

2. ORM 框架

# SQLAlchemy 自动防注入
User.query.filter_by(username=username).first()

3. 输入验证 — 过滤特殊字符('、--、; 等)

4. 最小权限 — 数据库账号只给必要的权限,禁用 DROP、EXEC 等

5. WAF 防火墙 — 拦截常见注入特征


一句话总结

永远不要信任用户输入,永远用参数化查询。

Sql注入的常见种类

SQL 注入深度解析

一、本质原理

SQL 注入的根本问题是:代码和数据没有分离。

程序期望的输入:一个普通的字符串(用户名)
攻击者实际输入:一段可执行的 SQL 代码
数据库无法区分:哪些是指令,哪些是数据

二、攻击类型详解

1️⃣ 联合查询注入(UNION-based)

原理: 用 UNION 把攻击者的查询结果拼接到正常结果后面。

-- 正常查询
SELECT name, price FROM products WHERE id = 1

-- 攻击输入:1 UNION SELECT username, password FROM users --
-- 最终执行:
SELECT name, price FROM products WHERE id = 1
UNION
SELECT username, password FROM users --

结果: 产品页变成了用户密码列表。


2️⃣ 报错注入(Error-based)

原理: 故意让 SQL 报错,错误信息中会泄露数据库内容。

-- 输入:' AND extractvalue(1, concat(0x7e, (SELECT version()))) --
-- 报错信息:
XPATH syntax error: '~5.7.34'

攻击者从错误信息中拿到了数据库版本号。


3️⃣ 布尔盲注(Boolean Blind)

原理: 页面没有回显数据,但根据「页面正常/异常」来判断猜测是否正确。

-- 判断数据库名第一个字符是否为 'r'
' AND (SELECT substring(database(),1,1)) = 'r' --
-- 页面正常 → 猜对了,第一个字符是 'r'

-- 判断第二个字符
' AND (SELECT substring(database(),2,1)) = 'o' --
-- 页面正常 → 数据库名可能是 'root'...

像猜密码一样,一个字符一个字符地试。


4️⃣ 时间盲注(Time Blind)

原理: 页面完全没有变化,通过响应时间来判断。

-- 如果条件为真,延迟 3 秒响应
' AND IF(1=1, SLEEP(3), 0) --
-- 响应慢了 3 秒 → 条件为真

' AND IF((SELECT substring(database(),1,1)) = 'r', SLEEP(3), 0) --
-- 响应慢 → 第一个字符确实是 'r'

5️⃣ 堆叠注入(Stacked Queries)

原理: 用分号 ; 执行多条 SQL 语句。

-- 输入:1; DROP TABLE users; --
-- 执行两条语句:
SELECT * FROM products WHERE id = 1;
DROP TABLE users;

后果: 用户表直接被删。


6️⃣ 二次注入(Second-order)

原理: 恶意输入先被「安全」地存入数据库,后续使用时再触发。

第一步:注册用户名 → admin'--  (存入数据库时被转义,安全)
第二步:修改密码功能读取该用户名 → 拼接到 SQL 中 → 触发注入
第三步:攻击者修改了真正 admin 的密码

最隐蔽的一种,因为存储时检查

数据库为层级结构

数据库基本代码回顾:

mysql> use lyqblog
Database changed
mysql> select * from users
    ->
    -> ;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
|  9 | apiuser  | api123    | api@example.com   |
+----+----------+-----------+-------------------+
7 rows in set (0.01 sec)


mysql> select username from users
    -> ;
+----------+
| username |
+----------+
| lyq      |
| whc      |
| dbw      |
| admin    |
| user1    |
| testuser |
| apiuser  |
+----------+
7 rows in set (0.00 sec)


mysql> select 'lyqnb' from users
    -> ;
+-------+
| lyqnb |
+-------+
| lyqnb |
| lyqnb |
| lyqnb |
| lyqnb |
| lyqnb |
| lyqnb |
| lyqnb |
+-------+
7 rows in set (0.00 sec)

mysql> select 1,2,4
    -> ;
+---+---+---+
| 1 | 2 | 4 |
+---+---+---+
| 1 | 2 | 4 |
+---+---+---+
1 row in set (0.00 sec)

mysql> select * from users union select * from users ;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
|  9 | apiuser  | api123    | api@example.com   |
+----+----------+-----------+-------------------+
7 rows in set (0.00 sec)


mysql> select * from users union select 1,2,3,4;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
|  9 | apiuser  | api123    | api@example.com   |
|  1 | 2        | 3         | 4                 |
+----+----------+-----------+-------------------+
8 rows in set (0.00 sec)




mysql> select * from users where username = '-1 ' union select 1 , 'admin',3,4;
+----+----------+----------+-------+
| id | username | password | email |
+----+----------+----------+-------+
|  1 | admin    | 3        | 4     |
+----+----------+----------+-------+
1 row in set (0.00 sec)

简单sql注入语句

mysql> select * from users where username = '' or 1=1 #' and password = "";
    ->
    -> ;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
|  9 | apiuser  | api123    | api@example.com   |
+----+----------+-----------+-------------------+
7 rows in set (0.00 sec)


mysql> select * from users where username =''union select 1,'lyq',3,4#' and password='';
    -> ;
+----+----------+----------+-------+
| id | username | password | email |
+----+----------+----------+-------+
|  1 | lyq      | 3        | 4     |
+----+----------+----------+-------+
1 row in set (0.00 sec)
//两个表的列应该相同
mysql> select * from users order by 1
    -> ;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
|  9 | apiuser  | api123    | api@example.com   |
+----+----------+-----------+-------------------+
7 rows in set (0.00 sec)

mysql> select * from users order by 3;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  1 | lyq      | 1         | lyq@163.com       |
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  9 | apiuser  | api123    | api@example.com   |
|  7 | user1    | password1 | user1@example.com |
|  8 | testuser | test123   | test@example.com  |
+----+----------+-----------+-------------------+
7 rows in set (0.00 sec)

mysql> select * from users order by 4;
+----+----------+-----------+-------------------+
| id | username | password  | email             |
+----+----------+-----------+-------------------+
|  4 | whc      | 1         | 123@123.com       |
|  5 | dbw      | 1         | 159@159.com       |
|  6 | admin    | admin123  | admin@example.com |
|  9 | apiuser  | api123    | api@example.com   |
|  1 | lyq      | 1         | lyq@163.com       |
|  8 | testuser | test123   | test@example.com  |
|  7 | user1    | password1 | user1@example.com |
+----+----------+-----------+-------------------+
7 rows in set (0.00 sec)

靶场训练:

XYCMS:

select * from  xxx where id = 13 ; 
1. 让语句进行报错
select * from  xxx where id = 13';
使用orderby进行猜测,
而后
select * from users where id =-13 union select 1,2,3,4,5,6,7,8,9,10;
其中的数字可以替换为,一些查询操作。

Kali 虚拟机

进行初始化的设置
(root㉿kali)-[~]
└─# vim /etc/ssh/sshd_config
#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
vim /etc/passwd
root:x:0:0:root:/root:/usr/bin/bash
apt -y install docker.io
#配置镜像下载加速
vim /etc/docker/daemon.josn
{
  "registry-mirrors": ["https://service-crproxy.onrender.com"],
  "insecure-registries": ["service-crproxy.onrender.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}

使用codebuddy

在远程主机中安装docker

image\.png

修复步骤

  1. 打开 PowerShell(以管理员身份运行)

按 Win + X,选择"Windows PowerShell (管理员)"或"终端 (管理员)"

  1. 删除损坏的安装

powershell

复制

Remove-Item -Recurse -Force "$env:APPDATA\npm\node_modules\openclaw"

  1. 重新安装 OpenClaw

powershell

复制

npm install -g openclaw@latest

  1. 验证安装

powershell

复制

openclaw --version

  1. 重启 OpenClaw 网关

powershell

复制

openclaw gateway restart

可能遇到的问题

如果 npm install 报权限错误,尝试用管理员权限运行

如果网络问题导致下载慢,可以设置 npm 镜像源:

powershell

复制

npm config set registry https://registry\.npmmirror\.com

npm install -g openclaw@latest

完成这些步骤后回来告诉我,我帮你确认更新是否成功。

docker run -d -P harbor.iproute.cn:30080/course/xycms:latest

docker run -d -P 172.16.17.4:30080/course/xycms:latest

https://notes\.iproute\.cn/s/065a4c88

不吆的博客

BUYAO / NOTES独立写作 · 持续学习

不吆的博客

在代码、设计与生活之间,记录缓慢而具体的思考。

FIND A NOTE

搜索文章

输入关键词,在全部文章中查找。
按 Ctrl / ⌘ K 随时打开Enter 打开首条结果
–
篇文章
–
条回应
–
个标签
RECENT / 新近

最新文章

长文阅读

BUYAO / JOURNAL

回应
PRIVATE DESK

后台登录

发布、编辑、删除需要登录。访客浏览与留言无需登录。
博客后台使用站长账号;刷题学习账号是另一套身份。

密码经后端加盐哈希校验,浏览器不会保存任何可写凭证。
这里登录的是博客后台,请使用站长账号;刷题属于另一套学习账号,请到 刷题登录页。
WRITING DESK

写一篇新文章

新文章
0 = 默认;1、2、3… 越小越靠前

置顶后会出现在首页「编辑精选」,并排在列表最前。

    只保存选中的标签;搜索结果里没有时,可以在菜单底部新建一个。

    未设置封面
    链接地址(slug)
    发布后地址为 /post/<slug>,可被搜索引擎收录。
    0 字 · 约 1 分钟
    正文插图有三种方式:点「插入图片」、直接把图片拖进编辑框、或粘贴截图。
    从飞书/语雀导出的 Markdown:点「导入 Markdown」把 .md 和图片一起选中(也支持含图片的 .zip),或点「导入文件夹」直接选整个导出目录——图片会上传到本站并自动改好链接;外链图片会尝试抓回本地,抓不到的保留原链接。
    如果正文已经贴好了、只有图片是「图片和附件/xxx.png」这种本地路径:点「修复正文图片」,选中同名的图片文件,会原位替换,不会动你的正文。
    文章保存到本站后端数据库(SQLite)。Ctrl/⌘ + S 也可保存;顶栏「备份」可导出全部数据为 JSON 文件。
    ⌘/Ctrl + S 保存

    站点设置

    标签决定文章怎么被分类和筛选。分组会出现在标签页上(如「技术栈」「设计与生活」);图标/封面图会显示在标签卡和筛选条里。