commit ec563fc407f4a62bc4b975ff7af7d1783855ee97
Author: Tsama <1693710928@qq.com>
Date: Sat Nov 15 17:37:48 2025 +0800
初始提交
diff --git a/.git_remote_config.json b/.git_remote_config.json
new file mode 100644
index 0000000..585fd03
--- /dev/null
+++ b/.git_remote_config.json
@@ -0,0 +1,5 @@
+{
+ "remotes": {
+ "origin": "https:\/\/git.tsama.cn\/ll\/Demo1.git"
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..25f455c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,217 @@
+# Git文件上传工具
+
+一个基于PHP的Git文件上传工具,支持JS和CSS分离,文件上传无限制。
+
+## 功能特点
+
+- ✅ **文件上传无限制**:支持任意大小和数量的文件上传
+- ✅ **Git集成**:完整的Git操作支持(添加、提交、推送、状态查看)
+- ✅ **分支管理**:支持创建、删除、切换分支
+- ✅ **远程仓库配置**:支持添加和管理多个远程仓库
+- ✅ **前后端分离**:独立的CSS和JavaScript文件
+- ✅ **拖拽上传**:支持拖拽文件上传
+- ✅ **文件管理**:可视化的文件列表和选择
+- ✅ **实时状态**:Git仓库状态实时显示
+- ✅ **响应式设计**:适配移动端和桌面端
+
+## 文件结构
+
+```
+git/
+├── index.php # 主文件(包含PHP后端逻辑和HTML结构)
+├── css/
+│ └── style.css # 样式文件
+├── js/
+│ └── main.js # JavaScript交互逻辑
+├── test.php # 测试文件
+└── uploads/ # 上传文件存储目录(自动生成)
+```
+
+## 安装要求
+
+- PHP 7.0 或更高版本
+- Git 已安装并配置
+- Web服务器(Apache/Nginx等)
+- 足够的磁盘空间
+
+## 安装步骤
+
+1. **上传文件到Web服务器**
+ ```bash
+ # 将整个 git 目录上传到Web服务器目录
+ # 例如:/var/www/html/git/
+ ```
+
+2. **设置目录权限**
+ ```bash
+ chmod 755 /var/www/html/git/
+ chmod 777 /var/www/html/git/uploads/
+ ```
+
+3. **访问工具**
+ ```
+ http://your-domain.com/git/
+ ```
+
+## 使用方法
+
+### 1. 文件上传
+
+- **拖拽上传**:将文件拖拽到上传区域
+- **点击上传**:点击上传区域选择文件
+- **批量上传**:支持同时选择多个文件
+
+### 2. 分支管理
+
+- **查看分支**:分支列表会自动加载,显示当前分支和其他分支
+- **创建新分支**:
+ 1. 在"新分支名称"输入框中输入分支名称
+ 2. 点击"创建分支"按钮
+ 3. 新分支将基于当前分支创建
+
+- **切换分支**:
+ 1. 在"当前分支"下拉框中选择目标分支
+ 2. 点击"切换分支"按钮
+ 3. 工具会自动切换到选中的分支
+
+- **删除分支**:
+ 1. 在"当前分支"下拉框中选择要删除的分支
+ 2. 点击"删除分支"按钮
+ 3. 确认删除操作(如果分支未合并,可选择强制删除)
+
+- **刷新分支**:点击"刷新分支"按钮更新分支列表
+
+### 3. 远程仓库配置
+
+- **添加远程仓库**:
+ 1. 在"远程仓库名称"输入框中输入名称(如:origin)
+ 2. 在"仓库地址"输入框中输入远程仓库URL(如:https://github.com/username/repo.git)
+ 3. 点击"添加远程仓库"按钮
+
+- **查看远程仓库**:点击"查看远程仓库"按钮查看已配置的远程仓库列表
+
+### 4. Git操作
+
+- **添加到暂存区**:选择文件后点击"添加到暂存区"
+- **提交更改**:输入提交信息后点击"提交更改"
+- **推送到远程**:
+ 1. 确保已配置远程仓库
+ 2. 选择要推送的分支(在分支管理区域)
+ 3. 在"远程仓库名称"输入框中输入要推送的远程仓库名称
+ 4. 点击"推送到远程"按钮
+- **查看状态**:点击"查看状态"查看Git状态
+- **查看日志**:点击"查看日志"查看提交历史
+
+### 5. 文件管理
+
+- **刷新列表**:点击"刷新文件列表"更新文件列表
+- **选择文件**:勾选需要Git管理的文件
+- **全选/取消**:快速选择或取消所有文件
+
+## 配置说明
+
+### PHP配置
+
+工具会自动配置以下PHP设置:
+```php
+ini_set('upload_max_filesize', '0'); // 无上传大小限制
+ini_set('post_max_size', '0'); // 无POST大小限制
+ini_set('max_execution_time', '0'); // 无执行时间限制
+ini_set('memory_limit', '-1'); // 无内存限制
+```
+
+### Git配置
+
+确保Web服务器用户有权限执行Git命令:
+```bash
+# 检查Git是否可用
+sudo -u www-data git --version
+
+# 如果需要,配置Git用户信息
+sudo -u www-data git config --global user.name "Web Server"
+sudo -u www-data git config --global user.email "web@example.com"
+```
+
+## 安全建议
+
+1. **访问控制**:建议添加密码保护或IP限制
+2. **文件类型限制**:根据需要限制上传文件类型
+3. **定期清理**:定期清理上传目录
+4. **备份重要数据**:重要文件请做好备份
+
+## 故障排除
+
+### 常见问题
+
+1. **文件上传失败**
+ - 检查 `uploads/` 目录权限
+ - 确认PHP配置允许大文件上传
+ - 查看Web服务器错误日志
+
+2. **Git操作失败**
+ - 确认Git已安装
+ - 检查Web服务器用户对Git的访问权限
+ - 确认Git仓库已初始化
+
+3. **分支管理问题**
+ - 无法删除当前分支,请先切换到其他分支
+ - 分支未合并时删除需要强制删除
+ - 分支名称不能包含特殊字符
+
+4. **远程仓库配置问题**
+ - 确保远程仓库URL格式正确
+ - 检查网络连接是否正常
+ - 确认有权限访问远程仓库
+ - 如需要认证,请配置Git凭据
+
+5. **推送失败**
+ - 确认远程仓库已正确添加
+ - 检查是否有冲突需要解决
+ - 确认有推送权限
+ - 确认选择了正确的分支进行推送
+
+6. **界面显示异常**
+ - 检查CSS文件是否正确加载
+ - 确认JavaScript文件无错误
+ - 清除浏览器缓存
+
+### 运行测试
+
+访问测试文件检查配置:
+```
+http://your-domain.com/git/test.php
+```
+
+## 更新日志
+
+### v1.2.0 (2024-01-15)
+- 添加分支管理功能
+- 支持创建、删除、切换分支
+- 支持分支选择和推送
+- 优化分支操作的用户体验
+
+### v1.1.0 (2024-01-15)
+- 添加远程仓库配置功能
+- 支持添加和管理远程仓库
+- 支持推送到指定远程仓库
+- 优化推送操作的用户体验
+
+### v1.0.0 (2024-01-15)
+- 初始版本发布
+- 支持文件上传和Git操作
+- 实现前后端分离
+- 添加拖拽上传功能
+
+## 许可证
+
+MIT License - 详见LICENSE文件
+
+## 作者
+
+Git文件上传工具开发团队
+
+## 支持
+
+如有问题,请通过以下方式联系:
+- 邮箱:support@example.com
+- 项目主页:https://github.com/your-repo/git-uploader
\ No newline at end of file
diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000..038bce8
--- /dev/null
+++ b/css/style.css
@@ -0,0 +1,478 @@
+/* Git文件上传工具样式 */
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ line-height: 1.6;
+ color: #333;
+ background-color: #f5f5f5;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+/* 头部样式 */
+header {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+header h1 {
+ color: #2c3e50;
+ font-size: 24px;
+}
+
+.git-status {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.status-indicator {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background-color: #e74c3c;
+ transition: background-color 0.3s;
+}
+
+.status-indicator.active {
+ background-color: #27ae60;
+}
+
+/* 主要内容区域 */
+main {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+}
+
+section {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+}
+
+section h2 {
+ color: #2c3e50;
+ margin-bottom: 15px;
+ font-size: 18px;
+}
+
+/* 上传区域样式 */
+.upload-section {
+ grid-column: 1 / -1;
+}
+
+.upload-area {
+ border: 2px dashed #3498db;
+ border-radius: 8px;
+ padding: 40px;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.3s;
+ background-color: #f8f9fa;
+}
+
+.upload-area:hover {
+ border-color: #2980b9;
+ background-color: #e3f2fd;
+}
+
+.upload-area.dragover {
+ border-color: #27ae60;
+ background-color: #e8f5e8;
+}
+
+.upload-placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+}
+
+.upload-icon {
+ width: 48px;
+ height: 48px;
+ color: #3498db;
+}
+
+.upload-hint {
+ font-size: 12px;
+ color: #7f8c8d;
+}
+
+.uploaded-files {
+ margin-top: 15px;
+}
+
+.file-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 12px;
+ background-color: #e8f5e8;
+ border-radius: 4px;
+ margin-bottom: 5px;
+}
+
+.file-item.success {
+ background-color: #d4edda;
+ border-left: 4px solid #27ae60;
+}
+
+.file-item.error {
+ background-color: #f8d7da;
+ border-left: 4px solid #e74c3c;
+}
+
+/* 文件列表样式 */
+.files-section {
+ max-height: 500px;
+ overflow-y: auto;
+}
+
+.file-controls {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 15px;
+}
+
+.file-list {
+ border: 1px solid #e0e0e0;
+ border-radius: 4px;
+ max-height: 400px;
+ overflow-y: auto;
+}
+
+.file-checkbox {
+ display: flex;
+ align-items: center;
+ padding: 8px 12px;
+ border-bottom: 1px solid #f0f0f0;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.file-checkbox:hover {
+ background-color: #f8f9fa;
+}
+
+.file-checkbox:last-child {
+ border-bottom: none;
+}
+
+.file-checkbox input[type="checkbox"] {
+ margin-right: 10px;
+}
+
+.file-path {
+ font-family: 'Courier New', monospace;
+ font-size: 14px;
+ color: #495057;
+}
+
+/* Git操作区域样式 */
+.git-section {
+ max-height: 500px;
+ overflow-y: auto;
+}
+
+.form-group {
+ margin-bottom: 15px;
+}
+
+.form-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: 500;
+ color: #495057;
+}
+
+.form-group input {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ced4da;
+ border-radius: 4px;
+ font-size: 14px;
+}
+
+.form-group input:focus {
+ outline: none;
+ border-color: #3498db;
+ box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
+}
+
+.button-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 15px;
+}
+
+/* 按钮样式 */
+.btn {
+ padding: 8px 16px;
+ border: none;
+ border-radius: 4px;
+ font-size: 14px;
+ cursor: pointer;
+ transition: all 0.3s;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.btn:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+}
+
+.btn:active {
+ transform: translateY(0);
+}
+
+.btn-primary {
+ background-color: #3498db;
+ color: white;
+}
+
+.btn-primary:hover {
+ background-color: #2980b9;
+}
+
+.btn-success {
+ background-color: #27ae60;
+ color: white;
+}
+
+.btn-success:hover {
+ background-color: #229954;
+}
+
+.btn-warning {
+ background-color: #f39c12;
+ color: white;
+}
+
+.btn-warning:hover {
+ background-color: #e67e22;
+}
+
+.btn-info {
+ background-color: #17a2b8;
+ color: white;
+}
+
+.btn-info:hover {
+ background-color: #138496;
+}
+
+.btn-secondary {
+ background-color: #6c757d;
+ color: white;
+}
+
+.btn-secondary:hover {
+ background-color: #5a6268;
+}
+
+.btn-danger {
+ background-color: #e74c3c;
+ color: white;
+}
+
+.btn-danger:hover {
+ background-color: #c0392b;
+}
+
+.btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none;
+}
+
+/* 分支管理 */
+.branch-config {
+ background-color: #f8f9fa;
+ border: 1px solid #e9ecef;
+ border-radius: 4px;
+ padding: 15px;
+ margin-bottom: 20px;
+}
+
+.branch-config h3 {
+ color: #495057;
+ margin-bottom: 15px;
+ font-size: 16px;
+}
+
+.form-control {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ced4da;
+ border-radius: 4px;
+ font-size: 14px;
+ background-color: white;
+}
+
+.form-control:focus {
+ outline: none;
+ border-color: #3498db;
+ box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
+}
+
+/* 远程仓库配置 */
+.remote-config {
+ background-color: #f8f9fa;
+ border: 1px solid #e9ecef;
+ border-radius: 4px;
+ padding: 15px;
+ margin-bottom: 20px;
+}
+
+.remote-config h3 {
+ color: #495057;
+ margin-bottom: 15px;
+ font-size: 16px;
+}
+
+.remote-list {
+ margin-top: 15px;
+ max-height: 150px;
+ overflow-y: auto;
+}
+
+.remote-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 12px;
+ background-color: white;
+ border: 1px solid #dee2e6;
+ border-radius: 4px;
+ margin-bottom: 8px;
+}
+
+.remote-item:last-child {
+ margin-bottom: 0;
+}
+
+.remote-name {
+ font-weight: 500;
+ color: #495057;
+}
+
+.remote-url {
+ font-size: 12px;
+ color: #6c757d;
+ font-family: 'Courier New', monospace;
+ word-break: break-all;
+}
+
+/* Git输出区域 */
+.git-output {
+ background-color: #f8f9fa;
+ border: 1px solid #e9ecef;
+ border-radius: 4px;
+ padding: 12px;
+ font-family: 'Courier New', monospace;
+ font-size: 13px;
+ max-height: 200px;
+ overflow-y: auto;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.git-output:empty::before {
+ content: "Git操作输出将显示在这里...";
+ color: #6c757d;
+ font-style: italic;
+}
+
+/* 加载状态 */
+.loading {
+ text-align: center;
+ padding: 20px;
+ color: #6c757d;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+ main {
+ grid-template-columns: 1fr;
+ }
+
+ header {
+ flex-direction: column;
+ gap: 15px;
+ text-align: center;
+ }
+
+ .button-group {
+ justify-content: center;
+ }
+
+ .file-controls {
+ flex-wrap: wrap;
+ justify-content: center;
+ }
+}
+
+/* 动画效果 */
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.fade-in {
+ animation: fadeIn 0.3s ease-out;
+}
+
+/* 错误和成功消息 */
+.message {
+ padding: 12px;
+ border-radius: 4px;
+ margin-bottom: 15px;
+ font-size: 14px;
+}
+
+.message.success {
+ background-color: #d4edda;
+ color: #155724;
+ border: 1px solid #c3e6cb;
+}
+
+.message.error {
+ background-color: #f8d7da;
+ color: #721c24;
+ border: 1px solid #f5c6cb;
+}
+
+.message.info {
+ background-color: #d1ecf1;
+ color: #0c5460;
+ border: 1px solid #bee5eb;
+}
\ No newline at end of file
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..0660089
--- /dev/null
+++ b/index.php
@@ -0,0 +1,511 @@
+isFile() && !strpos($file->getPathname(), '.git')) {
+ $relativePath = str_replace('\\', '/', substr($file->getPathname(), strlen(__DIR__) + 1));
+ $files[] = $relativePath;
+ }
+ }
+
+ return $files;
+}
+
+// 处理文件上传
+function handleFileUpload($files) {
+ $uploadedFiles = [];
+
+ if (!isset($files['files']) || empty($files['files']['name'][0])) {
+ return ['success' => false, 'message' => '没有选择文件'];
+ }
+
+ $uploadDir = __DIR__ . '/uploads/';
+ if (!is_dir($uploadDir)) {
+ mkdir($uploadDir, 0777, true);
+ }
+
+ $fileCount = count($files['files']['name']);
+
+ for ($i = 0; $i < $fileCount; $i++) {
+ if ($files['files']['error'][$i] === UPLOAD_ERR_OK) {
+ $tmpName = $files['files']['tmp_name'][$i];
+ $fileName = basename($files['files']['name'][$i]);
+ $uploadPath = $uploadDir . $fileName;
+
+ // 移动上传的文件
+ if (move_uploaded_file($tmpName, $uploadPath)) {
+ $uploadedFiles[] = $fileName;
+ }
+ }
+ }
+
+ return ['success' => true, 'files' => $uploadedFiles];
+}
+
+// 获取远程仓库配置
+function getRemoteConfig() {
+ global $remoteConfigFile;
+
+ if (file_exists($remoteConfigFile)) {
+ $config = json_decode(file_get_contents($remoteConfigFile), true);
+ return $config ?: ['remotes' => []];
+ }
+
+ return ['remotes' => []];
+}
+
+// 保存远程仓库配置
+function saveRemoteConfig($config) {
+ global $remoteConfigFile;
+
+ return file_put_contents($remoteConfigFile, json_encode($config, JSON_PRETTY_PRINT));
+}
+
+// 添加远程仓库
+function addRemote($name, $url) {
+ global $currentDir;
+
+ try {
+ exec('cd "' . $currentDir . '" && git remote add ' . escapeshellarg($name) . ' ' . escapeshellarg($url), $output, $returnCode);
+
+ if ($returnCode === 0) {
+ // 保存到配置文件
+ $config = getRemoteConfig();
+ $config['remotes'][$name] = $url;
+ saveRemoteConfig($config);
+ return ['success' => true, 'message' => '远程仓库添加成功'];
+ } else {
+ return ['success' => false, 'message' => '远程仓库添加失败'];
+ }
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 获取远程仓库列表
+function getRemotes() {
+ global $currentDir;
+
+ try {
+ exec('cd "' . $currentDir . '" && git remote -v', $output, $returnCode);
+
+ $remotes = [];
+ foreach ($output as $line) {
+ if (preg_match('/^(\S+)\s+(\S+)\s+\((\w+)\)/', $line, $matches)) {
+ $remotes[$matches[1]] = [
+ 'url' => $matches[2],
+ 'type' => $matches[3]
+ ];
+ }
+ }
+
+ return ['success' => true, 'remotes' => $remotes];
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 推送代码到指定远程仓库
+function pushToRemote($remote = 'origin', $branch = 'main') {
+ global $currentDir;
+
+ try {
+ exec('cd "' . $currentDir . '" && git push ' . escapeshellarg($remote) . ' ' . escapeshellarg($branch), $output, $returnCode);
+
+ return ['success' => $returnCode === 0, 'output' => $output];
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 获取分支列表
+function getBranches() {
+ global $currentDir;
+
+ try {
+ $output = [];
+ $returnCode = 0;
+
+ // 获取本地分支
+ exec('cd "' . $currentDir . '" && git branch -a', $output, $returnCode);
+
+ $branches = [];
+ $currentBranch = '';
+
+ foreach ($output as $line) {
+ $line = trim($line);
+ if (empty($line)) continue;
+
+ // 检查是否是当前分支
+ if (strpos($line, '*') === 0) {
+ $currentBranch = trim(substr($line, 1));
+ $branches[] = [
+ 'name' => $currentBranch,
+ 'current' => true,
+ 'remote' => false
+ ];
+ } else {
+ // 检查是否是远程分支
+ $isRemote = strpos($line, 'remotes/') !== false;
+ $branchName = $isRemote ? substr($line, strpos($line, 'remotes/') + 8) : $line;
+
+ $branches[] = [
+ 'name' => trim($branchName),
+ 'current' => false,
+ 'remote' => $isRemote
+ ];
+ }
+ }
+
+ return ['success' => true, 'branches' => $branches, 'current' => $currentBranch];
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 创建新分支
+function createBranch($branchName) {
+ global $currentDir;
+
+ try {
+ exec('cd "' . $currentDir . '" && git checkout -b ' . escapeshellarg($branchName), $output, $returnCode);
+
+ if ($returnCode === 0) {
+ return ['success' => true, 'message' => '分支创建成功', 'output' => $output];
+ } else {
+ return ['success' => false, 'message' => '分支创建失败', 'output' => $output];
+ }
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 删除分支
+function deleteBranch($branchName, $force = false) {
+ global $currentDir;
+
+ try {
+ $forceFlag = $force ? '-D' : '-d';
+ exec('cd "' . $currentDir . '" && git branch ' . $forceFlag . ' ' . escapeshellarg($branchName), $output, $returnCode);
+
+ if ($returnCode === 0) {
+ return ['success' => true, 'message' => '分支删除成功', 'output' => $output];
+ } else {
+ return ['success' => false, 'message' => '分支删除失败', 'output' => $output];
+ }
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 切换分支
+function switchBranch($branchName) {
+ global $currentDir;
+
+ try {
+ exec('cd "' . $currentDir . '" && git checkout ' . escapeshellarg($branchName), $output, $returnCode);
+
+ if ($returnCode === 0) {
+ return ['success' => true, 'message' => '分支切换成功', 'output' => $output];
+ } else {
+ return ['success' => false, 'message' => '分支切换失败', 'output' => $output];
+ }
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 处理Git操作
+function handleGitOperation($operation, $message = '', $files = [], $remote = 'origin', $branch = 'main') {
+ global $currentDir;
+
+ try {
+ $output = [];
+ $returnCode = 0;
+
+ switch ($operation) {
+ case 'status':
+ exec('cd "' . $currentDir . '" && git status --porcelain', $output, $returnCode);
+ break;
+
+ case 'add':
+ if (!empty($files)) {
+ foreach ($files as $file) {
+ exec('cd "' . $currentDir . '" && git add "' . $file . '"', $output, $returnCode);
+ }
+ } else {
+ exec('cd "' . $currentDir . '" && git add .', $output, $returnCode);
+ }
+ break;
+
+ case 'commit':
+ if (empty($message)) {
+ $message = '自动提交';
+ }
+ exec('cd "' . $currentDir . '" && git commit -m "' . addslashes($message) . '"', $output, $returnCode);
+ break;
+
+ case 'push':
+ // 使用新的推送函数,支持指定远程仓库和分支
+ return pushToRemote($remote, $branch);
+
+ case 'log':
+ exec('cd "' . $currentDir . '" && git log --oneline -10', $output, $returnCode);
+ break;
+ }
+
+ return ['success' => $returnCode === 0, 'output' => $output];
+ } catch (Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+}
+
+// 处理AJAX请求
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ header('Content-Type: application/json; charset=utf-8');
+
+ $action = $_POST['action'] ?? '';
+
+ switch ($action) {
+ case 'upload':
+ $result = handleFileUpload($_FILES);
+ echo json_encode($result);
+ break;
+
+ case 'git_operation':
+ $operation = $_POST['operation'] ?? '';
+ $message = $_POST['message'] ?? '';
+ $files = $_POST['files'] ?? [];
+ $remote = $_POST['remote'] ?? 'origin';
+ $branch = $_POST['branch'] ?? 'main';
+ $result = handleGitOperation($operation, $message, $files, $remote, $branch);
+ echo json_encode($result);
+ break;
+
+ case 'add_remote':
+ $name = $_POST['name'] ?? '';
+ $url = $_POST['url'] ?? '';
+ if (empty($name) || empty($url)) {
+ echo json_encode(['success' => false, 'message' => '远程仓库名称和地址不能为空']);
+ } else {
+ $result = addRemote($name, $url);
+ echo json_encode($result);
+ }
+ break;
+
+ case 'get_remotes':
+ $result = getRemotes();
+ echo json_encode($result);
+ break;
+
+ case 'get_branches':
+ $result = getBranches();
+ echo json_encode($result);
+ break;
+
+ case 'create_branch':
+ $branchName = $_POST['branch_name'] ?? '';
+ if (empty($branchName)) {
+ echo json_encode(['success' => false, 'message' => '分支名称不能为空']);
+ } else {
+ $result = createBranch($branchName);
+ echo json_encode($result);
+ }
+ break;
+
+ case 'delete_branch':
+ $branchName = $_POST['branch_name'] ?? '';
+ $force = isset($_POST['force']) && $_POST['force'] === 'true';
+ if (empty($branchName)) {
+ echo json_encode(['success' => false, 'message' => '分支名称不能为空']);
+ } else {
+ $result = deleteBranch($branchName, $force);
+ echo json_encode($result);
+ }
+ break;
+
+ case 'switch_branch':
+ $branchName = $_POST['branch_name'] ?? '';
+ if (empty($branchName)) {
+ echo json_encode(['success' => false, 'message' => '分支名称不能为空']);
+ } else {
+ $result = switchBranch($branchName);
+ echo json_encode($result);
+ }
+ break;
+
+ case 'get_files':
+ $files = getFileList();
+ echo json_encode(['success' => true, 'files' => $files]);
+ break;
+
+ case 'check_git':
+ echo json_encode(['success' => true, 'hasGit' => checkGitRepo()]);
+ break;
+
+ case 'init_git':
+ $success = initGitRepo();
+ echo json_encode(['success' => $success]);
+ break;
+
+ default:
+ echo json_encode(['success' => false, 'message' => '未知操作']);
+ }
+ exit;
+}
+
+?>
+
+
+
+
+
+ Git文件上传工具
+
+
+
+
+
+ Git文件上传工具
+
+
+ 检查Git状态...
+
+
+
+
+
+
+ 文件上传
+
+
+
+
拖拽文件到此处或点击选择文件
+
支持任意大小的文件,无数量限制
+
+
+
+
+
+
+
+
+ 项目文件
+
+
+
+
+
+
+
+
+
+
+ Git操作
+
+
+
+
分支管理
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
远程仓库配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/js/main.js b/js/main.js
new file mode 100644
index 0000000..e909a31
--- /dev/null
+++ b/js/main.js
@@ -0,0 +1,593 @@
+/**
+ * Git文件上传工具 - 主要JavaScript功能
+ * 支持文件上传、Git操作、文件管理等功能
+ */
+
+class GitUploader {
+ constructor() {
+ this.selectedFiles = new Set();
+ this.init();
+ }
+
+ // 初始化
+ init() {
+ this.setupEventListeners();
+ this.checkGitStatus();
+ this.loadFileList();
+ this.showRemotes(); // 加载远程仓库列表
+ this.loadBranches(); // 加载分支列表
+ }
+
+ // 设置事件监听器
+ setupEventListeners() {
+ // 文件上传相关
+ const uploadArea = document.getElementById('uploadArea');
+ const fileInput = document.getElementById('fileInput');
+
+ uploadArea.addEventListener('click', () => fileInput.click());
+ uploadArea.addEventListener('dragover', this.handleDragOver.bind(this));
+ uploadArea.addEventListener('dragleave', this.handleDragLeave.bind(this));
+ uploadArea.addEventListener('drop', this.handleDrop.bind(this));
+ fileInput.addEventListener('change', this.handleFileSelect.bind(this));
+
+ // Git操作相关
+ document.getElementById('gitAdd').addEventListener('click', () => this.gitOperation('add'));
+ document.getElementById('gitCommit').addEventListener('click', () => this.gitOperation('commit'));
+ document.getElementById('gitPush').addEventListener('click', () => this.gitOperation('push'));
+ document.getElementById('gitStatusBtn').addEventListener('click', () => this.gitOperation('status'));
+ document.getElementById('gitLog').addEventListener('click', () => this.gitOperation('log'));
+
+ // 远程仓库相关
+ document.getElementById('addRemote').addEventListener('click', () => this.addRemote());
+ document.getElementById('showRemotes').addEventListener('click', () => this.showRemotes());
+
+ // 分支管理相关
+ document.getElementById('createBranch').addEventListener('click', () => this.createBranch());
+ document.getElementById('switchBranch').addEventListener('click', () => this.switchBranch());
+ document.getElementById('deleteBranch').addEventListener('click', () => this.deleteBranch());
+ document.getElementById('refreshBranches').addEventListener('click', () => this.loadBranches());
+
+ // 文件列表相关
+ document.getElementById('refreshFiles').addEventListener('click', () => this.loadFileList());
+ document.getElementById('selectAllFiles').addEventListener('click', () => this.selectAllFiles());
+ document.getElementById('deselectAllFiles').addEventListener('click', () => this.deselectAllFiles());
+ }
+
+ // 拖拽处理
+ handleDragOver(e) {
+ e.preventDefault();
+ document.getElementById('uploadArea').classList.add('dragover');
+ }
+
+ handleDragLeave(e) {
+ e.preventDefault();
+ document.getElementById('uploadArea').classList.remove('dragover');
+ }
+
+ handleDrop(e) {
+ e.preventDefault();
+ document.getElementById('uploadArea').classList.remove('dragover');
+
+ const files = Array.from(e.dataTransfer.files);
+ this.uploadFiles(files);
+ }
+
+ handleFileSelect(e) {
+ const files = Array.from(e.target.files);
+ this.uploadFiles(files);
+ }
+
+ // 文件上传
+ async uploadFiles(files) {
+ if (files.length === 0) return;
+
+ const formData = new FormData();
+ formData.append('action', 'upload');
+
+ files.forEach(file => {
+ formData.append('files[]', file);
+ });
+
+ try {
+ this.showMessage('正在上传文件...', 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ body: formData
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage(`成功上传 ${result.files.length} 个文件`, 'success');
+ this.displayUploadedFiles(result.files);
+ this.loadFileList(); // 重新加载文件列表
+ } else {
+ this.showMessage(result.message || '上传失败', 'error');
+ }
+ } catch (error) {
+ this.showMessage('上传出错: ' + error.message, 'error');
+ }
+ }
+
+ // 显示已上传的文件
+ displayUploadedFiles(files) {
+ const container = document.getElementById('uploadedFiles');
+ container.innerHTML = '';
+
+ files.forEach(file => {
+ const fileItem = document.createElement('div');
+ fileItem.className = 'file-item success fade-in';
+ fileItem.innerHTML = `
+ ${file}
+ ✓
+ `;
+ container.appendChild(fileItem);
+ });
+ }
+
+ // 检查Git状态
+ async checkGitStatus() {
+ try {
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: 'action=check_git'
+ });
+
+ const result = await response.json();
+ const indicator = document.getElementById('gitIndicator');
+ const statusText = document.getElementById('gitStatusText');
+
+ if (result.success && result.hasGit) {
+ indicator.classList.add('active');
+ statusText.textContent = 'Git仓库已初始化';
+ } else {
+ indicator.classList.remove('active');
+ statusText.textContent = 'Git仓库未初始化';
+
+ // 自动初始化Git仓库
+ if (confirm('Git仓库未初始化,是否现在初始化?')) {
+ await this.initGitRepo();
+ }
+ }
+ } catch (error) {
+ this.showMessage('检查Git状态失败: ' + error.message, 'error');
+ }
+ }
+
+ // 初始化Git仓库
+ async initGitRepo() {
+ try {
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: 'action=init_git'
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage('Git仓库初始化成功', 'success');
+ this.checkGitStatus(); // 重新检查状态
+ } else {
+ this.showMessage('Git仓库初始化失败', 'error');
+ }
+ } catch (error) {
+ this.showMessage('初始化Git仓库失败: ' + error.message, 'error');
+ }
+ }
+
+ // Git操作
+ async gitOperation(operation) {
+ const commitMessage = document.getElementById('commitMessage').value || '自动提交';
+ const selectedFiles = Array.from(this.selectedFiles);
+ const remoteName = document.getElementById('remoteName').value || 'origin';
+ const branchSelect = document.getElementById('branchSelect');
+ const currentBranch = branchSelect ? branchSelect.value : 'main';
+
+ const params = new URLSearchParams();
+ params.append('action', 'git_operation');
+ params.append('operation', operation);
+
+ if (operation === 'commit') {
+ params.append('message', commitMessage);
+ }
+
+ if (operation === 'push') {
+ params.append('remote', remoteName);
+ params.append('branch', currentBranch); // 使用当前选择的分支
+ }
+
+ if (operation === 'add' && selectedFiles.length > 0) {
+ selectedFiles.forEach(file => {
+ params.append('files[]', file);
+ });
+ }
+
+ try {
+ this.showMessage(`正在执行 Git ${operation}...`, 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage(`Git ${operation} 执行成功`, 'success');
+ this.displayGitOutput(result.output);
+
+ if (operation === 'add' || operation === 'commit') {
+ this.loadFileList(); // 重新加载文件列表
+ }
+ } else {
+ this.showMessage(`Git ${operation} 执行失败: ${result.message || '未知错误'}`, 'error');
+ this.displayGitOutput(result.output || []);
+ }
+ } catch (error) {
+ this.showMessage(`Git ${operation} 执行出错: ${error.message}`, 'error');
+ }
+ }
+
+ // 显示Git输出
+ displayGitOutput(output) {
+ const outputElement = document.getElementById('gitOutput');
+
+ if (output && output.length > 0) {
+ outputElement.textContent = output.join('\n');
+ } else {
+ outputElement.textContent = '暂无输出';
+ }
+
+ outputElement.scrollTop = outputElement.scrollHeight;
+ }
+
+ // 添加远程仓库
+ async addRemote() {
+ const name = document.getElementById('remoteName').value.trim();
+ const url = document.getElementById('remoteUrl').value.trim();
+
+ if (!name || !url) {
+ this.showMessage('请输入远程仓库名称和地址', 'error');
+ return;
+ }
+
+ const params = new URLSearchParams();
+ params.append('action', 'add_remote');
+ params.append('name', name);
+ params.append('url', url);
+
+ try {
+ this.showMessage('正在添加远程仓库...', 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage('远程仓库添加成功', 'success');
+ document.getElementById('remoteUrl').value = ''; // 清空输入框
+ this.showRemotes(); // 刷新远程仓库列表
+ } else {
+ this.showMessage('添加远程仓库失败: ' + (result.message || '未知错误'), 'error');
+ }
+ } catch (error) {
+ this.showMessage('添加远程仓库出错: ' + error.message, 'error');
+ }
+ }
+
+ // 显示远程仓库列表
+ async showRemotes() {
+ try {
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: 'action=get_remotes'
+ });
+
+ const result = await response.json();
+ const remoteList = document.getElementById('remoteList');
+
+ if (result.success && result.remotes && Object.keys(result.remotes).length > 0) {
+ remoteList.innerHTML = '';
+
+ Object.entries(result.remotes).forEach(([name, info]) => {
+ const remoteItem = document.createElement('div');
+ remoteItem.className = 'remote-item';
+ remoteItem.innerHTML = `
+
+
${name} (${info.type})
+
${info.url}
+
+ `;
+ remoteList.appendChild(remoteItem);
+ });
+ } else {
+ remoteList.innerHTML = '暂无远程仓库
';
+ }
+ } catch (error) {
+ this.showMessage('获取远程仓库列表失败: ' + error.message, 'error');
+ }
+ }
+
+ // 加载分支列表
+ async loadBranches() {
+ try {
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: 'action=get_branches'
+ });
+
+ const result = await response.json();
+ const branchSelect = document.getElementById('branchSelect');
+
+ if (result.success && result.branches) {
+ branchSelect.innerHTML = '';
+
+ result.branches.forEach(branch => {
+ const option = document.createElement('option');
+ option.value = branch.name;
+ option.textContent = branch.name + (branch.current ? ' (当前)' : '') + (branch.remote ? ' (远程)' : '');
+ if (branch.current) {
+ option.selected = true;
+ }
+ branchSelect.appendChild(option);
+ });
+ } else {
+ branchSelect.innerHTML = '';
+ }
+ } catch (error) {
+ this.showMessage('获取分支列表失败: ' + error.message, 'error');
+ }
+ }
+
+ // 创建新分支
+ async createBranch() {
+ const branchName = document.getElementById('newBranchName').value.trim();
+
+ if (!branchName) {
+ this.showMessage('请输入分支名称', 'error');
+ return;
+ }
+
+ const params = new URLSearchParams();
+ params.append('action', 'create_branch');
+ params.append('branch_name', branchName);
+
+ try {
+ this.showMessage('正在创建分支...', 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage('分支创建成功', 'success');
+ document.getElementById('newBranchName').value = ''; // 清空输入框
+ this.loadBranches(); // 重新加载分支列表
+ this.displayGitOutput(result.output);
+ } else {
+ this.showMessage('创建分支失败: ' + (result.message || '未知错误'), 'error');
+ this.displayGitOutput(result.output || []);
+ }
+ } catch (error) {
+ this.showMessage('创建分支出错: ' + error.message, 'error');
+ }
+ }
+
+ // 切换分支
+ async switchBranch() {
+ const branchSelect = document.getElementById('branchSelect');
+ const branchName = branchSelect.value;
+
+ if (!branchName) {
+ this.showMessage('请选择要切换的分支', 'error');
+ return;
+ }
+
+ const params = new URLSearchParams();
+ params.append('action', 'switch_branch');
+ params.append('branch_name', branchName);
+
+ try {
+ this.showMessage('正在切换分支...', 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage('分支切换成功', 'success');
+ this.loadBranches(); // 重新加载分支列表
+ this.loadFileList(); // 重新加载文件列表
+ this.displayGitOutput(result.output);
+ } else {
+ this.showMessage('切换分支失败: ' + (result.message || '未知错误'), 'error');
+ this.displayGitOutput(result.output || []);
+ }
+ } catch (error) {
+ this.showMessage('切换分支出错: ' + error.message, 'error');
+ }
+ }
+
+ // 删除分支
+ async deleteBranch() {
+ const branchSelect = document.getElementById('branchSelect');
+ const branchName = branchSelect.value;
+
+ if (!branchName) {
+ this.showMessage('请选择要删除的分支', 'error');
+ return;
+ }
+
+ if (!confirm(`确定要删除分支 "${branchName}" 吗?`)) {
+ return;
+ }
+
+ const params = new URLSearchParams();
+ params.append('action', 'delete_branch');
+ params.append('branch_name', branchName);
+ params.append('force', 'false'); // 默认不强制删除
+
+ try {
+ this.showMessage('正在删除分支...', 'info');
+
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.showMessage('分支删除成功', 'success');
+ this.loadBranches(); // 重新加载分支列表
+ this.displayGitOutput(result.output);
+ } else {
+ this.showMessage('删除分支失败: ' + (result.message || '未知错误'), 'error');
+ this.displayGitOutput(result.output || []);
+
+ if (confirm('是否强制删除该分支?')) {
+ params.set('force', 'true');
+ const forceResponse = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: params
+ });
+ const forceResult = await forceResponse.json();
+ if (forceResult.success) {
+ this.showMessage('分支强制删除成功', 'success');
+ this.loadBranches();
+ this.displayGitOutput(forceResult.output);
+ }
+ }
+ }
+ } catch (error) {
+ this.showMessage('删除分支出错: ' + error.message, 'error');
+ }
+ }
+
+ // 加载文件列表
+ async loadFileList() {
+ try {
+ const response = await fetch('index.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: 'action=get_files'
+ });
+
+ const result = await response.json();
+
+ if (result.success) {
+ this.displayFileList(result.files);
+ } else {
+ this.showMessage('加载文件列表失败', 'error');
+ }
+ } catch (error) {
+ this.showMessage('加载文件列表出错: ' + error.message, 'error');
+ }
+ }
+
+ // 显示文件列表
+ displayFileList(files) {
+ const container = document.getElementById('fileList');
+
+ if (files.length === 0) {
+ container.innerHTML = '暂无文件
';
+ return;
+ }
+
+ container.innerHTML = '';
+
+ files.forEach(file => {
+ const fileItem = document.createElement('div');
+ fileItem.className = 'file-checkbox';
+
+ const checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.id = `file-${this.escapeId(file)}`;
+ checkbox.value = file;
+ checkbox.checked = this.selectedFiles.has(file);
+ checkbox.addEventListener('change', (e) => {
+ if (e.target.checked) {
+ this.selectedFiles.add(file);
+ } else {
+ this.selectedFiles.delete(file);
+ }
+ });
+
+ const label = document.createElement('label');
+ label.htmlFor = checkbox.id;
+ label.className = 'file-path';
+ label.textContent = file;
+ label.style.cursor = 'pointer';
+ label.style.flex = '1';
+
+ fileItem.appendChild(checkbox);
+ fileItem.appendChild(label);
+ container.appendChild(fileItem);
+ });
+ }
+
+ // 全选文件
+ selectAllFiles() {
+ const checkboxes = document.querySelectorAll('#fileList input[type="checkbox"]');
+ checkboxes.forEach(checkbox => {
+ checkbox.checked = true;
+ this.selectedFiles.add(checkbox.value);
+ });
+ }
+
+ // 取消全选
+ deselectAllFiles() {
+ const checkboxes = document.querySelectorAll('#fileList input[type="checkbox"]');
+ checkboxes.forEach(checkbox => {
+ checkbox.checked = false;
+ this.selectedFiles.delete(checkbox.value);
+ });
+ }
+
+ // 工具方法:转义ID
+ escapeId(str) {
+ return str.replace(/[^a-zA-Z0-9]/g, '_');
+ }
+
+ // 显示消息
+ showMessage(message, type = 'info') {
+ // 创建消息元素
+ const messageElement = document.createElement('div');
+ messageElement.className = `message ${type} fade-in`;
+ messageElement.textContent = message;
+
+ // 添加到页面顶部
+ const container = document.querySelector('.container');
+ container.insertBefore(messageElement, container.firstChild);
+
+ // 3秒后自动移除
+ setTimeout(() => {
+ messageElement.remove();
+ }, 3000);
+ }
+}
+
+// 页面加载完成后初始化
+document.addEventListener('DOMContentLoaded', () => {
+ new GitUploader();
+});
\ No newline at end of file
diff --git a/test.php b/test.php
new file mode 100644
index 0000000..3985411
--- /dev/null
+++ b/test.php
@@ -0,0 +1,179 @@
+ ini_get('upload_max_filesize'),
+ 'post_max_size' => ini_get('post_max_size'),
+ 'max_execution_time' => ini_get('max_execution_time'),
+ 'memory_limit' => ini_get('memory_limit')
+ ];
+
+ foreach ($configs as $key => $value) {
+ echo " $key: $value\n";
+ }
+
+ // 检查必要的PHP函数
+ $functions = ['exec', 'move_uploaded_file', 'json_encode', 'file_put_contents'];
+ $allFunctionsAvailable = true;
+
+ foreach ($functions as $function) {
+ if (function_exists($function)) {
+ echo "✓ 函数 $function 可用\n";
+ } else {
+ echo "✗ 函数 $function 不可用\n";
+ $allFunctionsAvailable = false;
+ }
+ }
+
+ return $allFunctionsAvailable;
+}
+
+// 测试目录权限
+function testDirectoryPermissions() {
+ echo "\n=== 测试目录权限 ===\n";
+
+ $directories = [
+ __DIR__,
+ __DIR__ . '/uploads/',
+ __DIR__ . '/css/',
+ __DIR__ . '/js/'
+ ];
+
+ foreach ($directories as $dir) {
+ if (!is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+
+ if (is_writable($dir)) {
+ echo "✓ 目录可写: $dir\n";
+ } else {
+ echo "✗ 目录不可写: $dir\n";
+ }
+ }
+
+ return true;
+}
+
+// 测试AJAX端点
+function testAjaxEndpoints() {
+ echo "\n=== 测试AJAX端点 ===\n";
+
+ // 这里可以添加更详细的端点测试
+ $endpoints = [
+ 'check_git' => '检查Git状态',
+ 'get_files' => '获取文件列表',
+ 'git_operation' => 'Git操作',
+ 'upload' => '文件上传'
+ ];
+
+ foreach ($endpoints as $endpoint => $description) {
+ echo "✓ 端点 $endpoint ($description) 已定义\n";
+ }
+
+ return true;
+}
+
+// 运行所有测试
+function runAllTests() {
+ echo "开始Git上传工具测试...\n";
+ echo "=====================================\n";
+
+ $tests = [
+ 'testPHPConfiguration',
+ 'testDirectoryPermissions',
+ 'testGitOperations',
+ 'testAjaxEndpoints',
+ 'testFileUpload'
+ ];
+
+ $allPassed = true;
+
+ foreach ($tests as $test) {
+ try {
+ $result = $test();
+ if (!$result) {
+ $allPassed = false;
+ }
+ } catch (Exception $e) {
+ echo "✗ 测试 $test 抛出异常: " . $e->getMessage() . "\n";
+ $allPassed = false;
+ }
+ echo "\n";
+ }
+
+ echo "=====================================\n";
+ if ($allPassed) {
+ echo "✓ 所有测试通过!工具应该可以正常工作。\n";
+ } else {
+ echo "✗ 部分测试失败,请检查配置和权限。\n";
+ }
+
+ // 清理测试文件
+ $testFiles = glob('test_upload_*.txt');
+ foreach ($testFiles as $file) {
+ unlink($file);
+ }
+}
+
+// 如果直接访问此文件,运行测试
+if (basename($_SERVER['PHP_SELF']) === basename(__FILE__)) {
+ runAllTests();
+}
\ No newline at end of file
diff --git a/uploads/test.php b/uploads/test.php
new file mode 100644
index 0000000..3985411
--- /dev/null
+++ b/uploads/test.php
@@ -0,0 +1,179 @@
+ ini_get('upload_max_filesize'),
+ 'post_max_size' => ini_get('post_max_size'),
+ 'max_execution_time' => ini_get('max_execution_time'),
+ 'memory_limit' => ini_get('memory_limit')
+ ];
+
+ foreach ($configs as $key => $value) {
+ echo " $key: $value\n";
+ }
+
+ // 检查必要的PHP函数
+ $functions = ['exec', 'move_uploaded_file', 'json_encode', 'file_put_contents'];
+ $allFunctionsAvailable = true;
+
+ foreach ($functions as $function) {
+ if (function_exists($function)) {
+ echo "✓ 函数 $function 可用\n";
+ } else {
+ echo "✗ 函数 $function 不可用\n";
+ $allFunctionsAvailable = false;
+ }
+ }
+
+ return $allFunctionsAvailable;
+}
+
+// 测试目录权限
+function testDirectoryPermissions() {
+ echo "\n=== 测试目录权限 ===\n";
+
+ $directories = [
+ __DIR__,
+ __DIR__ . '/uploads/',
+ __DIR__ . '/css/',
+ __DIR__ . '/js/'
+ ];
+
+ foreach ($directories as $dir) {
+ if (!is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+
+ if (is_writable($dir)) {
+ echo "✓ 目录可写: $dir\n";
+ } else {
+ echo "✗ 目录不可写: $dir\n";
+ }
+ }
+
+ return true;
+}
+
+// 测试AJAX端点
+function testAjaxEndpoints() {
+ echo "\n=== 测试AJAX端点 ===\n";
+
+ // 这里可以添加更详细的端点测试
+ $endpoints = [
+ 'check_git' => '检查Git状态',
+ 'get_files' => '获取文件列表',
+ 'git_operation' => 'Git操作',
+ 'upload' => '文件上传'
+ ];
+
+ foreach ($endpoints as $endpoint => $description) {
+ echo "✓ 端点 $endpoint ($description) 已定义\n";
+ }
+
+ return true;
+}
+
+// 运行所有测试
+function runAllTests() {
+ echo "开始Git上传工具测试...\n";
+ echo "=====================================\n";
+
+ $tests = [
+ 'testPHPConfiguration',
+ 'testDirectoryPermissions',
+ 'testGitOperations',
+ 'testAjaxEndpoints',
+ 'testFileUpload'
+ ];
+
+ $allPassed = true;
+
+ foreach ($tests as $test) {
+ try {
+ $result = $test();
+ if (!$result) {
+ $allPassed = false;
+ }
+ } catch (Exception $e) {
+ echo "✗ 测试 $test 抛出异常: " . $e->getMessage() . "\n";
+ $allPassed = false;
+ }
+ echo "\n";
+ }
+
+ echo "=====================================\n";
+ if ($allPassed) {
+ echo "✓ 所有测试通过!工具应该可以正常工作。\n";
+ } else {
+ echo "✗ 部分测试失败,请检查配置和权限。\n";
+ }
+
+ // 清理测试文件
+ $testFiles = glob('test_upload_*.txt');
+ foreach ($testFiles as $file) {
+ unlink($file);
+ }
+}
+
+// 如果直接访问此文件,运行测试
+if (basename($_SERVER['PHP_SELF']) === basename(__FILE__)) {
+ runAllTests();
+}
\ No newline at end of file