项目结构
/company-website/
├── admin/ # 后台管理目录
│ ├── css/
│ ├── js/
│ ├── uploads/ # 上传文件目录
│ ├── index.php # 后台首页
│ ├── login.php # 登录页面
│ └── ... # 其他后台页面
├── api/ # API接口目录
│ ├── v1/ # API版本
│ │ ├── news.php # 新闻API
│ │ ├── products.php # 产品API
│ │ └── ... # 其他API
│ └── config.php # API配置
├── assets/ # 前端静态资源
│ ├── css/
│ ├── js/
│ ├── images/
│ └── uploads/ # 前端访问的上传文件
├── includes/ # 公共包含文件
│ ├── config.php # 数据库配置
│ ├── functions.php # 公共函数
│ └── db.php # 数据库连接
├── pages/ # 独立页面目录
│ ├── index.php # 首页
│ ├── about.php # 关于我们
│ ├── news.php # 新闻中心
│ ├── products.php # 产品中心
│ └── contact.php # 联系我们
├── .htaccess # Apache伪静态规则
├── web.config # IIS伪静态规则
└── index.php # 前端入口文件
1. 数据库设计 (MySQL)
首先创建数据库和表:
CREATE DATABASE company_website CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 管理员表
CREATE TABLE admins (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 新闻表
CREATE TABLE news (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
image VARCHAR(255),
category VARCHAR(50),
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 产品表
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10,2),
image VARCHAR(255),
category VARCHAR(50),
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 页面内容表
CREATE TABLE pages (
id INT AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT,
meta_title VARCHAR(255),
meta_description VARCHAR(255),
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 插入初始管理员
INSERT INTO admins (username, password, email) VALUES
('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@company.com');
2. 配置文件 (includes/config.php)
<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', 'password');
define('DB_NAME', 'company_website');
// 网站配置
define('SITE_URL', 'http://localhost/company-website');
define('SITE_NAME', '企业官网');
define('UPLOAD_DIR', 'uploads/');
define('ADMIN_EMAIL', 'admin@company.com');
// 开启错误报告
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 时区设置
date_default_timezone_set('Asia/Shanghai');
// 开启会话
session_start();
?>
3. 数据库连接 (includes/db.php)
<?php
require_once 'config.php';
class Database {
private $conn;
public function __construct() {
$this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($this->conn->connect_error) {
die("数据库连接失败: " . $this->conn->connect_error);
}
$this->conn->set_charset("utf8mb4");
}
public function getConnection() {
return $this->conn;
}
public function query($sql) {
return $this->conn->query($sql);
}
public function prepare($sql) {
return $this->conn->prepare($sql);
}
public function lastInsertId() {
return $this->conn->insert_id;
}
public function escape($str) {
return $this->conn->real_escape_string($str);
}
public function __destruct() {
$this->conn->close();
}
}
// 公共函数
function redirect($url) {
header("Location: $url");
exit();
}
function isLoggedIn() {
return isset($_SESSION['admin_id']);
}
function sanitize($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
4. 前端入口 (index.php)
<?php
require_once 'includes/db.php';
// 路由处理
$request = $_SERVER['REQUEST_URI'];
$page = str_replace('/company-website/', '', $request);
// 去除查询字符串
if (strpos($page, '?') !== false) {
$page = substr($page, 0, strpos($page, '?'));
}
// 默认页面
if (empty($page) || $page == '/') {
$page = 'index';
}
// 检查页面是否存在
$pageFile = 'pages/' . $page . '.php';
if (file_exists($pageFile)) {
// 获取页面数据
$db = new Database();
$slug = ($page == 'index') ? 'home' : $page;
$stmt = $db->prepare("SELECT * FROM pages WHERE slug = ? AND status = 1");
$stmt->bind_param("s", $slug);
$stmt->execute();
$result = $stmt->get_result();
$pageData = $result->fetch_assoc();
$stmt->close();
// 包含公共头部
include 'includes/header.php';
// 包含页面内容
include $pageFile;
// 包含公共底部
include 'includes/footer.php';
} else {
// 404页面
header("HTTP/1.0 404 Not Found");
include 'pages/404.php';
}
?>
5. 公共头部 (includes/header.php)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo isset($pageData['meta_title']) ? $pageData['meta_title'] : SITE_NAME; ?></title>
<meta name="description" content="<?php echo isset($pageData['meta_description']) ? $pageData['meta_description'] : SITE_NAME; ?>">
<!-- CSS -->
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/font-awesome.min.css">
<link rel="stylesheet" href="assets/css/style.css">
<!-- Favicon -->
<link rel="icon" href="assets/images/favicon.ico" type="image/x-icon">
</head>
<body>
<header class="header">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="<?php echo SITE_URL; ?>"><?php echo SITE_NAME; ?></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item <?php echo ($page == 'index') ? 'active' : ''; ?>">
<a class="nav-link" href="<?php echo SITE_URL; ?>">首页</a>
</li>
<li class="nav-item <?php echo ($page == 'about') ? 'active' : ''; ?>">
<a class="nav-link" href="<?php echo SITE_URL; ?>/about">关于我们</a>
</li>
<li class="nav-item <?php echo ($page == 'products') ? 'active' : ''; ?>">
<a class="nav-link" href="<?php echo SITE_URL; ?>/products">产品中心</a>
</li>
<li class="nav-item <?php echo ($page == 'news') ? 'active' : ''; ?>">
<a class="nav-link" href="<?php echo SITE_URL; ?>/news">新闻中心</a>
</li>
<li class="nav-item <?php echo ($page == 'contact') ? 'active' : ''; ?>">
<a class="nav-link" href="<?php echo SITE_URL; ?>/contact">联系我们</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main class="main-content">
6. 公共底部 (includes/footer.php)
</main>
<footer class="footer bg-dark text-white py-5">
<div class="container">
<div class="row">
<div class="col-md-4">
<h5>关于我们</h5>
<p>企业简介和核心价值观</p>
</div>
<div class="col-md-4">
<h5>快速链接</h5>
<ul class="list-unstyled">
<li><a href="<?php echo SITE_URL; ?>/about">关于我们</a></li>
<li><a href="<?php echo SITE_URL; ?>/products">产品中心</a></li>
<li><a href="<?php echo SITE_URL; ?>/news">新闻中心</a></li>
<li><a href="<?php echo SITE_URL; ?>/contact">联系我们</a></li>
</ul>
</div>
<div class="col-md-4">
<h5>联系我们</h5>
<address>
<p><i class="fa fa-map-marker"></i> 地址:北京市朝阳区某某路123号</p>
<p><i class="fa fa-phone"></i> 电话:010-12345678</p>
<p><i class="fa fa-envelope"></i> 邮箱:info@company.com</p>
</address>
</div>
</div>
<hr>
<div class="text-center">
<p>© <?php echo date('Y'); ?> <?php echo SITE_NAME; ?> 版权所有</p>
</div>
</div>
</footer>
<!-- JavaScript -->
<script src="assets/js/jquery-3.5.1.min.js"></script>
<script src="assets/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
7. 示例页面 (pages/about.php)
<?php
// 设置页面特定的标题和描述
$pageTitle = "关于我们 - " . SITE_NAME;
$pageDescription = "了解我们公司的历史、使命和价值观";
// 如果数据库中有页面数据,使用数据库中的数据
if (isset($pageData)) {
$pageTitle = $pageData['title'] . " - " . SITE_NAME;
$pageDescription = $pageData['meta_description'];
}
?>
<section class="about-section py-5">
<div class="container">
<div class="row">
<div class="col-lg-6">
<h1 class="mb-4"><?php echo isset($pageData['title']) ? $pageData['title'] : '关于我们'; ?></h1>
<div class="about-content">
<?php echo isset($pageData['content']) ? $pageData['content'] : '<p>这里是默认的关于我们内容...</p>'; ?>
</div>
</div>
<div class="col-lg-6">
<img src="assets/images/about.jpg" alt="关于我们" class="img-fluid rounded">
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<h2 class="text-center mb-4">我们的团队</h2>
</div>
<!-- 团队成员可以通过后台添加,这里只是示例 -->
<div class="col-md-4 mb-4">
<div class="card">
<img src="assets/images/team1.jpg" class="card-img-top" alt="团队成员">
<div class="card-body">
<h5 class="card-title">张三</h5>
<p class="card-text">CEO/创始人</p>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card">
<img src="assets/images/team2.jpg" class="card-img-top" alt="团队成员">
<div class="card-body">
<h5 class="card-title">李四</h5>
<p class="card-text">技术总监</p>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card">
<img src="assets/images/team3.jpg" class="card-img-top" alt="团队成员">
<div class="card-body">
<h5 class="card-title">王五</h5>
<p class="card-text">市场总监</p>
</div>
</div>
</div>
</div>
</div>
</section>
8. 后台登录 (admin/login.php)
<?php
require_once '../includes/db.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = sanitize($_POST['username']);
$password = sanitize($_POST['password']);
$db = new Database();
$stmt = $db->prepare("SELECT id, username, password FROM admins WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows == 1) {
$admin = $result->fetch_assoc();
if (password_verify($password, $admin['password'])) {
$_SESSION['admin_id'] = $admin['id'];
$_SESSION['admin_username'] = $admin['username'];
redirect('index.php');
} else {
$error = "用户名或密码错误";
}
} else {
$error = "用户名或密码错误";
}
$stmt->close();
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台登录 - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/login.css">
</head>
<body>
<div class="login-container">
<div class="card login-card">
<div class="card-body">
<h2 class="text-center mb-4">后台管理系统</h2>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary btn-block">登录</button>
</form>
</div>
</div>
</div>
</body>
</html>
9. 后台首页 (admin/index.php)
<?php
require_once '../includes/db.php';
if (!isLoggedIn()) {
redirect('login.php');
}
$db = new Database();
// 获取统计数据
$newsCount = $db->query("SELECT COUNT(*) FROM news")->fetch_row()[0];
$productsCount = $db->query("SELECT COUNT(*) FROM products")->fetch_row()[0];
$pagesCount = $db->query("SELECT COUNT(*) FROM pages")->fetch_row()[0];
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理 - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/admin.css">
</head>
<body>
<div class="wrapper">
<!-- 侧边栏 -->
<nav id="sidebar">
<div class="sidebar-header">
<h3><?php echo SITE_NAME; ?></h3>
</div>
<ul class="list-unstyled components">
<li class="active">
<a href="index.php"><i class="fa fa-dashboard"></i> 控制面板</a>
</li>
<li>
<a href="#pageSubmenu" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<i class="fa fa-file-text"></i> 页面管理
</a>
<ul class="collapse list-unstyled" id="pageSubmenu">
<li><a href="pages.php">所有页面</a></li>
<li><a href="page-add.php">添加页面</a></li>
</ul>
</li>
<li>
<a href="news.php"><i class="fa fa-newspaper-o"></i> 新闻管理</a>
</li>
<li>
<a href="products.php"><i class="fa fa-product-hunt"></i> 产品管理</a>
</li>
<li>
<a href="settings.php"><i class="fa fa-cog"></i> 系统设置</a>
</li>
</ul>
</nav>
<!-- 页面内容 -->
<div id="content">
<!-- 顶部导航 -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<button type="button" id="sidebarCollapse" class="btn btn-info">
<i class="fa fa-align-left"></i>
</button>
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="../" target="_blank"><i class="fa fa-globe"></i> 查看网站</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php"><i class="fa fa-sign-out"></i> 退出</a>
</li>
</ul>
</div>
</nav>
<!-- 主要内容 -->
<div class="container-fluid">
<h2 class="mb-4">控制面板</h2>
<div class="row">
<div class="col-md-4 mb-4">
<div class="card text-white bg-primary">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="card-title">新闻数量</h5>
<h2 class="mb-0"><?php echo $newsCount; ?></h2>
</div>
<i class="fa fa-newspaper-o fa-3x"></i>
</div>
</div>
<div class="card-footer">
<a href="news.php" class="text-white">查看所有新闻 <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card text-white bg-success">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="card-title">产品数量</h5>
<h2 class="mb-0"><?php echo $productsCount; ?></h2>
</div>
<i class="fa fa-product-hunt fa-3x"></i>
</div>
</div>
<div class="card-footer">
<a href="products.php" class="text-white">查看所有产品 <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card text-white bg-info">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="card-title">页面数量</h5>
<h2 class="mb-0"><?php echo $pagesCount; ?></h2>
</div>
<i class="fa fa-file-text fa-3x"></i>
</div>
</div>
<div class="card-footer">
<a href="pages.php" class="text-white">查看所有页面 <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">最近活动</h5>
</div>
<div class="card-body">
<p>这里是最近的活动记录...</p>
</div>
</div>
</div>
</div>
</div>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/admin.js"></script>
</body>
</html>
10. 新闻管理 (admin/news.php)
<?php
require_once '../includes/db.php';
if (!isLoggedIn()) {
redirect('login.php');
}
$db = new Database();
// 删除新闻
if (isset($_GET['delete'])) {
$id = intval($_GET['delete']);
$stmt = $db->prepare("DELETE FROM news WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->close();
$_SESSION['message'] = "新闻已删除";
redirect('news.php');
}
// 获取所有新闻
$news = $db->query("SELECT * FROM news ORDER BY created_at DESC");
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新闻管理 - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/admin.css">
</head>
<body>
<div class="wrapper">
<?php include 'sidebar.php'; ?>
<div id="content">
<?php include 'navbar.php'; ?>
<div class="container-fluid">
<h2 class="mb-4">新闻管理</h2>
<?php if (isset($_SESSION['message'])): ?>
<div class="alert alert-success"><?php echo $_SESSION['message']; unset($_SESSION['message']); ?></div>
<?php endif; ?>
<div class="card mb-4">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">新闻列表</h5>
<a href="news-add.php" class="btn btn-primary btn-sm"><i class="fa fa-plus"></i> 添加新闻</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>分类</th>
<th>发布时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php while ($row = $news->fetch_assoc()): ?>
<tr>
<td><?php echo $row['id']; ?></td>
<td><?php echo $row['title']; ?></td>
<td><?php echo $row['category']; ?></td>
<td><?php echo date('Y-m-d H:i', strtotime($row['created_at'])); ?></td>
<td>
<?php if ($row['status'] == 1): ?>
<span class="badge badge-success">发布</span>
<?php else: ?>
<span class="badge badge-secondary">草稿</span>
<?php endif; ?>
</td>
<td>
<a href="news-edit.php?id=<?php echo $row['id']; ?>" class="btn btn-sm btn-info"><i class="fa fa-edit"></i></a>
<a href="news.php?delete=<?php echo $row['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('确定删除吗?')"><i class="fa fa-trash"></i></a>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/admin.js"></script>
</body>
</html>
11. 添加新闻 (admin/news-add.php)
<?php
require_once '../includes/db.php';
if (!isLoggedIn()) {
redirect('login.php');
}
$db = new Database();
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$title = sanitize($_POST['title']);
$content = sanitize($_POST['content']);
$category = sanitize($_POST['category']);
$status = isset($_POST['status']) ? 1 : 0;
// 处理图片上传
$image = '';
if (isset($_FILES['image']) && $_FILES['image']['error'] == UPLOAD_ERR_OK) {
$uploadDir = '../' . UPLOAD_DIR;
$uploadFile = $uploadDir . basename($_FILES['image']['name']);
// 检查文件类型
$imageFileType = strtolower(pathinfo($uploadFile, PATHINFO_EXTENSION));
$allowedTypes = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($imageFileType, $allowedTypes)) {
// 生成唯一文件名
$newFilename = uniqid() . '.' . $imageFileType;
$uploadFile = $uploadDir . $newFilename;
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadFile)) {
$image = UPLOAD_DIR . $newFilename;
}
}
}
// 插入数据库
$stmt = $db->prepare("INSERT INTO news (title, content, image, category, status) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("ssssi", $title, $content, $image, $category, $status);
if ($stmt->execute()) {
$_SESSION['message'] = "新闻添加成功";
redirect('news.php');
} else {
$error = "添加新闻失败: " . $stmt->error;
}
$stmt->close();
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>添加新闻 - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/admin.css">
<link rel="stylesheet" href="css/summernote-bs4.css">
</head>
<body>
<div class="wrapper">
<?php include 'sidebar.php'; ?>
<div id="content">
<?php include 'navbar.php'; ?>
<div class="container-fluid">
<h2 class="mb-4">添加新闻</h2>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<div class="card mb-4">
<div class="card-body">
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="title">标题</label>
<input type="text" class="form-control" id="title" name="title" required>
</div>
<div class="form-group">
<label for="content">内容</label>
<textarea class="form-control" id="content" name="content" rows="10" required></textarea>
</div>
<div class="form-group">
<label for="category">分类</label>
<select class="form-control" id="category" name="category">
<option value="公司新闻">公司新闻</option>
<option value="行业动态">行业动态</option>
<option value="产品资讯">产品资讯</option>
</select>
</div>
<div class="form-group">
<label for="image">封面图片</label>
<input type="file" class="form-control-file" id="image" name="image">
<small class="form-text text-muted">支持 JPG, PNG, GIF 格式,大小不超过 2MB</small>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="status" name="status" checked>
<label class="form-check-label" for="status">发布</label>
</div>
<button type="submit" class="btn btn-primary">保存</button>
<a href="news.php" class="btn btn-secondary">取消</a>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/summernote-bs4.min.js"></script>
<script src="js/admin.js"></script>
<script>
$(document).ready(function() {
$('#content').summernote({
height: 300,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['fontsize', ['fontsize']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['insert', ['link', 'picture', 'video', 'table', 'hr']],
['view', ['fullscreen', 'codeview', 'help']]
]
});
});
</script>
</body>
</html>
12. API 接口 (api/v1/news.php)
<?php
header('Content-Type: application/json');
require_once '../../includes/db.php';
$db = new Database();
// 设置默认响应
$response = [
'status' => 'error',
'message' => 'Invalid request',
'data' => []
];
// 获取请求方法
$method = $_SERVER['REQUEST_METHOD'];
try {
switch ($method) {
case 'GET':
// 获取新闻列表或单个新闻
if (isset($_GET['id'])) {
// 获取单个新闻
$id = intval($_GET['id']);
$stmt = $db->prepare("SELECT id, title, content, image, category, created_at FROM news WHERE id = ? AND status = 1");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$response['status'] = 'success';
$response['message'] = 'News found';
$response['data'] = $result->fetch_assoc();
} else {
$response['message'] = 'News not found';
}
$stmt->close();
} else {
// 获取新闻列表
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$limit = isset($_GET['limit']) ? max(1, intval($_GET['limit'])) : 10;
$offset = ($page - 1) * $limit;
// 获取总数
$total = $db->query("SELECT COUNT(*) FROM news WHERE status = 1")->fetch_row()[0];
// 获取新闻
$stmt = $db->prepare("SELECT id, title, content, image, category, created_at FROM news WHERE status = 1 ORDER BY created_at DESC LIMIT ? OFFSET ?");
$stmt->bind_param("ii", $limit, $offset);
$stmt->execute();
$result = $stmt->get_result();
$news = [];
while ($row = $result->fetch_assoc()) {
$news[] = $row;
}
$response['status'] = 'success';
$response['message'] = 'News list';
$response['data'] = [
'news' => $news,
'pagination' => [
'total' => $total,
'page' => $page,
'limit' => $limit,
'total_pages' => ceil($total / $limit)
]
];
$stmt->close();
}
break;
case 'POST':
// 创建新闻 (需要认证)
if (!isset($_SERVER['HTTP_AUTHORIZATION']) {
$response['message'] = 'Authentication required';
break;
}
// 验证API密钥
$apiKey = str_replace('Bearer ', '', $_SERVER['HTTP_AUTHORIZATION']);
$validKey = 'your-secret-api-key'; // 应该从配置中获取
if ($apiKey !== $validKey) {
$response['message'] = 'Invalid API key';
break;
}
// 获取输入数据
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['title']) || !isset($input['content'])) {
$response['message'] = 'Title and content are required';
break;
}
$title = sanitize($input['title']);
$content = sanitize($input['content']);
$category = isset($input['category']) ? sanitize($input['category']) : '公司新闻';
$status = isset($input['status']) ? intval($input['status']) : 1;
$image = isset($input['image']) ? sanitize($input['image']) : '';
// 插入数据库
$stmt = $db->prepare("INSERT INTO news (title, content, image, category, status) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("ssssi", $title, $content, $image, $category, $status);
if ($stmt->execute()) {
$response['status'] = 'success';
$response['message'] = 'News created successfully';
$response['data'] = ['id' => $stmt->insert_id];
} else {
$response['message'] = 'Failed to create news';
}
$stmt->close();
break;
default:
$response['message'] = 'Method not allowed';
break;
}
} catch (Exception $e) {
$response['message'] = $e->getMessage();
}
// 输出JSON响应
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>
13. 伪静态配置
Apache (.htaccess)
<IfModule mod_rewrite.c>
RewriteEngine On
# 后台伪静态排除
RewriteRule ^admin/ - [L]
# API伪静态排除
RewriteRule ^api/ - [L]
# 静态资源排除
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ [NC]
# 前端路由
RewriteRule ^([a-zA-Z0-9_-]+)/?$ index.php?page=$1 [L,QSA]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$ index.php?page=$1&action=$2 [L,QSA]
</IfModule>
IIS (web.config)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<!-- 排除后台和API -->
<rule name="Exclude Admin" stopProcessing="true">
<match url="^admin/" ignoreCase="false" />
<action type="None" />
</rule>
<rule name="Exclude API" stopProcessing="true">
<match url="^api/" ignoreCase="false" />
<action type="None" />
</rule>
<!-- 排除静态资源 -->
<rule name="Exclude Static Files" stopProcessing="true">
<match url="\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$" ignoreCase="true" />
<action type="None" />
</rule>
<!-- 前端路由规则 -->
<rule name="Frontend Routes" stopProcessing="true">
<match url="^([a-zA-Z0-9_-]+)/?$" ignoreCase="false" />
<action type="Rewrite" url="index.php?page={R:1}" appendQueryString="true" />
</rule>
<rule name="Frontend Routes with Action" stopProcessing="true">
<match url="^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$" ignoreCase="false" />
<action type="Rewrite" url="index.php?page={R:1}&action={R:2}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
14. 宝塔面板伪静态设置
在宝塔面板中,选择网站 -> 设置 -> 伪静态,然后根据服务器类型选择:
对于Apache
直接复制上面的.htaccess内容即可。
对于Nginx
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /admin/ {
try_files $uri $uri/ /admin/index.php?$query_string;
}
location /api/ {
try_files $uri $uri/ /api/index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires max;
add_header Cache-Control "public, no-transform";
}
15. 前端JavaScript (assets/js/main.js)
$(document).ready(function() {
// 初始化工具提示
$('[data-toggle="tooltip"]').tooltip();
// 初始化弹出框
$('[data-toggle="popover"]').popover();
// 平滑滚动
$('a[href*="#"]').on('click', function(e) {
e.preventDefault();
$('html, body').animate(
{
scrollTop: $($(this).attr('href')).offset().top,
},
500,
'linear'
);
});
// 新闻加载更多
$('#load-more-news').on('click', function() {
const button = $(this);
const page = parseInt(button.data('page')) || 1;
button.text('加载中...').prop('disabled', true);
$.ajax({
url: 'api/v1/news',
data: { page: page + 1, limit: 5 },
dataType: 'json',
success: function(response) {
if (response.status === 'success') {
const news = response.data.news;
if (news.length > 0) {
let html = '';
news.forEach(function(item) {
html += `
<div class="col-md-4 mb-4">
<div class="card news-card">
<img src="${item.image || 'assets/images/news-default.jpg'}" class="card-img-top" alt="${item.title}">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<p class="card-text">${item.content.substring(0, 100)}...</p>
<a href="news/${item.id}" class="btn btn-primary">阅读更多</a>
</div>
<div class="card-footer text-muted">
${new Date(item.created_at).toLocaleDateString()}
</div>
</div>
</div>
`;
});
$('#news-container').append(html);
button.data('page', page + 1).text('加载更多').prop('disabled', false);
if (response.data.pagination.page >= response.data.pagination.total_pages) {
button.hide();
}
} else {
button.text('没有更多新闻').prop('disabled', true);
}
}
},
error: function() {
button.text('加载失败').prop('disabled', false);
}
});
});
// 联系表单提交
$('#contact-form').on('submit', function(e) {
e.preventDefault();
const form = $(this);
const button = form.find('button[type="submit"]');
const originalText = button.text();
button.text('发送中...').prop('disabled', true);
$.ajax({
url: 'api/v1/contact',
method: 'POST',
data: form.serialize(),
dataType: 'json',
success: function(response) {
if (response.status === 'success') {
form[0].reset();
$('#form-message').html(`
<div class="alert alert-success">
${response.message}
</div>
`);
} else {
$('#form-message').html(`
<div class="alert alert-danger">
${response.message}
</div>
`);
}
},
error: function() {
$('#form-message').html(`
<div class="alert alert-danger">
发送失败,请稍后再试
</div>
`);
},
complete: function() {
button.text(originalText).prop('disabled', false);
}
});
});
});
总结
这个解决方案提供了完整的全栈企业官网实现,包括:
- 前端部分:使用HTML5、CSS3和JavaScript实现响应式设计
- 后端部分:PHP实现后台管理功能,包括内容增删改查和文件上传
- API接口:JSON格式的RESTful API,便于前后端分离和移动端调用
- 数据库:MySQL数据库设计和管理
- 伪静态:支持Apache、IIS和Nginx的伪静态规则
- 安全性:管理员认证、输入过滤和防SQL注入
您可以根据实际需求进一步扩展和定制这个解决方案。 更多详情:baijiahao.baidu.com/s?id=183050…