我们将使用 Laravel 作为 PHP 框架,虽然您提到了“模板”,但直接使用原生 PHP 写模板会比较混乱,而像 Laravel 这样的现代 MVC 框架,其“模板”系统(Blade)非常强大、优雅且安全,是当前行业的主流实践。

php mysql 网站模板
(图片来源网络,侵删)

为什么选择 Laravel?

  • MVC 架构:代码结构清晰,易于维护。
  • Eloquent ORM:让数据库操作变得像“与对象对话”一样简单。
  • Blade 模板引擎:提供强大的模板继承和组件功能。
  • 强大的生态系统:有海量的扩展包,可以快速实现各种功能。
  • 安全性高:内置了防止 SQL 注入、XSS 等攻击的机制。

第一步:环境准备

在开始之前,您需要准备好本地开发环境。

  1. PHP: 版本 >= 8.0
  2. Composer: PHP 的依赖管理工具。
  3. MySQL: 数据库服务。
  4. Web 服务器: Nginx 或 Apache (推荐使用集成环境如 XAMPP, WAMP, MAMP 或 Docker)。

第二步:安装 Laravel

Laravel 提供了一个非常方便的安装器。

  1. 全局安装 Laravel 安装器 (如果尚未安装):

    composer global require laravel/installer

    确保将 ~/.composer/vendor/bin 添加到您的 PATH 环境变量中。

    php mysql 网站模板
    (图片来源网络,侵删)
  2. 创建一个新的 Laravel 项目:

    laravel new my-website

    或者使用 Composer:

    composer create-project laravel/laravel my-website
  3. 进入项目目录:

    cd my-website
  4. 启动开发服务器:

    php mysql 网站模板
    (图片来源网络,侵删)
    php artisan serve

    现在在浏览器中访问 http://127.0.0.1:8000,您应该能看到 Laravel 的欢迎页面。


第三步:项目结构解析

Laravel 的目录结构非常清晰:

my-website/
├── app/                  # 核心应用代码
│   ├── Http/
│   │   ├── Controllers/ # 控制器
│   │   └── Middleware/  # 中间件
│   ├── Models/          # 数据模型
│   └── Providers/       # 服务提供者
├── config/              # 配置文件
├── database/
│   ├── migrations/      # 数据库迁移文件
│   └── seeds/           # 数据库填充文件
├── public/              # Web 可访问的目录 (CSS, JS, 图片)
├── resources/
│   ├── views/           # Blade 模板文件
│   └── lang/            # 语言文件
├── routes/              # 路由定义文件
├── .env                 # 环境变量配置 (重要!)
└── composer.json        # 项目依赖

第四步:配置数据库

  1. 创建数据库: 在您的 MySQL 管理工具 (如 phpMyAdmin) 中创建一个新的数据库,my_website_db

  2. 配置 .env 文件: 在项目根目录下,找到 .env 文件并修改数据库配置:

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=my_website_db
    DB_USERNAME=your_mysql_username
    DB_PASSWORD=your_mysql_password

第五步:构建核心功能模块

我们将构建一个简单的博客系统作为示例,它包含文章列表、文章详情和后台管理。

数据库迁移

Laravel 使用迁移来管理数据库结构,我们创建一个 posts 表。

php artisan make:migration create_posts_table --create=posts

这会在 database/migrations/ 目录下创建一个新的文件,打开它并定义表结构:

// database/migrations/xxxx_xx_xx_xxxxxx_create_posts_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->boolean('is_published')->default(false);
            $table->timestamps(); // 自动创建 created_at 和 updated_at
        });
    }
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

运行迁移来创建表:

php artisan migrate

创建模型

模型是与数据库表交互的类。

php artisan make:model Post

这会在 app/Models/Post.php 创建模型文件,我们可以在这里添加一些规则:

// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    use HasFactory;
    // 定义哪些属性可以被批量赋值
    protected $fillable = [
        'title',
        'content',
        'is_published',
    ];
    // 可以添加一个作用域,方便查询已发布的文章
    public function scopePublished($query)
    {
        return $query->where('is_published', true);
    }
}

