PHP 怎么PHP Wiki

wen PHP项目 1

本文目录导读:

PHP 怎么PHP Wiki

  1. 方案一:使用现成的 Wiki 系统
  2. 方案二:从零开发简单 Wiki
  3. 方案三:使用框架构建
  4. 推荐学习资源

我来帮你了解如何使用 PHP 构建一个 Wiki 系统,这里提供一个从简单到完整方案的全景介绍:

使用现成的 Wiki 系统

MediaWiki(最流行)

# 需要环境:PHP 7.4+, MySQL, Composer
composer create-project mediawiki/core my-wiki

DokuWiki(轻量级)

# 只需要 PHP,不需要数据库
wget https://download.dokuwiki.org/src/dokuwiki/dokuwiki-stable.tgz
tar -xzf dokuwiki-stable.tgz

Tiki Wiki(功能丰富)

composer create-project tikiwiki/tiki my-tiki

从零开发简单 Wiki

基础架构设计

// config.php
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'wiki_db');
define('DB_USER', 'root');
define('DB_PASS', '');
define('BASE_URL', 'http://localhost/wiki');
define('UPLOAD_DIR', __DIR__ . '/uploads/');
// 数据库连接
function db_connect() {
    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    if ($conn->connect_error) {
        die("连接失败: " . $conn->connect_error);
    }
    return $conn;
}
?>

创建数据库表

// install.php
<?php
$conn = db_connect();
$sql = "
CREATE TABLE IF NOT EXISTS pages (
    id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL UNIQUE,
    content MEDIUMTEXT,
    slug VARCHAR(255) UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS revisions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    page_id INT,
    content MEDIUMTEXT,
    user_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (page_id) REFERENCES pages(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE,
    password_hash VARCHAR(255),
    email VARCHAR(100),
    role ENUM('admin', 'editor', 'viewer') DEFAULT 'viewer',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login TIMESTAMP NULL
);
CREATE TABLE IF NOT EXISTS categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) UNIQUE,
    description TEXT,
    parent_id INT NULL
);
CREATE TABLE IF NOT EXISTS pages_categories (
    page_id INT,
    category_id INT,
    PRIMARY KEY (page_id, category_id)
);
CREATE TABLE IF NOT EXISTS tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) UNIQUE
);
CREATE TABLE IF NOT EXISTS pages_tags (
    page_id INT,
    tag_id INT,
    PRIMARY KEY (page_id, tag_id)
);
CREATE TABLE IF NOT EXISTS search_terms (
    id INT AUTO_INCREMENT PRIMARY KEY,
    term VARCHAR(255) UNIQUE,
    page_id INT,
    weight FLOAT DEFAULT 1.0
);
";
$conn->query($sql);
?>

页面管理类

