当前位置: 首页 > news >正文

PHP版本控制系统:高效文档管理

系统功能说明

这个PHP版本控制系统实现了以下核心功能:

1. 用户认证与权限管理

  • 用户注册、登录和登出
  • 三级权限系统:管理员(admin)、编辑者(editor)和查看者(viewer)
  • 基于角色的访问控制(RBAC)

2. 仓库管理

  • 创建新仓库
  • 查看仓库列表和详情
  • 仓库统计信息(提交数、分支数、贡献者)

3. 文档版本控制

  • 上传文档到仓库
  • 查看文档历史版本
  • 检索特定版本的文档内容
  • 类似Git的提交机制

4. 分支管理

  • 创建新分支
  • 查看分支列表
  • 合并分支到主分支

5. 权限控制

  • 仓库级别的权限控制
  • 基于用户角色的操作限制

安装与使用

  1. 创建数据库并运行install.php初始化数据库结构
  2. 配置config.php中的数据库连接信息
  3. 将所有文件上传到Web服务器
  4. 访问系统首页进行注册和登录
  5. 管理员可以创建仓库,用户可以上传文档并管理版本

这个系统提供了完整的文档版本控制功能,适合团队协作管理文档,支持权限分级和版本历史追踪。

以下是一些视图文件的示例,用于展示用户界面:

	/* css/style.css */* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;background-color: #f5f5f5;}.container {max-width: 1200px;margin: 0 auto;padding: 0 20px;}header {background-color: #2c3e50;color: white;padding: 1rem 0;margin-bottom: 2rem;}header h1 {display: inline-block;margin-right: 2rem;}header nav {display: inline-block;}header nav a {color: white;text-decoration: none;margin-right: 1rem;padding: 0.5rem;border-radius: 4px;transition: background-color 0.3s;}header nav a:hover {background-color: #34495e;}main {background-color: white;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);padding: 2rem;margin-bottom: 2rem;}footer {text-align: center;padding: 1rem 0;color: #7f8c8d;font-size: 0.9rem;}/* Home Page */.hero {text-align: center;padding: 3rem 0;background-color: #3498db;color: white;border-radius: 8px;margin-bottom: 2rem;}.hero h2 {font-size: 2.5rem;margin-bottom: 1rem;}.hero p {font-size: 1.2rem;margin-bottom: 2rem;max-width: 800px;margin-left: auto;margin-right: auto;}.cta a {display: inline-block;margin: 0 0.5rem;padding: 0.75rem 1.5rem;border-radius: 4px;text-decoration: none;font-weight: bold;}.btn {background-color: #2ecc71;color: white;}.btn-secondary {background-color: #95a5a6;color: white;}.features {display: flex;justify-content: space-between;margin-top: 2rem;}.feature {flex: 1;padding: 1.5rem;margin: 0 0.5rem;background-color: #f8f9fa;border-radius: 8px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);}.feature h3 {margin-bottom: 1rem;color: #2c3e50;}/* Dashboard */.dashboard-header {margin-bottom: 2rem;padding-bottom: 1rem;border-bottom: 1px solid #ecf0f1;}.dashboard-header h2 {margin-bottom: 0.5rem;}.repositories h3 {margin-bottom: 1rem;}.repo-list {display: grid;grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));gap: 1.5rem;}.repo-card {background-color: #f8f9fa;border-radius: 8px;padding: 1.5rem;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);transition: transform 0.3s, box-shadow 0.3s;}.repo-card:hover {transform: translateY(-5px);box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);}.repo-card h4 {margin-bottom: 0.5rem;}.repo-card h4 a {color: #3498db;text-decoration: none;}.repo-card h4 a:hover {text-decoration: underline;}.repo-meta {margin-top: 1rem;font-size: 0.9rem;color: #7f8c8d;}.repo-meta span {margin-right: 1rem;}/* Repository Page */.repo-header {margin-bottom: 2rem;padding-bottom: 1rem;border-bottom: 1px solid #ecf0f1;}.repo-header h2 {margin-bottom: 0.5rem;}.repo-actions {margin-top: 1rem;}.repo-actions a {margin-right: 0.5rem;}.repo-stats {display: flex;margin-bottom: 2rem;}.stat {flex: 1;padding: 1rem;background-color: #f8f9fa;border-radius: 8px;text-align: center;margin: 0 0.5rem;}.stat h4 {margin-bottom: 0.5rem;color: #7f8c8d;}.stat p {font-size: 1.5rem;font-weight: bold;color: #2c3e50;}.repo-latest-commit, .repo-branches, .repo-documents {margin-bottom: 2rem;}.repo-latest-commit h3, .repo-branches h3, .repo-documents h3 {margin-bottom: 1rem;padding-bottom: 0.5rem;border-bottom: 1px solid #ecf0f1;}.commit {padding: 1rem;background-color: #f8f9fa;border-radius: 8px;}.commit-message {margin-bottom: 0.5rem;font-weight: bold;}.commit-meta {font-size: 0.9rem;color: #7f8c8d;}.commit-meta span {margin-right: 1rem;}.repo-branches ul {list-style-type: none;}.repo-branches li {padding: 0.5rem 0;border-bottom: 1px solid #ecf0f1;}.document-list {width: 100%;border-collapse: collapse;}.document-list th, .document-list td {padding: 0.75rem;text-align: left;border-bottom: 1px solid #ecf0f1;}.document-list th {background-color: #f8f9fa;font-weight: bold;}.document-list tr:hover {background-color: #f8f9fa;}/* Forms */.form-container {max-width: 600px;margin: 0 auto;}.form-container h2 {margin-bottom: 1.5rem;text-align: center;}.form-group {margin-bottom: 1.5rem;}.form-group label {display: block;margin-bottom: 0.5rem;font-weight: bold;}.form-group input[type="text"],.form-group input[type="email"],.form-group input[type="password"],.form-group input[type="file"],.form-group textarea {width: 100%;padding: 0.75rem;border: 1px solid #ddd;border-radius: 4px;font-size: 1rem;}.form-group textarea {resize: vertical;}.form-group small {display: block;margin-top: 0.25rem;color: #7f8c8d;font-size: 0.9rem;}.form-actions {text-align: center;margin-top: 2rem;}.form-actions button {margin: 0 0.5rem;}.error {padding: 1rem;margin-bottom: 1rem;background-color: #f8d7da;color: #721c24;border-radius: 4px;border: 1px solid #f5c6cb;}/* Responsive Design */@media (max-width: 768px) {header {text-align: center;}header h1 {display: block;margin-bottom: 1rem;}.features {flex-direction: column;}.feature {margin: 0.5rem 0;}.repo-stats {flex-direction: column;}.stat {margin: 0.5rem 0;}.repo-list {grid-template-columns: 1fr;}}

