CatPtain commited on
Commit
c005a05
·
verified ·
1 Parent(s): 4ba9d42

Upload 6 files

Browse files
Files changed (3) hide show
  1. github-advanced-test.php +244 -217
  2. github-save-debug.php +335 -0
  3. storage.php +42 -0
github-advanced-test.php CHANGED
@@ -51,7 +51,7 @@ function testGitHubAPI($token, $endpoint, $method = 'GET', $data = null) {
51
  // 详细日志记录
52
  error_log("GitHub API Test: $method $endpoint - HTTP $httpCode");
53
  if ($error) {
54
- error_log("GitHub API cURL Error: $error");
55
  }
56
 
57
  return [
@@ -59,8 +59,7 @@ function testGitHubAPI($token, $endpoint, $method = 'GET', $data = null) {
59
  'http_code' => $httpCode,
60
  'response' => $result,
61
  'error' => $error,
62
- 'endpoint' => $endpoint,
63
- 'method' => $method
64
  ];
65
  }
66
 
@@ -78,28 +77,30 @@ if ($_POST['run_diagnostics'] ?? false) {
78
  $branchUrl = "https://api.github.com/repos/{$github['owner']}/{$github['repo']}/branches/{$github['branch']}";
79
  $diagnostics['branch_test'] = testGitHubAPI($github['token'], $branchUrl);
80
 
81
- // 测试 4: 测试文件创建权限(使用更安全的测试文件名)
82
- $testFile = 'test/diagnostic-test-' . time() . '.txt';
83
- $testContent = 'VvvebJs Diagnostic Test - ' . date('Y-m-d H:i:s') . "\nThis is a test file created by VvvebJs diagnostic tool.";
84
- $createUrl = "https://api.github.com/repos/{$github['owner']}/{$github['repo']}/contents/{$github['path']}{$testFile}";
85
- $diagnostics['create_test'] = testGitHubAPI($github['token'], $createUrl, 'PUT', [
86
- 'message' => 'VvvebJs diagnostic test - ' . date('Y-m-d H:i:s'),
 
 
 
 
 
87
  'content' => base64_encode($testContent),
88
  'branch' => $github['branch']
89
- ]);
 
90
 
91
- // 如果创建成功,尝试删除测试文件以保持整洁
92
- if ($diagnostics['create_test']['success']) {
93
- // 获取创建的文件的SHA以便删除
94
- $createdFile = json_decode($diagnostics['create_test']['response'], true);
95
- if (isset($createdFile['content']['sha'])) {
96
- $deleteData = [
97
- 'message' => 'Clean up diagnostic test file - ' . date('Y-m-d H:i:s'),
98
- 'sha' => $createdFile['content']['sha'],
99
- 'branch' => $github['branch']
100
- ];
101
- $diagnostics['cleanup_test'] = testGitHubAPI($github['token'], $createUrl, 'DELETE', $deleteData);
102
- }
103
  }
104
  }
105
  ?>
@@ -112,49 +113,40 @@ if ($_POST['run_diagnostics'] ?? false) {
112
  <title>VvvebJs GitHub 高级诊断</title>
113
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
114
  <style>
115
- .diagnostic-result { font-family: monospace; font-size: 12px; }
116
  .status-ok { color: #28a745; }
117
  .status-error { color: #dc3545; }
118
  .status-warning { color: #ffc107; }
119
- .config-value { background-color: #f8f9fa; padding: 2px 6px; border-radius: 3px; }
 
120
  </style>
121
  </head>
122
  <body>
123
  <div class="container mt-5">
124
  <div class="row">
125
- <div class="col-md-10 mx-auto">
126
- <h1 class="mb-4">🔍 VvvebJs GitHub 高级诊断</h1>
127
 
128
- <!-- 当前配置 -->
129
  <div class="card mb-4">
130
  <div class="card-header">
131
- <h3>📋 当前配置</h3>
132
  </div>
133
  <div class="card-body">
134
  <div class="row">
135
  <div class="col-md-6">
136
  <p><strong>Token:</strong>
137
- <span class="diagnostic-result config-value">
138
- <?= !empty($github['token']) ? substr($github['token'], 0, 8) . '...' : ' 缺失' ?>
139
  </span>
140
  </p>
141
- <p><strong>Owner:</strong>
142
- <span class="diagnostic-result config-value"><?= htmlspecialchars($github['owner']) ?></span>
143
- </p>
144
- <p><strong>Repo:</strong>
145
- <span class="diagnostic-result config-value"><?= htmlspecialchars($github['repo']) ?></span>
146
- </p>
147
  </div>
148
  <div class="col-md-6">
149
- <p><strong>Branch:</strong>
150
- <span class="diagnostic-result config-value"><?= htmlspecialchars($github['branch']) ?></span>
151
- </p>
152
- <p><strong>Path:</strong>
153
- <span class="diagnostic-result config-value"><?= htmlspecialchars($github['path']) ?></span>
154
- </p>
155
- <p><strong>API URL:</strong>
156
- <span class="diagnostic-result config-value">https://api.github.com/repos/<?= htmlspecialchars($github['owner']) ?>/<?= htmlspecialchars($github['repo']) ?></span>
157
- </p>
158
  </div>
159
  </div>
160
  </div>
@@ -162,223 +154,258 @@ if ($_POST['run_diagnostics'] ?? false) {
162
 
163
  <!-- 诊断控制 -->
164
  <div class="card mb-4">
165
- <div class="card-body text-center">
 
 
 
 
 
166
  <form method="POST">
167
  <button type="submit" name="run_diagnostics" value="1" class="btn btn-primary btn-lg">
168
- 🧪 运行完整诊断
169
  </button>
170
  </form>
 
 
 
 
 
 
 
 
171
  </div>
172
  </div>
173
 
174
- <?php if (!empty($diagnostics)): ?>
175
  <!-- 诊断结果 -->
 
 
 
176
  <div class="card mb-4">
177
  <div class="card-header">
178
- <h3>🔬 诊断结果</h3>
179
  </div>
180
  <div class="card-body">
181
-
182
- <!-- Token 验证 -->
183
- <div class="mb-4">
184
- <h5>1. GitHub Token 验证</h5>
185
- <?php $test = $diagnostics['token_test']; ?>
186
- <div class="alert alert-<?= $test['success'] ? 'success' : 'danger' ?>">
187
- <strong>状态:</strong>
188
- <span class="<?= $test['success'] ? 'status-ok' : 'status-error' ?>">
189
- <?= $test['success'] ? '✅ 有效' : '❌ 无效' ?>
190
  </span>
191
- (HTTP <?= $test['http_code'] ?>)
192
-
193
- <?php if ($test['success'] && $test['response']): ?>
194
- <?php $user = json_decode($test['response'], true); ?>
195
- <br><strong>用户信息:</strong> <?= htmlspecialchars($user['login'] ?? 'Unknown') ?>
196
- <br><strong>用户名:</strong> <?= htmlspecialchars($user['name'] ?? 'N/A') ?>
197
- <br><strong>API Rate Limit:</strong> <?= isset($user['id']) ? '✅ 正常' : '⚠️ 可能受限' ?>
198
- <?php elseif (!$test['success']): ?>
199
- <br><strong>错误详情:</strong>
200
- <pre class="diagnostic-result mt-2"><?= htmlspecialchars($test['error'] ?: $test['response']) ?></pre>
201
- <?php endif; ?>
202
- </div>
203
  </div>
 
 
 
 
 
 
 
 
 
204
 
205
- <!-- 仓库检查 -->
206
- <div class="mb-4">
207
- <h5>2. 仓库访问检查</h5>
208
- <?php $test = $diagnostics['repo_test']; ?>
209
- <div class="alert alert-<?= $test['success'] ? 'success' : 'danger' ?>">
210
- <strong>状态:</strong>
211
- <span class="<?= $test['success'] ? 'status-ok' : 'status-error' ?>">
212
- <?= $test['success'] ? '✅ 可访问' : '❌ 无法访问' ?>
 
 
 
213
  </span>
214
- (HTTP <?= $test['http_code'] ?>)
215
-
216
- <?php if ($test['success'] && $test['response']): ?>
217
- <?php $repo = json_decode($test['response'], true); ?>
218
- <br><strong>仓库全名:</strong> <?= htmlspecialchars($repo['full_name'] ?? 'Unknown') ?>
219
- <br><strong>私有仓库:</strong> <?= $repo['private'] ? '是' : '否' ?>
220
- <br><strong>默认分支:</strong> <?= htmlspecialchars($repo['default_branch'] ?? 'Unknown') ?>
221
- <br><strong>权限:</strong>
222
- <?php
223
- $permissions = $repo['permissions'] ?? [];
224
- $canPush = $permissions['push'] ?? false;
225
- echo $canPush ? '✅ 可写入' : '⚠️ 只读';
226
- ?>
227
- <?php elseif ($test['http_code'] == 404): ?>
228
- <br><strong>错误:</strong> 仓库不存在或无访问权限
229
- <?php else: ?>
230
- <br><strong>错误详情:</strong>
231
- <pre class="diagnostic-result mt-2"><?= htmlspecialchars($test['response']) ?></pre>
232
- <?php endif; ?>
233
- </div>
234
  </div>
 
 
 
235
 
236
- <!-- 分支检查 -->
237
- <div class="mb-4">
238
- <h5>3. 分支检查</h5>
239
- <?php $test = $diagnostics['branch_test']; ?>
240
- <div class="alert alert-<?= $test['success'] ? 'success' : 'danger' ?>">
241
- <strong>状态:</strong>
242
- <span class="<?= $test['success'] ? 'status-ok' : 'status-error' ?>">
243
- <?= $test['success'] ? '✅ 分支存在' : '❌ 分支不存在' ?>
 
 
 
244
  </span>
245
- (HTTP <?= $test['http_code'] ?>)
246
-
247
- <?php if ($test['success'] && $test['response']): ?>
248
- <?php $branch = json_decode($test['response'], true); ?>
249
- <br><strong>分支名:</strong> <?= htmlspecialchars($branch['name'] ?? 'Unknown') ?>
250
- <br><strong>最新提交:</strong> <?= htmlspecialchars(substr($branch['commit']['sha'] ?? '', 0, 7)) ?>
251
- <br><strong>提交信息:</strong> <?= htmlspecialchars(substr($branch['commit']['commit']['message'] ?? '', 0, 50)) ?><?= strlen($branch['commit']['commit']['message'] ?? '') > 50 ? '...' : '' ?>
252
- <?php endif; ?>
253
- </div>
254
  </div>
 
 
 
 
 
 
 
 
 
255
 
256
- <!-- 文件创建权限 -->
257
- <div class="mb-4">
258
- <h5>4. 文件创建权限测试</h5>
259
- <?php $test = $diagnostics['create_test']; ?>
260
- <div class="alert alert-<?= $test['success'] ? 'success' : 'danger' ?>">
261
- <strong>状态:</strong>
262
- <span class="<?= $test['success'] ? 'status-ok' : 'status-error' ?>">
263
- <?= $test['success'] ? '✅ 可以创建文件' : '❌ 无法创建文件' ?>
 
 
 
264
  </span>
265
- (HTTP <?= $test['http_code'] ?>)
266
-
267
- <?php if ($test['success']): ?>
268
- <br><strong>✅ 成功创建测试文件!GitHub 保存功能正常。</strong>
269
- <?php if (isset($diagnostics['cleanup_test']) && $diagnostics['cleanup_test']['success']): ?>
270
- <br><small class="text-muted">🧹 测试文件已自动清理</small>
271
- <?php endif; ?>
272
- <?php else: ?>
273
- <br><strong>错误详情:</strong>
274
- <pre class="diagnostic-result mt-2"><?= htmlspecialchars($test['response']) ?></pre>
275
- <br><strong>请求信息:</strong> <?= $test['method'] ?> <?= htmlspecialchars($test['endpoint']) ?>
276
- <?php endif; ?>
277
- </div>
278
  </div>
 
 
 
279
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  </div>
281
  </div>
282
 
283
- <!-- 解决方案 -->
284
- <div class="card">
285
  <div class="card-header">
286
- <h3>🔧 问题解决方案</h3>
287
  </div>
288
  <div class="card-body">
289
- <?php
290
- $hasErrors = false;
291
- $hasWarnings = false;
292
- foreach ($diagnostics as $key => $test) {
293
- if ($key === 'cleanup_test') continue; // 跳过清理测试
294
- if (!$test['success']) {
295
- $hasErrors = true;
296
- break;
297
- }
298
- }
299
  ?>
300
 
301
- <?php if (!$hasErrors): ?>
302
  <div class="alert alert-success">
303
- <h5>🎉 所有测试通过!</h5>
304
- <p>GitHub 配置完全正常,可以正常保存文件。如果编辑器保存仍有问题,请检查:</p>
 
 
 
 
 
 
305
  <ul>
306
- <li>编辑器中的用户认证是否正确</li>
307
- <li>浏览器控制台是否有JavaScript错误</li>
308
- <li>网络连接是否稳定</li>
309
- <li>防火墙是否阻止了API请求</li>
 
 
 
 
 
 
 
 
310
  </ul>
311
- <div class="mt-3">
312
- <a href="editor.html" class="btn btn-success">🚀 开始使用编辑器</a>
313
- </div>
314
  </div>
315
- <?php else: ?>
316
- <div class="alert alert-warning">
317
- <h5>⚠️ 发现问题,请按以下步骤修复:</h5>
318
-
319
- <?php if (!$diagnostics['token_test']['success']): ?>
320
- <div class="mb-3">
321
- <h6>🔑 Token 问题</h6>
322
- <ul>
323
- <li>检查 <code>GITHUB_TOKEN</code> 环境变量是否正确设置</li>
324
- <li>访问 <a href="https://github.com/settings/tokens" target="_blank">GitHub Token 设置</a> 重新生成</li>
325
- <li>确保 Token 有 <code>repo</code> 权限(不仅是 <code>public_repo</code>)</li>
326
- <li>如果是私有仓库,确保 Token 有完整的私有仓库访问权限</li>
327
- </ul>
328
  </div>
329
- <?php endif; ?>
330
-
331
- <?php if (!$diagnostics['repo_test']['success']): ?>
332
- <div class="mb-3">
333
- <h6>📁 仓库问题</h6>
334
- <ul>
335
- <li>检查 <code>GITHUB_OWNER</code> 是否是正确的用户名或组织名(区分大小写)</li>
336
- <li>检查 <code>GITHUB_REPO</code> 是否是正确的仓库名(区分大小写)</li>
337
- <li>确保仓库存在且 Token 有访问权限</li>
338
- <li>如果是组织仓库,确保 Token 有组织权限</li>
339
- </ul>
340
  </div>
341
- <?php endif; ?>
342
-
343
- <?php if (!$diagnostics['branch_test']['success']): ?>
344
- <div class="mb-3">
345
- <h6>🌿 分支问题</h6>
346
- <ul>
347
- <li>检查 <code>GITHUB_BRANCH</code> 是否正确(通常是 <code>main</code> 或 <code>master</code>)</li>
348
- <li>在 GitHub 仓库中创建对应的分支</li>
349
- <li>确保分支存在且不是空分支</li>
350
- </ul>
351
  </div>
352
- <?php endif; ?>
353
-
354
- <?php if (!$diagnostics['create_test']['success']): ?>
355
- <div class="mb-3">
356
- <h6>✏️ 写入权限问题</h6>
357
- <ul>
358
- <li><strong>确保 Token 有 <code>repo</code> 的完整权限</strong>(这是最常见的问题)</li>
359
- <li>检查仓库是否允许写入(不是只读状态)</li>
360
- <li>检查 <code>GITHUB_PATH</code> 路径格式是否正确(应以 <code>/</code> 结尾)</li>
361
- <li>确保目标路径在仓库中存在或可以创建</li>
362
- <li>检查是否有分支保护规则阻止直接推送</li>
363
- </ul>
364
  </div>
365
- <?php endif; ?>
366
- </div>
367
- <?php endif; ?>
368
-
369
- <div class="mt-4">
370
- <a href="config.php" class="btn btn-secondary">⚙️ 返回配置页面</a>
371
- <a href="github-test.php" class="btn btn-info">🧪 基础测试</a>
372
- <?php if (!$hasErrors): ?>
373
- <a href="editor.html" class="btn btn-primary">📝 返回编辑器</a>
374
- <?php endif; ?>
375
  </div>
376
  </div>
377
  </div>
378
-
379
- <?php endif; ?>
380
  </div>
381
  </div>
382
  </div>
 
 
383
  </body>
384
  </html>
 
51
  // 详细日志记录
52
  error_log("GitHub API Test: $method $endpoint - HTTP $httpCode");
53
  if ($error) {
54
+ error_log("GitHub API Test cURL Error: $error");
55
  }
56
 
57
  return [
 
59
  'http_code' => $httpCode,
60
  'response' => $result,
61
  'error' => $error,
62
+ 'decoded' => json_decode($result, true)
 
63
  ];
64
  }
65
 
 
77
  $branchUrl = "https://api.github.com/repos/{$github['owner']}/{$github['repo']}/branches/{$github['branch']}";
78
  $diagnostics['branch_test'] = testGitHubAPI($github['token'], $branchUrl);
79
 
80
+ // 测试 4: 测试用户目录读取
81
+ $userPath = StorageConfig::getUserPath();
82
+ $userDirUrl = "https://api.github.com/repos/{$github['owner']}/{$github['repo']}/contents/{$github['path']}{$userPath}";
83
+ $diagnostics['user_dir_test'] = testGitHubAPI($github['token'], $userDirUrl);
84
+
85
+ // 测试 5: 测试写入权限(创建测试文件)
86
+ $testFilePath = "{$github['path']}{$userPath}test-write-permission.txt";
87
+ $testFileUrl = "https://api.github.com/repos/{$github['owner']}/{$github['repo']}/contents/{$testFilePath}";
88
+ $testContent = "VvvebJs write permission test - " . date('Y-m-d H:i:s');
89
+ $testData = [
90
+ 'message' => 'VvvebJs write permission test',
91
  'content' => base64_encode($testContent),
92
  'branch' => $github['branch']
93
+ ];
94
+ $diagnostics['write_test'] = testGitHubAPI($github['token'], $testFileUrl, 'PUT', $testData);
95
 
96
+ // 如果写入成功,立即删除测试文件
97
+ if ($diagnostics['write_test']['success'] && isset($diagnostics['write_test']['decoded']['sha'])) {
98
+ $deleteData = [
99
+ 'message' => 'Clean up VvvebJs write permission test',
100
+ 'sha' => $diagnostics['write_test']['decoded']['sha'],
101
+ 'branch' => $github['branch']
102
+ ];
103
+ $diagnostics['cleanup_test'] = testGitHubAPI($github['token'], $testFileUrl, 'DELETE', $deleteData);
 
 
 
 
104
  }
105
  }
106
  ?>
 
113
  <title>VvvebJs GitHub 高级诊断</title>
114
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
115
  <style>
116
+ .config-value { background-color: #f8f9fa; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
117
  .status-ok { color: #28a745; }
118
  .status-error { color: #dc3545; }
119
  .status-warning { color: #ffc107; }
120
+ .test-result { margin-bottom: 20px; }
121
+ .response-data { background: #f8f9fa; padding: 10px; border-radius: 5px; max-height: 200px; overflow-y: auto; font-family: monospace; font-size: 12px; }
122
  </style>
123
  </head>
124
  <body>
125
  <div class="container mt-5">
126
  <div class="row">
127
+ <div class="col-md-12">
128
+ <h1 class="mb-4">🔬 VvvebJs GitHub 高级诊断工具</h1>
129
 
130
+ <!-- 当前配置概览 -->
131
  <div class="card mb-4">
132
  <div class="card-header">
133
+ <h3>��️ 当前GitHub配置</h3>
134
  </div>
135
  <div class="card-body">
136
  <div class="row">
137
  <div class="col-md-6">
138
  <p><strong>Token:</strong>
139
+ <span class="config-value <?= empty($github['token']) ? 'status-error' : 'status-ok' ?>">
140
+ <?= empty($github['token']) ? '❌ 未设置' : '✅ ' . substr($github['token'], 0, 8) . '... (长度: ' . strlen($github['token']) . ')' ?>
141
  </span>
142
  </p>
143
+ <p><strong>Owner:</strong> <span class="config-value"><?= htmlspecialchars($github['owner']) ?></span></p>
144
+ <p><strong>Repo:</strong> <span class="config-value"><?= htmlspecialchars($github['repo']) ?></span></p>
 
 
 
 
145
  </div>
146
  <div class="col-md-6">
147
+ <p><strong>Branch:</strong> <span class="config-value"><?= htmlspecialchars($github['branch']) ?></span></p>
148
+ <p><strong>Path:</strong> <span class="config-value"><?= htmlspecialchars($github['path']) ?></span></p>
149
+ <p><strong>User Path:</strong> <span class="config-value"><?= htmlspecialchars(StorageConfig::getUserPath()) ?></span></p>
 
 
 
 
 
 
150
  </div>
151
  </div>
152
  </div>
 
154
 
155
  <!-- 诊断控制 -->
156
  <div class="card mb-4">
157
+ <div class="card-header">
158
+ <h3>🚀 开始诊断</h3>
159
+ </div>
160
+ <div class="card-body">
161
+ <?php if (empty($diagnostics)): ?>
162
+ <p>点击下方按钮开始完整的GitHub连接和权限诊断:</p>
163
  <form method="POST">
164
  <button type="submit" name="run_diagnostics" value="1" class="btn btn-primary btn-lg">
165
+ 🔍 运行完整诊断
166
  </button>
167
  </form>
168
+ <?php else: ?>
169
+ <p>诊断完成!查看下方详细结果。</p>
170
+ <form method="POST">
171
+ <button type="submit" name="run_diagnostics" value="1" class="btn btn-secondary">
172
+ 🔄 重新运行诊断
173
+ </button>
174
+ </form>
175
+ <?php endif; ?>
176
  </div>
177
  </div>
178
 
 
179
  <!-- 诊断结果 -->
180
+ <?php if (!empty($diagnostics)): ?>
181
+
182
+ <!-- Token验证结果 -->
183
  <div class="card mb-4">
184
  <div class="card-header">
185
+ <h3>🔐 Token验证结果</h3>
186
  </div>
187
  <div class="card-body">
188
+ <?php $tokenTest = $diagnostics['token_test']; ?>
189
+ <div class="alert alert-<?= $tokenTest['success'] ? 'success' : 'danger' ?>">
190
+ <h5>
191
+ <span class="<?= $tokenTest['success'] ? 'status-ok' : 'status-error' ?>">
192
+ <?= $tokenTest['success'] ? '✅ Token有效' : '❌ Token无效' ?>
 
 
 
 
193
  </span>
194
+ (HTTP <?= $tokenTest['http_code'] ?>)
195
+ </h5>
196
+ <?php if ($tokenTest['success'] && $tokenTest['decoded']): ?>
197
+ <p><strong>GitHub用户:</strong> <?= htmlspecialchars($tokenTest['decoded']['login']) ?></p>
198
+ <p><strong>用户类型:</strong> <?= htmlspecialchars($tokenTest['decoded']['type']) ?></p>
199
+ <?php if (isset($tokenTest['decoded']['scopes'])): ?>
200
+ <p><strong>Token权限:</strong> <?= implode(', ', $tokenTest['decoded']['scopes']) ?></p>
201
+ <?php endif; ?>
202
+ <?php endif; ?>
 
 
 
203
  </div>
204
+
205
+ <?php if (!$tokenTest['success']): ?>
206
+ <div class="response-data">
207
+ <strong>错误响应:</strong><br>
208
+ <?= htmlspecialchars($tokenTest['response']) ?>
209
+ </div>
210
+ <?php endif; ?>
211
+ </div>
212
+ </div>
213
 
214
+ <!-- 仓库访问结果 -->
215
+ <div class="card mb-4">
216
+ <div class="card-header">
217
+ <h3>📁 仓库访问结果</h3>
218
+ </div>
219
+ <div class="card-body">
220
+ <?php $repoTest = $diagnostics['repo_test']; ?>
221
+ <div class="alert alert-<?= $repoTest['success'] ? 'success' : 'danger' ?>">
222
+ <h5>
223
+ <span class="<?= $repoTest['success'] ? 'status-ok' : 'status-error' ?>">
224
+ <?= $repoTest['success'] ? '✅ 仓库可访问' : '❌ 仓库不可访问' ?>
225
  </span>
226
+ (HTTP <?= $repoTest['http_code'] ?>)
227
+ </h5>
228
+ <?php if ($repoTest['success'] && $repoTest['decoded']): ?>
229
+ <p><strong>仓库全名:</strong> <?= htmlspecialchars($repoTest['decoded']['full_name']) ?></p>
230
+ <p><strong>默认分支:</strong> <?= htmlspecialchars($repoTest['decoded']['default_branch']) ?></p>
231
+ <p><strong>仓库权限:</strong>
232
+ 读取: <?= $repoTest['decoded']['permissions']['pull'] ? '' : '❌' ?>,
233
+ 写入: <?= $repoTest['decoded']['permissions']['push'] ? '✅' : '❌' ?>,
234
+ 管理: <?= $repoTest['decoded']['permissions']['admin'] ? '✅' : '❌' ?>
235
+ </p>
236
+ <?php endif; ?>
237
+ </div>
238
+
239
+ <?php if (!$repoTest['success']): ?>
240
+ <div class="response-data">
241
+ <strong>错误响应:</strong><br>
242
+ <?= htmlspecialchars($repoTest['response']) ?>
 
 
 
243
  </div>
244
+ <?php endif; ?>
245
+ </div>
246
+ </div>
247
 
248
+ <!-- 分支检查结果 -->
249
+ <div class="card mb-4">
250
+ <div class="card-header">
251
+ <h3>🌿 分支检查结果</h3>
252
+ </div>
253
+ <div class="card-body">
254
+ <?php $branchTest = $diagnostics['branch_test']; ?>
255
+ <div class="alert alert-<?= $branchTest['success'] ? 'success' : 'danger' ?>">
256
+ <h5>
257
+ <span class="<?= $branchTest['success'] ? 'status-ok' : 'status-error' ?>">
258
+ <?= $branchTest['success'] ? '✅ 分支存在' : '❌ 分支不存在' ?>
259
  </span>
260
+ (HTTP <?= $branchTest['http_code'] ?>)
261
+ </h5>
262
+ <?php if ($branchTest['success'] && $branchTest['decoded']): ?>
263
+ <p><strong>分支名:</strong> <?= htmlspecialchars($branchTest['decoded']['name']) ?></p>
264
+ <p><strong>最后提交:</strong> <?= htmlspecialchars($branchTest['decoded']['commit']['sha']) ?></p>
265
+ <?php endif; ?>
 
 
 
266
  </div>
267
+
268
+ <?php if (!$branchTest['success']): ?>
269
+ <div class="response-data">
270
+ <strong>错误响应:</strong><br>
271
+ <?= htmlspecialchars($branchTest['response']) ?>
272
+ </div>
273
+ <?php endif; ?>
274
+ </div>
275
+ </div>
276
 
277
+ <!-- 用户目录检查结果 -->
278
+ <div class="card mb-4">
279
+ <div class="card-header">
280
+ <h3>👤 用户目录检查结果</h3>
281
+ </div>
282
+ <div class="card-body">
283
+ <?php $userDirTest = $diagnostics['user_dir_test']; ?>
284
+ <div class="alert alert-<?= $userDirTest['success'] ? 'success' : 'warning' ?>">
285
+ <h5>
286
+ <span class="<?= $userDirTest['success'] ? 'status-ok' : 'status-warning' ?>">
287
+ <?= $userDirTest['success'] ? '✅ 用户目录存在' : '⚠️ 用户目录不存在' ?>
288
  </span>
289
+ (HTTP <?= $userDirTest['http_code'] ?>)
290
+ </h5>
291
+ <?php if ($userDirTest['success'] && $userDirTest['decoded']): ?>
292
+ <p><strong>目录文件数:</strong> <?= count($userDirTest['decoded']) ?></p>
293
+ <?php elseif ($userDirTest['http_code'] == 404): ?>
294
+ <p>用户目录尚不存在,将在首次保存文件时自动创建。</p>
295
+ <?php endif; ?>
296
+ </div>
297
+
298
+ <?php if ($userDirTest['http_code'] != 404 && !$userDirTest['success']): ?>
299
+ <div class="response-data">
300
+ <strong>错误响应:</strong><br>
301
+ <?= htmlspecialchars($userDirTest['response']) ?>
302
  </div>
303
+ <?php endif; ?>
304
+ </div>
305
+ </div>
306
 
307
+ <!-- 写入权限测试结果 -->
308
+ <div class="card mb-4">
309
+ <div class="card-header">
310
+ <h3>✍️ 写入权限测试结果</h3>
311
+ </div>
312
+ <div class="card-body">
313
+ <?php $writeTest = $diagnostics['write_test']; ?>
314
+ <div class="alert alert-<?= $writeTest['success'] ? 'success' : 'danger' ?>">
315
+ <h5>
316
+ <span class="<?= $writeTest['success'] ? 'status-ok' : 'status-error' ?>">
317
+ <?= $writeTest['success'] ? '✅ 写入权限正常' : '❌ 写入权限失败' ?>
318
+ </span>
319
+ (HTTP <?= $writeTest['http_code'] ?>)
320
+ </h5>
321
+ <?php if ($writeTest['success']): ?>
322
+ <p>成功创建测试文件,GitHub写入权限正常。</p>
323
+ <?php if (isset($diagnostics['cleanup_test'])): ?>
324
+ <p><strong>清理:</strong>
325
+ <span class="<?= $diagnostics['cleanup_test']['success'] ? 'status-ok' : 'status-warning' ?>">
326
+ <?= $diagnostics['cleanup_test']['success'] ? '✅ 测试文件已删除' : '⚠️ 测试文件删除失败' ?>
327
+ </span>
328
+ </p>
329
+ <?php endif; ?>
330
+ <?php endif; ?>
331
+ </div>
332
+
333
+ <?php if (!$writeTest['success']): ?>
334
+ <div class="response-data">
335
+ <strong>错误响应:</strong><br>
336
+ <?= htmlspecialchars($writeTest['response']) ?>
337
+ </div>
338
+ <?php endif; ?>
339
  </div>
340
  </div>
341
 
342
+ <!-- 诊断总结 -->
343
+ <div class="card mb-4">
344
  <div class="card-header">
345
+ <h3>📊 诊断总结</h3>
346
  </div>
347
  <div class="card-body">
348
+ <?php
349
+ $allPassed = $diagnostics['token_test']['success'] &&
350
+ $diagnostics['repo_test']['success'] &&
351
+ $diagnostics['branch_test']['success'] &&
352
+ $diagnostics['write_test']['success'];
 
 
 
 
 
353
  ?>
354
 
355
+ <?php if ($allPassed): ?>
356
  <div class="alert alert-success">
357
+ <h4>🎉 所有测试通过!</h4>
358
+ <p>你的GitHub配置完全正常,VvvebJs应该能够正常保存文件到GitHub仓库。</p>
359
+ <p><strong>建议:</strong> 如果仍然遇到保存问题,请检查网络连接或尝试重启Hugging Face Space。</p>
360
+ </div>
361
+ <?php else: ?>
362
+ <div class="alert alert-danger">
363
+ <h4>❌ 发现问题</h4>
364
+ <p>部分测试失败,请根据上述详细结果修复相关问题:</p>
365
  <ul>
366
+ <?php if (!$diagnostics['token_test']['success']): ?>
367
+ <li>Token验证失败 - 检查Token是否正确且有效</li>
368
+ <?php endif; ?>
369
+ <?php if (!$diagnostics['repo_test']['success']): ?>
370
+ <li>仓库访问失败 - 检查仓库名称和权限</li>
371
+ <?php endif; ?>
372
+ <?php if (!$diagnostics['branch_test']['success']): ?>
373
+ <li>分支不存在 - 检查分支名称是否正确</li>
374
+ <?php endif; ?>
375
+ <?php if (!$diagnostics['write_test']['success']): ?>
376
+ <li>写入权限不足 - 检查Token是否有repo权限</li>
377
+ <?php endif; ?>
378
  </ul>
 
 
 
379
  </div>
380
+ <?php endif; ?>
381
+ </div>
382
+ </div>
383
+
384
+ <?php endif; ?>
385
+
386
+ <!-- 操作按钮 -->
387
+ <div class="card">
388
+ <div class="card-body text-center">
389
+ <div class="row">
390
+ <div class="col-md-3">
391
+ <a href="github-save-debug.php" class="btn btn-warning w-100">保存调试</a>
 
392
  </div>
393
+ <div class="col-md-3">
394
+ <a href="hf-space-check.php" class="btn btn-info w-100">HF Space 检查</a>
 
 
 
 
 
 
 
 
 
395
  </div>
396
+ <div class="col-md-3">
397
+ <a href="config-check.php" class="btn btn-secondary w-100">配置检查</a>
 
 
 
 
 
 
 
 
398
  </div>
399
+ <div class="col-md-3">
400
+ <a href="editor.html" class="btn btn-success w-100">返回编辑器</a>
 
 
 
 
 
 
 
 
 
 
401
  </div>
 
 
 
 
 
 
 
 
 
 
402
  </div>
403
  </div>
404
  </div>
 
 
405
  </div>
406
  </div>
407
  </div>
408
+
409
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
410
  </body>
411
  </html>
github-save-debug.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once __DIR__ . '/storage.php';
3
+
4
+ // 简单认证
5
+ $testAuth = false;
6
+ if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
7
+ $users = StorageConfig::getUsers();
8
+ $testAuth = isset($users[$_SERVER['PHP_AUTH_USER']]) &&
9
+ $users[$_SERVER['PHP_AUTH_USER']] === $_SERVER['PHP_AUTH_PW'];
10
+ }
11
+
12
+ if (!$testAuth) {
13
+ header('WWW-Authenticate: Basic realm="VvvebJs GitHub Debug"');
14
+ header('HTTP/1.0 401 Unauthorized');
15
+ die('Authentication required');
16
+ }
17
+
18
+ // 获取环境信息
19
+ $isHuggingFace = StorageConfig::isHuggingFaceSpace();
20
+ $github = StorageConfig::getGitHubConfig();
21
+ $envDebug = StorageConfig::debugEnvironment();
22
+
23
+ // 测试保存功能
24
+ $testResults = [];
25
+ if ($_POST['test_save'] ?? false) {
26
+ $testHtml = '<!DOCTYPE html><html><head><title>VvvebJs Test</title></head><body><h1>Test file created at ' . date('Y-m-d H:i:s') . '</h1><p>This is a test file created to verify GitHub save functionality.</p></body></html>';
27
+ $testFilename = 'test-' . time() . '.html';
28
+
29
+ try {
30
+ $storageManager = new StorageManager();
31
+ $result = $storageManager->saveFile($testFilename, $testHtml);
32
+
33
+ $testResults['save_test'] = [
34
+ 'success' => $result,
35
+ 'filename' => $testFilename,
36
+ 'content_length' => strlen($testHtml),
37
+ 'message' => $result ? 'File saved successfully!' : 'Save failed!'
38
+ ];
39
+
40
+ // 立即尝试读取文件验证
41
+ if ($result) {
42
+ $retrievedContent = $storageManager->getFile($testFilename);
43
+ $testResults['read_test'] = [
44
+ 'success' => $retrievedContent !== false,
45
+ 'content_matches' => $retrievedContent === $testHtml,
46
+ 'retrieved_length' => $retrievedContent ? strlen($retrievedContent) : 0
47
+ ];
48
+ }
49
+
50
+ } catch (Exception $e) {
51
+ $testResults['save_test'] = [
52
+ 'success' => false,
53
+ 'error' => $e->getMessage(),
54
+ 'filename' => $testFilename
55
+ ];
56
+ }
57
+ }
58
+ ?>
59
+
60
+ <!DOCTYPE html>
61
+ <html lang="en">
62
+ <head>
63
+ <meta charset="utf-8">
64
+ <meta name="viewport" content="width=device-width, initial-scale=1">
65
+ <title>VvvebJs GitHub 保存调试</title>
66
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
67
+ <style>
68
+ .config-value { background-color: #f8f9fa; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
69
+ .status-ok { color: #28a745; }
70
+ .status-error { color: #dc3545; }
71
+ .status-warning { color: #ffc107; }
72
+ .debug-output { background: #f8f9fa; padding: 15px; border-radius: 5px; font-family: monospace; font-size: 12px; max-height: 400px; overflow-y: auto; }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="container mt-5">
77
+ <div class="row">
78
+ <div class="col-md-10 mx-auto">
79
+ <h1 class="mb-4">🚨 VvvebJs GitHub 保存问题调试</h1>
80
+
81
+ <!-- 环境状态 -->
82
+ <div class="card mb-4">
83
+ <div class="card-header">
84
+ <h3>🌐 环境状态检查</h3>
85
+ </div>
86
+ <div class="card-body">
87
+ <div class="row">
88
+ <div class="col-md-6">
89
+ <p><strong>运行环境:</strong>
90
+ <span class="<?= $isHuggingFace ? 'status-ok' : 'status-warning' ?>">
91
+ <?= $isHuggingFace ? '✅ Hugging Face Space' : '⚠️ 本地环境' ?>
92
+ </span>
93
+ </p>
94
+ <p><strong>主机:</strong> <span class="config-value"><?= htmlspecialchars($_SERVER['HTTP_HOST'] ?? 'unknown') ?></span></p>
95
+ <p><strong>Space ID:</strong> <span class="config-value"><?= htmlspecialchars($envDebug['space_id']) ?></span></p>
96
+ </div>
97
+ <div class="col-md-6">
98
+ <p><strong>当前用户:</strong> <span class="config-value"><?= htmlspecialchars(StorageConfig::getCurrentUser()) ?></span></p>
99
+ <p><strong>用户路径:</strong> <span class="config-value"><?= htmlspecialchars(StorageConfig::getUserPath()) ?></span></p>
100
+ <p><strong>存储类型:</strong> <span class="config-value"><?= htmlspecialchars(StorageConfig::getStorageType()) ?></span></p>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ </div>
105
+
106
+ <!-- GitHub 配置状态 -->
107
+ <div class="card mb-4">
108
+ <div class="card-header">
109
+ <h3>🔧 GitHub 配置状态</h3>
110
+ </div>
111
+ <div class="card-body">
112
+ <div class="row">
113
+ <div class="col-md-6">
114
+ <p><strong>GITHUB_TOKEN:</strong>
115
+ <span class="config-value <?= empty($github['token']) ? 'status-error' : 'status-ok' ?>">
116
+ <?php
117
+ if (empty($github['token'])) {
118
+ echo '❌ 未设置';
119
+ } else {
120
+ echo '✅ 已设置 (长度: ' . strlen($github['token']) . ')';
121
+ }
122
+ ?>
123
+ </span>
124
+ </p>
125
+ <p><strong>GITHUB_OWNER:</strong>
126
+ <span class="config-value <?= empty($github['owner']) ? 'status-error' : 'status-ok' ?>">
127
+ <?= empty($github['owner']) ? '❌ 未设置' : '✅ ' . htmlspecialchars($github['owner']) ?>
128
+ </span>
129
+ </p>
130
+ <p><strong>GITHUB_REPO:</strong>
131
+ <span class="config-value <?= empty($github['repo']) ? 'status-error' : 'status-ok' ?>">
132
+ <?= empty($github['repo']) ? '❌ 未设置' : '✅ ' . htmlspecialchars($github['repo']) ?>
133
+ </span>
134
+ </p>
135
+ </div>
136
+ <div class="col-md-6">
137
+ <p><strong>GITHUB_BRANCH:</strong>
138
+ <span class="config-value"><?= htmlspecialchars($github['branch']) ?></span>
139
+ </p>
140
+ <p><strong>GITHUB_PATH:</strong>
141
+ <span class="config-value"><?= htmlspecialchars($github['path']) ?></span>
142
+ </p>
143
+ <p><strong>完整API URL:</strong>
144
+ <span class="config-value">https://api.github.com/repos/<?= htmlspecialchars($github['owner']) ?>/<?= htmlspecialchars($github['repo']) ?></span>
145
+ </p>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+
151
+ <!-- 保存测试 -->
152
+ <div class="card mb-4">
153
+ <div class="card-header">
154
+ <h3>🧪 实际保存测试</h3>
155
+ </div>
156
+ <div class="card-body">
157
+ <?php if (empty($testResults)): ?>
158
+ <p>点击下方按钮来测试实际的文件保存功能:</p>
159
+ <form method="POST">
160
+ <button type="submit" name="test_save" value="1" class="btn btn-primary">
161
+ 🚀 测试保存到 GitHub
162
+ </button>
163
+ </form>
164
+ <?php else: ?>
165
+ <div class="row">
166
+ <div class="col-md-6">
167
+ <h5>保存测试结果</h5>
168
+ <?php $saveTest = $testResults['save_test']; ?>
169
+ <div class="alert alert-<?= $saveTest['success'] ? 'success' : 'danger' ?>">
170
+ <strong>状态:</strong>
171
+ <span class="<?= $saveTest['success'] ? 'status-ok' : 'status-error' ?>">
172
+ <?= $saveTest['success'] ? '✅ 成功' : '❌ 失败' ?>
173
+ </span>
174
+ <br><strong>文件名:</strong> <?= htmlspecialchars($saveTest['filename']) ?>
175
+ <br><strong>内容长度:</strong> <?= $saveTest['content_length'] ?? 0 ?> 字符
176
+ <?php if (!$saveTest['success'] && isset($saveTest['error'])): ?>
177
+ <br><strong>错误:</strong> <?= htmlspecialchars($saveTest['error']) ?>
178
+ <?php endif; ?>
179
+ </div>
180
+ </div>
181
+ <div class="col-md-6">
182
+ <?php if (isset($testResults['read_test'])): ?>
183
+ <h5>读取验证结果</h5>
184
+ <?php $readTest = $testResults['read_test']; ?>
185
+ <div class="alert alert-<?= $readTest['success'] && $readTest['content_matches'] ? 'success' : 'warning' ?>">
186
+ <strong>读取状态:</strong>
187
+ <span class="<?= $readTest['success'] ? 'status-ok' : 'status-error' ?>">
188
+ <?= $readTest['success'] ? '✅ 成功' : '❌ 失败' ?>
189
+ </span>
190
+ <br><strong>内容匹配:</strong>
191
+ <span class="<?= $readTest['content_matches'] ? 'status-ok' : 'status-error' ?>">
192
+ <?= $readTest['content_matches'] ? '✅ 一致' : '❌ 不一致' ?>
193
+ </span>
194
+ <br><strong>读取长度:</strong> <?= $readTest['retrieved_length'] ?> 字符
195
+ </div>
196
+ <?php endif; ?>
197
+ </div>
198
+ </div>
199
+
200
+ <div class="mt-3">
201
+ <form method="POST">
202
+ <button type="submit" name="test_save" value="1" class="btn btn-secondary">
203
+ 🔄 重新测试
204
+ </button>
205
+ </form>
206
+ </div>
207
+ <?php endif; ?>
208
+ </div>
209
+ </div>
210
+
211
+ <!-- 环境变量调试信息 -->
212
+ <div class="card mb-4">
213
+ <div class="card-header">
214
+ <h3>🔍 环境变量调试信息</h3>
215
+ </div>
216
+ <div class="card-body">
217
+ <div class="debug-output">
218
+ <?= json_encode($envDebug, JSON_PRETTY_PRINT) ?>
219
+ </div>
220
+ </div>
221
+ </div>
222
+
223
+ <!-- 服务器日志信息 -->
224
+ <div class="card mb-4">
225
+ <div class="card-header">
226
+ <h3>📋 最近的服务器日志</h3>
227
+ </div>
228
+ <div class="card-body">
229
+ <p class="text-muted">请检查Hugging Face Space的日志面板查看详细的错误信息。关键日志标识符:</p>
230
+ <ul>
231
+ <li><code>GitHub Save Debug:</code> - GitHub保存调试信息</li>
232
+ <li><code>GitHub Save Error:</code> - GitHub保存错误</li>
233
+ <li><code>GitHub API Error:</code> - GitHub API错误响应</li>
234
+ <li><code>StorageManager saveFile:</code> - 存储管理器保存过程</li>
235
+ </ul>
236
+ </div>
237
+ </div>
238
+
239
+ <!-- 问题诊断建议 -->
240
+ <div class="card mb-4">
241
+ <div class="card-header">
242
+ <h3>💡 常见问题诊断</h3>
243
+ </div>
244
+ <div class="card-body">
245
+ <div class="accordion" id="diagnosticAccordion">
246
+ <div class="accordion-item">
247
+ <h2 class="accordion-header">
248
+ <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#diag1">
249
+ Token 配置问题
250
+ </button>
251
+ </h2>
252
+ <div id="diag1" class="accordion-collapse collapse show" data-bs-parent="#diagnosticAccordion">
253
+ <div class="accordion-body">
254
+ <strong>检查项目:</strong>
255
+ <ul>
256
+ <li>确认 <code>GITHUB_TOKEN</code> 在Hugging Face Space Settings中正确设置为Private Secret</li>
257
+ <li>GitHub Token必须有 <code>repo</code> 权限(不仅是public_repo)</li>
258
+ <li>Token没有过期</li>
259
+ <li>Token对目标仓库有写入权限</li>
260
+ </ul>
261
+ </div>
262
+ </div>
263
+ </div>
264
+ <div class="accordion-item">
265
+ <h2 class="accordion-header">
266
+ <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#diag2">
267
+ 仓库配置问题
268
+ </button>
269
+ </h2>
270
+ <div id="diag2" class="accordion-collapse collapse" data-bs-parent="#diagnosticAccordion">
271
+ <div class="accordion-body">
272
+ <strong>检查项目:</strong>
273
+ <ul>
274
+ <li>仓库名和所有者名称完全正确(区分大小写)</li>
275
+ <li>分支名称正确(通常是main或master)</li>
276
+ <li>目标路径存在或可以创建</li>
277
+ <li>仓库没有分支保护规则阻止直接推送</li>
278
+ </ul>
279
+ </div>
280
+ </div>
281
+ </div>
282
+ <div class="accordion-item">
283
+ <h2 class="accordion-header">
284
+ <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#diag3">
285
+ Hugging Face Space 特殊情况
286
+ </button>
287
+ </h2>
288
+ <div id="diag3" class="accordion-collapse collapse" data-bs-parent="#diagnosticAccordion">
289
+ <div class="accordion-body">
290
+ <strong>可能的问题:</strong>
291
+ <ul>
292
+ <li>环境变量需要在设置后重启Space才能生效</li>
293
+ <li>网络限制或超时问题</li>
294
+ <li>Space的文件系统权限限制</li>
295
+ <li>GitHub API速率限制</li>
296
+ </ul>
297
+ <strong>解决方案:</strong>
298
+ <ul>
299
+ <li>确保点击了"Restart this Space"</li>
300
+ <li>检查所有环境变量拼写正确</li>
301
+ <li>使用GitHub Personal Access Token (classic)</li>
302
+ </ul>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ </div>
307
+ </div>
308
+ </div>
309
+
310
+ <!-- 操作按钮 -->
311
+ <div class="card">
312
+ <div class="card-body text-center">
313
+ <div class="row">
314
+ <div class="col-md-3">
315
+ <a href="hf-space-check.php" class="btn btn-info w-100">HF Space 检查</a>
316
+ </div>
317
+ <div class="col-md-3">
318
+ <a href="github-advanced-test.php" class="btn btn-primary w-100">GitHub 完整测试</a>
319
+ </div>
320
+ <div class="col-md-3">
321
+ <a href="config-check.php" class="btn btn-secondary w-100">配置检查</a>
322
+ </div>
323
+ <div class="col-md-3">
324
+ <a href="editor.html" class="btn btn-success w-100">返回编辑器</a>
325
+ </div>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+ </div>
331
+ </div>
332
+
333
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
334
+ </body>
335
+ </html>
storage.php CHANGED
@@ -387,6 +387,15 @@ class GitHubStorage {
387
  $url = "https://api.github.com/repos/{$this->config['owner']}/{$this->config['repo']}/contents/{$path}";
388
 
389
  error_log("GitHub Save Debug: Attempting to save to $url on branch '{$this->config['branch']}' for user '{$this->userPath}'");
 
 
 
 
 
 
 
 
 
390
 
391
  // Get current file SHA if exists
392
  $sha = $this->getFileSHA($path);
@@ -404,10 +413,13 @@ class GitHubStorage {
404
  error_log("GitHub Save Debug: Creating new file");
405
  }
406
 
 
 
407
  $result = $this->makeRequest($url, 'PUT', $data);
408
 
409
  if ($result) {
410
  error_log("GitHub Save Success: File saved successfully");
 
411
  return true;
412
  } else {
413
  error_log("GitHub Save Error: API request failed");
@@ -415,6 +427,36 @@ class GitHubStorage {
415
  }
416
  }
417
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
  public function get($filename) {
419
  if (empty($this->config['token'])) return false;
420
 
 
387
  $url = "https://api.github.com/repos/{$this->config['owner']}/{$this->config['repo']}/contents/{$path}";
388
 
389
  error_log("GitHub Save Debug: Attempting to save to $url on branch '{$this->config['branch']}' for user '{$this->userPath}'");
390
+ error_log("GitHub Save Debug: Token length: " . strlen($this->config['token']));
391
+ error_log("GitHub Save Debug: Owner: " . $this->config['owner']);
392
+ error_log("GitHub Save Debug: Repo: " . $this->config['repo']);
393
+ error_log("GitHub Save Debug: Branch: " . $this->config['branch']);
394
+ error_log("GitHub Save Debug: User path: " . $this->userPath);
395
+ error_log("GitHub Save Debug: Full path: " . $path);
396
+
397
+ // 首次保存时,先尝试创建用户目录的 README.md 文件
398
+ $this->ensureUserDirectoryExists();
399
 
400
  // Get current file SHA if exists
401
  $sha = $this->getFileSHA($path);
 
413
  error_log("GitHub Save Debug: Creating new file");
414
  }
415
 
416
+ error_log("GitHub Save Debug: Request data: " . json_encode(array_merge($data, ['content' => '[BASE64_CONTENT_' . strlen($data['content']) . '_CHARS]'])));
417
+
418
  $result = $this->makeRequest($url, 'PUT', $data);
419
 
420
  if ($result) {
421
  error_log("GitHub Save Success: File saved successfully");
422
+ error_log("GitHub Save Success: Response: " . json_encode($result));
423
  return true;
424
  } else {
425
  error_log("GitHub Save Error: API request failed");
 
427
  }
428
  }
429
 
430
+ // 新增方法:确保用户目录存在
431
+ private function ensureUserDirectoryExists() {
432
+ $userDirPath = $this->config['path'] . $this->userPath;
433
+ $readmePath = $userDirPath . 'README.md';
434
+ $readmeUrl = "https://api.github.com/repos/{$this->config['owner']}/{$this->config['repo']}/contents/{$readmePath}";
435
+
436
+ // 检查 README.md 是否存在(用来确认目录是否存在)
437
+ $existing = $this->makeRequest($readmeUrl, 'GET');
438
+
439
+ if (!$existing) {
440
+ // 目录不存在,创建 README.md 文件来建立目录
441
+ $readmeContent = "# User Files for " . trim($this->userPath, '/') . "\n\nThis directory contains HTML files created by VvvebJs web builder.\n\nCreated: " . date('Y-m-d H:i:s') . " UTC";
442
+
443
+ $readmeData = [
444
+ 'message' => "Create user directory for " . trim($this->userPath, '/'),
445
+ 'content' => base64_encode($readmeContent),
446
+ 'branch' => $this->config['branch']
447
+ ];
448
+
449
+ error_log("GitHub Save Debug: Creating user directory with README.md at: $readmePath");
450
+ $result = $this->makeRequest($readmeUrl, 'PUT', $readmeData);
451
+
452
+ if ($result) {
453
+ error_log("GitHub Save Success: User directory created successfully");
454
+ } else {
455
+ error_log("GitHub Save Warning: Failed to create user directory, but will continue with file save");
456
+ }
457
+ }
458
+ }
459
+
460
  public function get($filename) {
461
  if (empty($this->config['token'])) return false;
462