定义路由

路由定义了 URL 如何映射到控制器。

打开 routes/web.php

// routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
// 前台路由
Route::get('/', [PostController::class, 'index'])->name('home');
Route::get('posts/{post:slug}', [PostController::class, 'show'])->name('posts.show');
// 后台路由组
Route::prefix('admin')->name('admin.')->middleware('auth')->group(function () {
    Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
    Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
    Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
    Route::get('/posts/{post}/edit', [PostController::class, 'edit'])->name('posts.edit');
    Route::put('/posts/{post}', [PostController::class, 'update'])->name('posts.update');
    Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
});
// 简单的认证路由
require __DIR__.'/auth.php';
  • name() 方法为路由命名,方便在模板中生成链接。
  • middleware('auth') 表示这些路由需要登录才能访问。

创建控制器

控制器处理业务逻辑。

php artisan make:controller PostController --resource

--resource 会自动生成处理 CRUD (增删改查) 操作的方法。

打开 app/Http/Controllers/PostController.php 并填充逻辑:

// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
    // 显示文章列表 (前台)
    public function index()
    {
        $posts = Post::published()->latest()->paginate(10);
        return view('posts.index', compact('posts'));
    }
    // 显示单篇文章详情
    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }
    // 后台:显示文章列表
    public function index()
    {
        $posts = Post::latest()->paginate(10);
        return view('admin.posts.index', compact('posts'));
    }
    // 后台:显示创建文章的表单
    public function create()
    {
        return view('admin.posts.create');
    }
    // 后台:保存新文章
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);
        Post::create($request->all());
        return redirect()->route('admin.posts.index')
                         ->with('success', '文章创建成功!');
    }
    // ... 其他后台方法 (edit, update, destroy) ...
    // 逻辑类似,主要是处理表单验证和模型操作
}

创建视图 (Blade 模板)

视图是用户看到的 HTML 部分,我们将创建一个主布局文件和几个子页面。

a) 主布局文件 resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">@yield('title', '我的网站')</title>
    <!-- 引入一个 CSS 框架,如 Tailwind CSS 或 Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    @stack('styles')
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="{{ route('home') }}">我的网站</a>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto">
                    <li class="nav-item"><a class="nav-link" href="{{ route('home') }}">首页</a></li>
                    <!-- 后台链接,只有登录用户可见 -->
                    @auth
                        <li class="nav-item"><a class="nav-link" href="{{ route('admin.posts.index') }}">后台管理</a></li>
                    @endauth
                </ul>
                @guest
                    <a href="{{ route('login') }}" class="btn btn-outline-light">登录</a>
                @else
                    <a href="{{ route('logout') }}"
                       class="btn btn-outline-light"
                       onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
                        退出
                    </a>
                    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                        @csrf
                    </form>
                @endguest
            </div>
        </div>
    </nav>
    <div class="container mt-4">
        @if (session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif
        @yield('content')
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    @stack('scripts')
</body>
</html>

关键 Blade 指令:

  • @yield('title'): 定义一个可填充的区域,用于页面标题。
  • @stack('styles') / @stack('scripts'): 允许子页面向布局中注入 CSS 或 JS 代码。
  • @auth / @guest: 判断用户是否登录,显示不同的内容。
  • @yield('content'): 这是主要内容区域,每个页面都会填充这里。

b) 前台文章列表 resources/views/posts/index.blade.php

@extends('layouts.app')
@section('title', '文章列表')
@section('content')
    <h1>文章列表</h1>
    @foreach ($posts as $post)
        <article class="card mb-3">
            <div class="card-body">
                <h2 class="card-title">
                    <a href="{{ route('posts.show', $post) }}" class="text-decoration-none">
                        {{ $post->title }}
                    </a>
                </h2>
                <p class="card-text">{{ Str::limit($post->content, 100) }}</p>
                <small class="text-muted">发布于: {{ $post->created_at->format('Y-m-d') }}</small>
            </div>
        </article>
    @endforeach
    {{ $posts->links() }} <!-- 分页链接 -->