view

	<!-- views/upload.php --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Upload Document - <?php echo htmlspecialchars($repository['name']); ?></title><link rel="stylesheet" href="css/style.css"></head><body><div class="container"><header><h1>Document Version Control System</h1><nav><a href="index.php">Home</a><a href="index.php?action=home">Dashboard</a><a href="index.php?action=repo&id=<?php echo $repository['id']; ?>">Repository</a><a href="index.php?action=logout">Logout</a></nav></header><main><div class="form-container"><h2>Upload Document</h2><?php if (isset($error)): ?><div class="error"><?php echo htmlspecialchars($error); ?></div><?php endif; ?><form action="index.php?action=upload&id=<?php echo $repository['id']; ?>" method="post" enctype="multipart/form-data"><div class="form-group"><label for="file">Select Document</label><input type="file" id="file" name="file" required><small>Allowed file types: <?php echo implode(', ', Config::ALLOWED_EXTENSIONS); ?></small></div><div class="form-group"><label for="message">Commit Message</label><textarea id="message" name="message" rows="3"></textarea></div><div class="form-actions"><button type="submit" class="btn">Upload Document</button><a href="index.php?action=repo&id=<?php echo $repository['id']; ?>" class="btn btn-secondary">Cancel</a></div></form></div></main><footer><p>&copy; <?php echo date('Y'); ?> Document Version Control System</p></footer></div></body></html>
	<!-- views/repo.php --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title><?php echo htmlspecialchars($repository['name']); ?> - Document VCS</title><link rel="stylesheet" href="css/style.css"></head><body><div class="container"><header><h1>Document Version Control System</h1><nav><a href="index.php">Home</a><a href="index.php?action=home">Dashboard</a><a href="index.php?action=logout">Logout</a></nav></header><main><div class="repo-header"><h2><?php echo htmlspecialchars($repository['name']); ?></h2><p><?php echo htmlspecialchars($repository['description']); ?></p><div class="repo-actions"><?php if ($auth->hasPermission('write', $repository['id'])): ?><a href="index.php?action=upload&id=<?php echo $repository['id']; ?>" class="btn">Upload Document</a><a href="index.php?action=create_branch&repo_id=<?php echo $repository['id']; ?>" class="btn">Create Branch</a><a href="index.php?action=merge_branch&repo_id=<?php echo $repository['id']; ?>" class="btn">Merge Branch</a><?php endif; ?></div></div><div class="repo-stats"><div class="stat"><h4>Commits</h4><p><?php echo $stats['commit_count']; ?></p></div><div class="stat"><h4>Branches</h4><p><?php echo $stats['branch_count']; ?></p></div><div class="stat"><h4>Contributors</h4><p><?php echo count($stats['contributors']); ?></p></div></div><div class="repo-latest-commit"><h3>Latest Commit</h3><?php if (isset($repository['latest_commit'])): ?><div class="commit"><p class="commit-message"><?php echo htmlspecialchars($repository['latest_commit']['message']); ?></p><div class="commit-meta"><span>Hash: <?php echo substr($repository['latest_commit']['hash'], 0, 7); ?></span><span>Author: <?php echo htmlspecialchars($repository['latest_commit']['author']); ?></span><span>Date: <?php echo $repository['latest_commit']['date']; ?></span></div></div><?php else: ?><p>No commits yet</p><?php endif; ?></div><div class="repo-branches"><h3>Branches</h3><ul><?php foreach ($repository['branches'] as $branch): ?><li><?php echo htmlspecialchars($branch); ?></li><?php endforeach; ?></ul></div><div class="repo-documents"><h3>Documents</h3><?php if (empty($documents)): ?><p>No documents found.</p><?php else: ?><table class="document-list"><thead><tr><th>Name</th><th>Actions</th></tr></thead><tbody><?php foreach ($documents as $doc): ?><tr><td><?php echo htmlspecialchars($doc['name']); ?></td><td><a href="index.php?action=history&repo_id=<?php echo $repository['id']; ?>&file=<?php echo urlencode($doc['name']); ?>">View History</a></td></tr><?php endforeach; ?></tbody></table><?php endif; ?></div></main><footer><p>&copy; <?php echo date('Y'); ?> Document Version Control System</p></footer></div></body></html>
	<!-- views/dashboard.php --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Dashboard - Document VCS</title><link rel="stylesheet" href="css/style.css"></head><body><div class="container"><header><h1>Document Version Control System</h1><nav><a href="index.php">Home</a><a href="index.php?action=home">Dashboard</a><?php if ($auth->getUser()['role'] === Config::ROLE_ADMIN): ?><a href="index.php?action=create_repo">Create Repository</a><?php endif; ?><a href="index.php?action=logout">Logout</a></nav></header><main><div class="dashboard-header"><h2>Welcome, <?php echo htmlspecialchars($auth->getUser()['username']); ?></h2><p>Role: <?php echo ucfirst($auth->getUser()['role']); ?></p></div><div class="repositories"><h3>Your Repositories</h3><?php if (empty($repositories)): ?><p>No repositories found. <?php if ($auth->getUser()['role'] === Config::ROLE_ADMIN): ?><a href="index.php?action=create_repo">Create one</a><?php endif; ?></p><?php else: ?><div class="repo-list"><?php foreach ($repositories as $repo): ?><div class="repo-card"><h4><a href="index.php?action=repo&id=<?php echo $repo['id']; ?>"><?php echo htmlspecialchars($repo['name']); ?></a></h4><p><?php echo htmlspecialchars($repo['description']); ?></p><div class="repo-meta"><span>Created: <?php echo date('M j, Y', strtotime($repo['created_at'])); ?></span><span>Owner: <?php echo htmlspecialchars($repo['owner_id']); ?></span></div></div><?php endforeach; ?></div><?php endif; ?></div></main><footer><p>&copy; <?php echo date('Y'); ?> Document Version Control System</p></footer></div></body></html>
	<!-- views/home.php --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document Version Control System</title><link rel="stylesheet" href="css/style.css"></head><body><div class="container"><header><h1>Document Version Control System</h1><nav><a href="index.php">Home</a><?php if ($auth->isLoggedIn()): ?><a href="index.php?action=logout">Logout</a><?php else: ?><a href="index.php?action=login">Login</a><a href="index.php?action=register">Register</a><?php endif; ?></nav></header><main><div class="hero"><h2>Welcome to Document VCS</h2><p>A powerful version control system for managing your documents with Git-like features.</p><?php if (!$auth->isLoggedIn()): ?><div class="cta"><a href="index.php?action=login" class="btn">Login</a><a href="index.php?action=register" class="btn btn-secondary">Register</a></div><?php else: ?><div class="cta"><a href="index.php?action=home" class="btn">Go to Dashboard</a></div><?php endif; ?></div><div class="features"><div class="feature"><h3>Version Control</h3><p>Track changes, view history, and revert to previous versions of your documents.</p></div><div class="feature"><h3>Branching & Merging</h3><p>Create branches for experimental changes and merge them back when ready.</p></div><div class="feature"><h3>Permission Management</h3><p>Control who can view, edit, or administer your repositories with fine-grained permissions.</p></div></div></main><footer><p>&copy; <?php echo date('Y'); ?> Document Version Control System</p></footer></div></body></html>
	<?php// config.php - 配置文件class Config {// 数据库配置const DB_HOST = 'localhost';const DB_NAME = 'document_vcs';const DB_USER = 'root';const DB_PASS = '';// 文件存储路径const REPO_PATH = __DIR__ . '/repositories/';const UPLOAD_PATH = __DIR__ . '/uploads/';// 权限级别const ROLE_ADMIN = 'admin';      // 管理员:完全控制const ROLE_EDITOR = 'editor';    // 编辑者:可编辑、提交const ROLE_VIEWER = 'viewer';    // 查看者:只读权限// 系统设置const MAX_FILE_SIZE = 10485760;  // 10MBconst ALLOWED_EXTENSIONS = ['doc', 'docx', 'txt', 'pdf', 'md'];}// db.php - 数据库连接与操作class Database {private static $instance = null;private $connection;private function __construct() {try {$this->connection = new PDO("mysql:host=" . Config::DB_HOST . ";dbname=" . Config::DB_NAME,Config::DB_USER,Config::DB_PASS);$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);} catch (PDOException $e) {die("Database connection failed: " . $e->getMessage());}}public static function getInstance() {if (!self::$instance) {self::$instance = new self();}return self::$instance;}public function getConnection() {return $this->connection;}public function query($sql, $params = []) {try {$stmt = $this->connection->prepare($sql);$stmt->execute($params);return $stmt;} catch (PDOException $e) {die("Query failed: " . $e->getMessage());}}public function insert($table, $data) {$columns = implode(', ', array_keys($data));$placeholders = implode(', ', array_fill(0, count($data), '?'));$sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";$this->query($sql, array_values($data));return $this->connection->lastInsertId();}public function update($table, $data, $where, $whereParams = []) {$setParts = [];foreach ($data as $key => $value) {$setParts[] = "$key = ?";}$setClause = implode(', ', $setParts);$sql = "UPDATE $table SET $setClause WHERE $where";$params = array_merge(array_values($data), $whereParams);$this->query($sql, $params);return $this->connection->rowCount();}public function delete($table, $where, $params = []) {$sql = "DELETE FROM $table WHERE $where";$this->query($sql, $params);return $this->connection->rowCount();}public function select($table, $where = '', $params = [], $columns = '*') {$sql = "SELECT $columns FROM $table";if ($where) {$sql .= " WHERE $where";}return $this->query($sql, $params)->fetchAll(PDO::FETCH_ASSOC);}public function selectOne($table, $where = '', $params = [], $columns = '*') {$sql = "SELECT $columns FROM $table";if ($where) {$sql .= " WHERE $where";}$result = $this->query($sql, $params)->fetch(PDO::FETCH_ASSOC);return $result ?: null;}}// auth.php - 用户认证与权限管理class Auth {private $db;private $user = null;public function __construct() {$this->db = Database::getInstance();session_start();if (isset($_SESSION['user_id'])) {$this->user = $this->db->selectOne('users', 'id = ?', [$_SESSION['user_id']]);}}public function login($username, $password) {$user = $this->db->selectOne('users', 'username = ?', [$username]);if ($user && password_verify($password, $user['password'])) {$_SESSION['user_id'] = $user['id'];$this->user = $user;return true;}return false;}public function logout() {session_destroy();$this->user = null;}public function register($username, $email, $password, $role = Config::ROLE_VIEWER) {// 检查用户名是否已存在if ($this->db->selectOne('users', 'username = ?', [$username])) {throw new Exception("Username already exists");}// 检查邮箱是否已存在if ($this->db->selectOne('users', 'email = ?', [$email])) {throw new Exception("Email already exists");}$hashedPassword = password_hash($password, PASSWORD_DEFAULT);return $this->db->insert('users', ['username' => $username,'email' => $email,'password' => $hashedPassword,'role' => $role,'created_at' => date('Y-m-d H:i:s')]);}public function isLoggedIn() {return $this->user !== null;}public function getUser() {return $this->user;}public function hasPermission($permission, $documentId = null) {if (!$this->isLoggedIn()) {return false;}// 管理员拥有所有权限if ($this->user['role'] === Config::ROLE_ADMIN) {return true;}// 检查文档特定权限if ($documentId) {$docPermission = $this->db->selectOne('document_permissions','document_id = ? AND user_id = ?',[$documentId, $this->user['id']]);if ($docPermission) {return $docPermission['permission'] === $permission;}}// 默认权限检查switch ($permission) {case 'read':return in_array($this->user['role'], [Config::ROLE_EDITOR, Config::ROLE_VIEWER]);case 'write':return $this->user['role'] === Config::ROLE_EDITOR;case 'admin':return false;default:return false;}}public function requireLogin() {if (!$this->isLoggedIn()) {header('Location: login.php');exit;}}public function requirePermission($permission, $documentId = null) {$this->requireLogin();if (!$this->hasPermission($permission, $documentId)) {http_response_code(403);die("You don't have permission to perform this action");}}}// repository.php - 仓库管理与版本控制class Repository {private $db;private $auth;private $repoPath;public function __construct($auth) {$this->db = Database::getInstance();$this->auth = $auth;$this->repoPath = Config::REPO_PATH;// 确保仓库目录存在if (!file_exists($this->repoPath)) {mkdir($this->repoPath, 0755, true);}}public function createRepository($name, $description = '') {$this->auth->requirePermission('admin');// 检查仓库名称是否已存在if ($this->db->selectOne('repositories', 'name = ?', [$name])) {throw new Exception("Repository already exists");}// 创建数据库记录$repoId = $this->db->insert('repositories', ['name' => $name,'description' => $description,'owner_id' => $this->auth->getUser()['id'],'created_at' => date('Y-m-d H:i:s')]);// 创建仓库目录$repoDir = $this->repoPath . $repoId;if (!mkdir($repoDir, 0755, true)) {throw new Exception("Failed to create repository directory");}// 初始化Git仓库$this->executeGitCommand($repoDir, 'init');$this->executeGitCommand($repoDir, 'config user.name "' . $this->auth->getUser()['username'] . '"');$this->executeGitCommand($repoDir, 'config user.email "' . $this->auth->getUser()['email'] . '"');// 创建初始提交file_put_contents($repoDir . '/README.md', "# $name\n\n$description");$this->executeGitCommand($repoDir, 'add README.md');$this->executeGitCommand($repoDir, 'commit -m "Initial commit"');return $repoId;}public function getRepositories() {$this->auth->requireLogin();$userId = $this->auth->getUser()['id'];// 管理员可以查看所有仓库if ($this->auth->getUser()['role'] === Config::ROLE_ADMIN) {return $this->db->select('repositories');}// 其他用户只能查看有权限的仓库return $this->db->select('repositories r','r.owner_id = ? OR EXISTS (SELECT 1 FROM repository_permissions rp WHERE rp.repository_id = r.id AND rp.user_id = ?)',[$userId, $userId]);}public function getRepository($id) {$this->auth->requirePermission('read', $id);$repo = $this->db->selectOne('repositories', 'id = ?', [$id]);if (!$repo) {throw new Exception("Repository not found");}$repoDir = $this->repoPath . $id;// 获取最新提交信息$latestCommit = $this->executeGitCommand($repoDir, 'log -1 --pretty=format:"%H|%s|%an|%ad" --date=short');if ($latestCommit) {list($hash, $message, $author, $date) = explode('|', $latestCommit);$repo['latest_commit'] = ['hash' => $hash,'message' => $message,'author' => $author,'date' => $date];}// 获取分支列表$branchesOutput = $this->executeGitCommand($repoDir, 'branch -l');$branches = [];if ($branchesOutput) {$lines = explode("\n", trim($branchesOutput));foreach ($lines as $line) {$branch = trim(str_replace('*', '', $line));$branches[] = $branch;}}$repo['branches'] = $branches;return $repo;}public function addDocument($repoId, $file, $message = '') {$this->auth->requirePermission('write', $repoId);// 验证文件if ($file['error'] !== UPLOAD_ERR_OK) {throw new Exception("File upload error");}if ($file['size'] > Config::MAX_FILE_SIZE) {throw new Exception("File too large");}$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));if (!in_array($extension, Config::ALLOWED_EXTENSIONS)) {throw new Exception("File type not allowed");}$repoDir = $this->repoPath . $repoId;$fileName = $file['name'];$filePath = $repoDir . '/' . $fileName;// 移动文件到仓库目录if (!move_uploaded_file($file['tmp_name'], $filePath)) {throw new Exception("Failed to save file");}// 添加到Git并提交$this->executeGitCommand($repoDir, 'add "' . $fileName . '"');$commitMessage = $message ?: "Add document: $fileName";$this->executeGitCommand($repoDir, 'commit -m "' . $commitMessage . '"');// 记录到数据库$commitHash = trim($this->executeGitCommand($repoDir, 'rev-parse HEAD'));$this->db->insert('documents', ['repository_id' => $repoId,'name' => $fileName,'file_path' => $filePath,'commit_hash' => $commitHash,'uploaded_by' => $this->auth->getUser()['id'],'uploaded_at' => date('Y-m-d H:i:s')]);return $commitHash;}public function getDocuments($repoId) {$this->auth->requirePermission('read', $repoId);$repoDir = $this->repoPath . $repoId;// 获取Git中的文件列表$filesOutput = $this->executeGitCommand($repoDir, 'ls-files');$files = [];if ($filesOutput) {$lines = explode("\n", trim($filesOutput));foreach ($lines as $line) {$files[] = ['name' => $line,'path' => $repoDir . '/' . $line];}}return $files;}public function getDocumentHistory($repoId, $fileName) {$this->auth->requirePermission('read', $repoId);$repoDir = $this->repoPath . $repoId;// 获取文件历史记录$historyOutput = $this->executeGitCommand($repoDir, 'log --pretty=format:"%H|%s|%an|%ad" --date=short -- "' . $fileName . '"');$history = [];if ($historyOutput) {$lines = explode("\n", trim($historyOutput));foreach ($lines as $line) {list($hash, $message, $author, $date) = explode('|', $line);$history[] = ['hash' => $hash,'message' => $message,'author' => $author,'date' => $date];}}return $history;}public function getDocumentVersion($repoId, $fileName, $commitHash) {$this->auth->requirePermission('read', $repoId);$repoDir = $this->repoPath . $repoId;// 获取特定版本的文件内容$content = $this->executeGitCommand($repoDir, 'show ' . $commitHash . ':"' . $fileName . '"');return $content;}public function createBranch($repoId, $branchName, $sourceBranch = 'main') {$this->auth->requirePermission('write', $repoId);$repoDir = $this->repoPath . $repoId;// 检查分支是否已存在$branchesOutput = $this->executeGitCommand($repoDir, 'branch -l');if ($branchesOutput && strpos($branchesOutput, $branchName) !== false) {throw new Exception("Branch already exists");}// 创建新分支$this->executeGitCommand($repoDir, 'branch ' . $branchName . ' ' . $sourceBranch);// 记录到数据库$this->db->insert('branches', ['repository_id' => $repoId,'name' => $branchName,'source_branch' => $sourceBranch,'created_by' => $this->auth->getUser()['id'],'created_at' => date('Y-m-d H:i:s')]);return true;}public function mergeBranch($repoId, $sourceBranch, $targetBranch = 'main') {$this->auth->requirePermission('write', $repoId);$repoDir = $this->repoPath . $repoId;// 切换到目标分支$this->executeGitCommand($repoDir, 'checkout ' . $targetBranch);// 合并源分支$mergeOutput = $this->executeGitCommand($repoDir, 'merge ' . $sourceBranch . ' --no-edit');// 记录合并操作$this->db->insert('merges', ['repository_id' => $repoId,'source_branch' => $sourceBranch,'target_branch' => $targetBranch,'merged_by' => $this->auth->getUser()['id'],'merged_at' => date('Y-m-d H:i:s'),'status' => 'success']);return $mergeOutput;}public function getRepositoryStats($repoId) {$this->auth->requirePermission('read', $repoId);$repoDir = $this->repoPath . $repoId;// 获取提交总数$commitCount = trim($this->executeGitCommand($repoDir, 'rev-list --count HEAD'));// 获取分支数量$branchesOutput = $this->executeGitCommand($repoDir, 'branch -l');$branchCount = $branchesOutput ? count(explode("\n", trim($branchesOutput))) : 0;// 获取贡献者数量$contributorsOutput = $this->executeGitCommand($repoDir, 'shortlog -s | cut -c8-');$contributors = [];if ($contributorsOutput) {$lines = explode("\n", trim($contributorsOutput));foreach ($lines as $line) {$contributors[] = trim($line);}}return ['commit_count' => (int)$commitCount,'branch_count' => $branchCount,'contributors' => $contributors];}private function executeGitCommand($repoDir, $command) {$output = [];$returnValue = 0;$fullCommand = "cd $repoDir && git $command 2>&1";exec($fullCommand, $output, $returnValue);if ($returnValue !== 0) {throw new Exception("Git command failed: " . implode("\n", $output));}return implode("\n", $output);}}// install.php - 数据库安装脚本function installDatabase() {$db = Database::getInstance();// 创建用户表$db->query("CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) UNIQUE NOT NULL,email VARCHAR(100) UNIQUE NOT NULL,password VARCHAR(255) NOT NULL,role ENUM('admin', 'editor', 'viewer') NOT NULL DEFAULT 'viewer',created_at DATETIME NOT NULL)");// 创建仓库表$db->query("CREATE TABLE IF NOT EXISTS repositories (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) UNIQUE NOT NULL,description TEXT,owner_id INT NOT NULL,created_at DATETIME NOT NULL,FOREIGN KEY (owner_id) REFERENCES users(id))");// 创建文档表$db->query("CREATE TABLE IF NOT EXISTS documents (id INT AUTO_INCREMENT PRIMARY KEY,repository_id INT NOT NULL,name VARCHAR(255) NOT NULL,file_path VARCHAR(255) NOT NULL,commit_hash VARCHAR(40) NOT NULL,uploaded_by INT NOT NULL,uploaded_at DATETIME NOT NULL,FOREIGN KEY (repository_id) REFERENCES repositories(id),FOREIGN KEY (uploaded_by) REFERENCES users(id))");// 创建分支表$db->query("CREATE TABLE IF NOT EXISTS branches (id INT AUTO_INCREMENT PRIMARY KEY,repository_id INT NOT NULL,name VARCHAR(100) NOT NULL,source_branch VARCHAR(100) NOT NULL,created_by INT NOT NULL,created_at DATETIME NOT NULL,FOREIGN KEY (repository_id) REFERENCES repositories(id),FOREIGN KEY (created_by) REFERENCES users(id),UNIQUE KEY (repository_id, name))");// 创建合并记录表$db->query("CREATE TABLE IF NOT EXISTS merges (id INT AUTO_INCREMENT PRIMARY KEY,repository_id INT NOT NULL,source_branch VARCHAR(100) NOT NULL,target_branch VARCHAR(100) NOT NULL,merged_by INT NOT NULL,merged_at DATETIME NOT NULL,status ENUM('success', 'failed') NOT NULL,FOREIGN KEY (repository_id) REFERENCES repositories(id),FOREIGN KEY (merged_by) REFERENCES users(id))");// 创建仓库权限表$db->query("CREATE TABLE IF NOT EXISTS repository_permissions (id INT AUTO_INCREMENT PRIMARY KEY,repository_id INT NOT NULL,user_id INT NOT NULL,permission ENUM('read', 'write', 'admin') NOT NULL,granted_at DATETIME NOT NULL,FOREIGN KEY (repository_id) REFERENCES repositories(id),FOREIGN KEY (user_id) REFERENCES users(id),UNIQUE KEY (repository_id, user_id))");// 创建默认管理员账户$adminExists = $db->selectOne('users', 'role = ?', [Config::ROLE_ADMIN]);if (!$adminExists) {$db->insert('users', ['username' => 'admin','email' => 'admin@example.com','password' => password_hash('admin123', PASSWORD_DEFAULT),'role' => Config::ROLE_ADMIN,'created_at' => date('Y-m-d H:i:s')]);}return "Database installed successfully!";}// index.php - 主入口文件require_once 'config.php';require_once 'db.php';require_once 'auth.php';require_once 'repository.php';// 初始化$auth = new Auth();$repo = new Repository($auth);// 处理请求$action = $_GET['action'] ?? 'home';try {switch ($action) {case 'home':// 首页if ($auth->isLoggedIn()) {$repositories = $repo->getRepositories();include 'views/dashboard.php';} else {include 'views/home.php';}break;case 'login':// 登录if ($_SERVER['REQUEST_METHOD'] === 'POST') {$username = $_POST['username'] ?? '';$password = $_POST['password'] ?? '';if ($auth->login($username, $password)) {header('Location: index.php');exit;} else {$error = "Invalid username or password";include 'views/login.php';}} else {include 'views/login.php';}break;case 'logout':// 登出$auth->logout();header('Location: index.php');break;case 'register':// 注册if ($_SERVER['REQUEST_METHOD'] === 'POST') {$username = $_POST['username'] ?? '';$email = $_POST['email'] ?? '';$password = $_POST['password'] ?? '';$confirmPassword = $_POST['confirm_password'] ?? '';if ($password !== $confirmPassword) {$error = "Passwords do not match";include 'views/register.php';} else {try {$auth->register($username, $email, $password);$success = "Registration successful. Please login.";include 'views/login.php';} catch (Exception $e) {$error = $e->getMessage();include 'views/register.php';}}} else {include 'views/register.php';}break;case 'create_repo':// 创建仓库$auth->requirePermission('admin');if ($_SERVER['REQUEST_METHOD'] === 'POST') {$name = $_POST['name'] ?? '';$description = $_POST['description'] ?? '';try {$repoId = $repo->createRepository($name, $description);header("Location: index.php?action=repo&id=$repoId");exit;} catch (Exception $e) {$error = $e->getMessage();include 'views/create_repo.php';}} else {include 'views/create_repo.php';}break;case 'repo':// 仓库详情$repoId = $_GET['id'] ?? 0;if (!$repoId) {header('Location: index.php');exit;}$repository = $repo->getRepository($repoId);$documents = $repo->getDocuments($repoId);$stats = $repo->getRepositoryStats($repoId);include 'views/repo.php';break;case 'upload':// 上传文档$repoId = $_GET['id'] ?? 0;if (!$repoId) {header('Location: index.php');exit;}if ($_SERVER['REQUEST_METHOD'] === 'POST') {$message = $_POST['message'] ?? '';try {$repo->addDocument($repoId, $_FILES['file'], $message);header("Location: index.php?action=repo&id=$repoId");exit;} catch (Exception $e) {$error = $e->getMessage();$repository = $repo->getRepository($repoId);include 'views/upload.php';}} else {$repository = $repo->getRepository($repoId);include 'views/upload.php';}break;case 'history':// 文档历史$repoId = $_GET['repo_id'] ?? 0;$fileName = $_GET['file'] ?? '';if (!$repoId || !$fileName) {header('Location: index.php');exit;}$history = $repo->getDocumentHistory($repoId, $fileName);$repository = $repo->getRepository($repoId);include 'views/history.php';break;case 'version':// 文档版本$repoId = $_GET['repo_id'] ?? 0;$fileName = $_GET['file'] ?? '';$commitHash = $_GET['hash'] ?? '';if (!$repoId || !$fileName || !$commitHash) {header('Location: index.php');exit;}$content = $repo->getDocumentVersion($repoId, $fileName, $commitHash);$repository = $repo->getRepository($repoId);include 'views/version.php';break;case 'create_branch':// 创建分支$repoId = $_GET['repo_id'] ?? 0;if (!$repoId) {header('Location: index.php');exit;}if ($_SERVER['REQUEST_METHOD'] === 'POST') {$branchName = $_POST['name'] ?? '';$sourceBranch = $_POST['source'] ?? 'main';try {$repo->createBranch($repoId, $branchName, $sourceBranch);header("Location: index.php?action=repo&id=$repoId");exit;} catch (Exception $e) {$error = $e->getMessage();$repository = $repo->getRepository($repoId);include 'views/create_branch.php';}} else {$repository = $repo->getRepository($repoId);include 'views/create_branch.php';}break;case 'merge_branch':// 合并分支$repoId = $_GET['repo_id'] ?? 0;if (!$repoId) {header('Location: index.php');exit;}if ($_SERVER['REQUEST_METHOD'] === 'POST') {$sourceBranch = $_POST['source'] ?? '';$targetBranch = $_POST['target'] ?? 'main';try {$result = $repo->mergeBranch($repoId, $sourceBranch, $targetBranch);header("Location: index.php?action=repo&id=$repoId");exit;} catch (Exception $e) {$error = $e->getMessage();$repository = $repo->getRepository($repoId);include 'views/merge_branch.php';}} else {$repository = $repo->getRepository($repoId);include 'views/merge_branch.php';}break;case 'install':// 安装数据库echo installDatabase();break;default:// 默认首页include 'views/home.php';break;}} catch (Exception $e) {$error = $e->getMessage();include 'views/error.php';}?>