// Page.php
<?php
class Page {
    private $conn;
    private $table = 'pages';
    public function __construct() {
        $this->conn = db_connect();
    }
    // 创建页面
    public function create($title, $content, $category_ids = [], $tags = []) {
        $slug = $this->createSlug($title);
        $stmt = $this->conn->prepare("INSERT INTO $this->table (title, content, slug) VALUES (?, ?, ?)");
        $stmt->bind_param("sss", $title, $content, $slug);
        if ($stmt->execute()) {
            $page_id = $stmt->insert_id;
            $this->addCategories($page_id, $category_ids);
            $this->addTags($page_id, $tags);
            $this->updateSearchIndex($page_id, $content);
            return $page_id;
        }
        return false;
    }
    // 获取页面
    public function getPage($id = null, $slug = null) {
        if ($id) {
            $sql = "SELECT * FROM $this->table WHERE id = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param("i", $id);
        } else if ($slug) {
            $sql = "SELECT * FROM $this->table WHERE slug = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param("s", $slug);
        }
        $stmt->execute();
        $result = $stmt->get_result();
        return $result->fetch_assoc();
    }
    // 更新页面
    public function update($id, $content, $category_ids = [], $tags = []) {
        $sql = "UPDATE $this->table SET content = ? WHERE id = ?";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("si", $content, $id);
        if ($stmt->execute()) {
            // 保存修订历史
            $this->saveRevision($id, $content);
            $this->updateCategories($id, $category_ids);
            $this->updateTags($id, $tags);
            $this->updateSearchIndex($id, $content);
            return true;
        }
        return false;
    }
    // 删除页面
    public function delete($id) {
        $this->conn->begin_transaction();
        try {
            // 删除相关数据
            $this->conn->query("DELETE FROM pages_categories WHERE page_id = $id");
            $this->conn->query("DELETE FROM pages_tags WHERE page_id = $id");
            $this->conn->query("DELETE FROM revisions WHERE page_id = $id");
            $this->conn->query("DELETE FROM search_terms WHERE page_id = $id");
            // 删除页面
            $sql = "DELETE FROM $this->table WHERE id = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param("i", $id);
            $stmt->execute();
            $this->conn->commit();
            return true;
        } catch (Exception $e) {
            $this->conn->rollback();
            return false;
        }
    }
    // 搜索页面
    public function search($query) {
        $sql = "SELECT p.*, MATCH(p.content, p.title) AS relevance 
                FROM $this->table p 
                WHERE MATCH(p.content, p.title) AGAINST (?) 
                ORDER BY relevance DESC LIMIT 10";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("s", $query);
        $stmt->execute();
        $result = $stmt->get_result();
        return $result->fetch_all(MYSQLI_ASSOC);
    }
    // 创建 URL 别名
    private function createSlug($title) {
        $slug = strtolower($title);
        $slug = preg_replace('/[^a-z0-9-]/', '-', $slug);
        $slug = preg_replace('/-+/', '-', $slug);
        $slug = trim($slug, '-');
        return $slug;
    }
    // 保存修订
    private function saveRevision($page_id, $content) {
        $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 1;
        $stmt = $this->conn->prepare("INSERT INTO revisions (page_id, content, user_id) VALUES (?, ?, ?)");
        $stmt->bind_param("isi", $page_id, $content, $user_id);
        $stmt->execute();
    }
    // 更新索引
    private function updateSearchIndex($page_id, $content) {
        // 清除旧索引
        $this->conn->query("DELETE FROM search_terms WHERE page_id = $page_id");
        // 提取关键词(简化示例)
        $words = str_word_count(strip_tags($content), 1);
        $stop_words = ['the', 'a', 'an', 'and', 'or', 'but'];
        $word_count = array_count_values($words);
        foreach ($word_count as $word => $count) {
            if (!in_array($word, $stop_words) && strlen($word) > 3) {
                $weight = $count / max(1, count($words));
                $stmt = $this->conn->prepare("INSERT IGNORE INTO search_terms (term, page_id, weight) VALUES (?, ?, ?)");
                $stmt->bind_param("sid", $word, $page_id, $weight);
                $stmt->execute();
            }
        }
    }
    // 关联分类
    private function addCategories($page_id, $category_ids) {
        if (empty($category_ids)) return;
        foreach ($category_ids as $cat_id) {
            $stmt = $this->conn->prepare("INSERT IGNORE INTO pages_categories (page_id, category_id) VALUES (?, ?)");
            $stmt->bind_param("ii", $page_id, $cat_id);
            $stmt->execute();
        }
    }
    // 添加标签
    private function addTags($page_id, $tags) {
        if (empty($tags)) return;
        foreach ($tags as $tag) {
            // 获取或创建标签
            $stmt = $this->conn->prepare("INSERT IGNORE INTO tags (name) VALUES (?)");
            $stmt->bind_param("s", $tag);
            $stmt->execute();
            $tag_id = $this->conn->insert_id ?: $this->getTagId($tag);
            $stmt = $this->conn->prepare("INSERT IGNORE INTO pages_tags (page_id, tag_id) VALUES (?, ?)");
            $stmt->bind_param("ii", $page_id, $tag_id);
            $stmt->execute();
        }
    }
    private function getTagId($name) {
        $sql = "SELECT id FROM tags WHERE name = ?";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("s", $name);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        return $row['id'] ?? 0;
    }
}
?>

前端控制器