@endsection

c) 前台文章详情 resources/views/posts/show.blade.php

@extends('layouts.app')
@section('title', $post->title)
@section('content')
    <article>
        <h1>{{ $post->title }}</h1>
        <p class="text-muted">发布于: {{ $post->created_at->format('Y-m-d H:i') }}</p>
        <hr>
        <div class="content">
            {!! $post->content !!} {!! !!} 使用 {!! !!} 安全地渲染 HTML 内容
        </div>
    </article>
@endsection

d) 后台文章列表 resources/views/admin/posts/index.blade.php

@extends('layouts.app')
@section('title', '管理文章')
@section('content')
    <h1>管理文章</h1>
    <a href="{{ route('admin.posts.create') }}" class="btn btn-primary mb-3">创建新文章</a>
    <table class="table table-striped">
        <thead>
            <tr>
                <th>ID</th>
                <th>标题</th>
                <th>状态</th>
                <th>创建时间</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach ($posts as $post)
                <tr>
                    <td>{{ $post->id }}</td>
                    <td>{{ $post->title }}</td>
                    <td>{{ $post->is_published ? '已发布' : '草稿' }}</td>
                    <td>{{ $post->created_at->format('Y-m-d') }}</td>
                    <td>
                        <a href="{{ route('admin.posts.edit', $post) }}" class="btn btn-sm btn-info">编辑</a>
                        <form action="{{ route('admin.posts.destroy', $post) }}" method="POST" style="display: inline;">
                            @csrf
                            @method('DELETE')
                            <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('确定要删除吗?')">删除</button>
                        </form>
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
@endsection

第六步:用户认证

Laravel 提供了开箱即用的用户认证系统。

  1. 运行认证脚手架命令:

    php artisan make:auth

    注意:在新版 Laravel 中,这个命令被替换了,您需要安装 laravel/ui 包。

    composer require laravel/ui
    php artisan ui bootstrap --auth
    npm install && npm run dev

    这会自动生成登录、注册、密码重置等页面和相关的控制器、路由。

  2. 创建用户表: 运行迁移来创建 users 表和相关的密码重置表。

    php artisan migrate

您就有了完整的用户注册、登录功能,之前我们在后台路由中使用的 middleware('auth') 现在已经可以正常工作了。


第七步:部署

当您的网站开发完成后,需要将其部署到服务器上。

  1. Git 版本控制: 将您的代码推送到 GitHub、GitLab 等平台。
  2. 服务器环境: 在您的服务器上安装 PHP, Nginx/Apache, MySQL, Composer。
  3. 拉取代码: git clone <your-repo-url>
  4. 安装依赖: composer install --no-dev (生产环境不需要开发依赖)
  5. 配置环境: 复制 .env.example.env 并修改数据库等配置。
  6. 生成应用密钥: php artisan key:generate
  7. 运行迁移: php artisan migrate --force (生产环境需要 --force)
  8. 配置 Web 服务器: 将 Nginx/Apache 的 root 指向 public 目录,并配置 URL 重写。

总结与扩展

您现在已经有了一个功能齐全的、基于 Laravel 的 PHP MySQL 网站模板,这个模板包含了:

  • 清晰的 MVC 架构
  • 数据库迁移和 Eloquent ORM
  • 强大的 Blade 模板系统
  • RESTful 路由设计
  • 用户认证系统
  • 前后台分离的示例

您可以基于此模板进行扩展:

  • 添加更多功能: 如评论系统、标签、分类、用户角色等。
  • 使用 API: 创建一个 API 控制器,为移动端提供数据。
  • 优化性能: 学习使用缓存、队列、优化数据库查询等。
  • 使用 Vue/React: 在 resources/js 中集成前端框架,构建更动态的用户界面。

这个模板为您提供了一个坚实的基础,是构建现代 PHP 网站的绝佳起点。