http://www.xdnf.cn/news/1273249.html

相关文章:

  • 从MySQL到大数据平台:基于Spark的离线分析实战指南
  • 5Python异常处理与模块导入全指南
  • 元数据管理与数据治理平台:Apache Atlas 分类传播 Classification Propagation
  • vue中使用h5plus
  • 【Elasticsearch入门到落地】16、RestClient查询文档-快速入门
  • Java Stream流详解:从基础语法到实战应用
  • spring-ai整合PGVector实现RAG
  • 【代码随想录day 15】 力扣 257. 二叉树的所有路径
  • uni-app 网络请求终极选型:uni.request、axios、uni-network、alova 谁才是你的真命请求库?
  • LeetCode_字符串
  • LeetCode 刷题【37. 解数独】
  • 计算XGBoost分类模型的错误率
  • 网工笔记——BGP协议
  • 解决 Linux 下 “E: 仓库xxx没有数字签名” 问题
  • 编程基础之多维数组——同行列对角线的格
  • scanpy单细胞转录组python教程(四):单样本数据分析之降维聚类及细胞注释
  • (Python)爬虫进阶(Python爬虫教程)(CSS选择器)
  • stm32没有CMSIS文件
  • 【精彩回顾·成都】成都 User Group×柴火创客空间:开源硬件驱动 AI 与云的创新实践!
  • vue和react和uniapp的状态管理分别是什么,并且介绍和怎么使用
  • Day38--动态规划--322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结
  • 如何理解SA_RESTART”被信号中断的系统调用自动重启“?
  • Vue3 组件化开发
  • 人工智能技术发展历史演变
  • Filter,Interceptor拦截器-登录校验
  • 关于城市农村创业的一点构想
  • RecyclerView 缓存机制
  • 堆----3.数据流的中位数
  • Slab 算法浅析
  • HTML全景效果实现