// router.php
<?php
// 简单的路由器
class Router {
    private $routes = [];
    public function get($path, $callback) {
        $this->routes['GET'][$path] = $callback;
    }
    public function post($path, $callback) {
        $this->routes['POST'][$path] = $callback;
    }
    public function resolve() {
        $method = $_SERVER['REQUEST_METHOD'];
        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        foreach ($this->routes[$method] ?? [] as $route => $callback) {
            if ($route === $path) {
                return call_user_func($callback);
            }
        }
        http_response_code(404);
        echo "404 Not Found";
    }
}
$router = new Router();
// 页面路由
$router->get('/wiki', function() {
    $page = new Page();
    $pages = $page->getAll();
    include 'templates/home.php';
});
$router->get('/wiki/page/{id}', function($id) {
    $page = new Page();
    $data = $page->getPage($id);
    include 'templates/page-view.php';
});
// 创建页面
$router->get('/wiki/create', function() {
    include 'templates/page-create.php';
});
$router->post('/wiki/create', function() {
    $page = new Page();
    $page->create($_POST['title'], $_POST['content']);
    header("Location: /wiki/page/" . $page->getLastId());
});
// 编辑页面
$router->get('/wiki/edit/{id}', function($id) {
    $page = new Page();
    $data = $page->getPage($id);
    include 'templates/page-edit.php';
});
$router->post('/wiki/edit/{id}', function($id) {
    $page = new Page();
    $page->update($id, $_POST['content']);
    header("Location: /wiki/page/$id");
});
// 搜索
$router->get('/wiki/search', function() {
    $page = new Page();
    $results = $page->search($_GET['q'] ?? '');
    include 'templates/search-results.php';
});
$router->resolve();
?>

使用框架构建

使用 Laravel(推荐)

composer create-project laravel/laravel wiki-app

模型

// app/Models/Page.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Page extends Model {
    protected $fillable = ['title', 'content', 'slug', 'category_id'];
    public function categories() {
        return $this->belongsToMany(Category::class);
    }
    public function tags() {
        return $this->belongsToMany(Tag::class);
    }
    public function revisions() {
        return $this->hasMany(Revision::class);
    }
    public function user() {
        return $this->belongsTo(User::class);
    }
    public function searchableAs() {
        return 'wiki_pages';
    }
}
?>

控制器

// app/Http/Controllers/WikiController.php
<?php
namespace App\Http\Controllers;
use App\Models\Page;
use Illuminate\Http\Request;
class WikiController extends Controller {
    public function index() {
        $pages = Page::latest()->paginate(10);
        return view('wiki.index', compact('pages'));
    }
    public function show($slug) {
        $page = Page::where('slug', $slug)->firstOrFail();
        return view('wiki.show', compact('page'));
    }
    public function create() {
        return view('wiki.create');
    }
    public function store(Request $request) {
        $validated = $request->validate([
            'title' => 'required|unique:pages',
            'content' => 'required',
        ]);
        $page = Page::create($validated);
        return redirect()->route('wiki.show', $page->slug);
    }
    public function edit($slug) {
        $page = Page::where('slug', $slug)->firstOrFail();
        return view('wiki.edit', compact('page'));
    }
    public function update(Request $request, $slug) {
        $page = Page::where('slug', $slug)->firstOrFail();
        $validated = $request->validate([
            'title' => 'required|unique:pages,title,'.$page->id,
            'content' => 'required',
        ]);
        $page->update($validated);
        return redirect()->route('wiki.show', $page->slug);
    }
    public function search(Request $request) {
        $query = $request->input('q');
        $pages = Page::where('title', 'LIKE', "%{$query}%")
                    ->orWhere('content', 'LIKE', "%{$query}%")
                    ->get();
        return view('wiki.search', compact('pages', 'query'));
    }
}
?>

推荐学习资源

  1. 官方文档

    • PHP 官方文档:https://www.php.net/manual/
    • Laravel 文档:https://laravel.com/docs
  2. 学习路径

    • 基础:变量、数组、函数、OOP
    • 进阶:MVC 架构、路由、中间件
    • 实践:CRUD 应用、用户认证
  3. 工具推荐

    • IDE:PhpStorm、VS Code + PHP Intelephense
    • 调试:Xdebug
    • 包管理:Composer
  4. 完整 Wiki 系统推荐

    • MediaWiki(资料最多)
    • DokuWiki(轻量简单)
    • BookStack(界面美观)

建议先使用现成系统了解 Wiki 功能,再根据需求决定是否自己开发,如果自己开发,推荐使用 Laravel 框架,开发效率更高,需要更详细的代码示例吗?

抱歉,评论功能暂时关闭!