diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5501035 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# 依赖 +/vendor/ + +# 测试缓存 +/.phpunit.cache/ +/coverage/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# 系统文件 +.DS_Store +Thumbs.db + +# 环境配置 +.env +.env.local +config.local.php + +# 用户数据目录 (每个用户独立) +/*/ + +# 但保留这些目录 +!/deploy/ +!/tests/ +!/src/ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b1b6931 --- /dev/null +++ b/composer.json @@ -0,0 +1,25 @@ +{ + "name": "starmen1265/kb-web", + "description": "知识库网页系统", + "type": "project", + "require": { + "php": ">=8.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "scripts": { + "test": "phpunit --testdox", + "test:coverage": "phpunit --coverage-html coverage" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..ab8f628 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,23 @@ + + + + + tests/Unit + + + tests/Feature + + + + + src + . + vendor + tests + + + diff --git a/tests/Feature/SecurityTest.php b/tests/Feature/SecurityTest.php new file mode 100644 index 0000000..2f8e733 --- /dev/null +++ b/tests/Feature/SecurityTest.php @@ -0,0 +1,65 @@ +assertStringNotContainsString('123456', $config, '配置中不应包含简单密码'); + $this->assertStringNotContainsString('password', strtolower($config), '配置中不应包含 password 字符串'); + } + + /** + * 测试 SQL 注入防护 + */ + public function testConfigUsesPreparedStatements(): void + { + $config = file_get_contents(__DIR__ . '/../../config.php'); + + // 确保使用 PDO 预处理 + $this->assertStringContainsString('prepare', $config, '应该使用 PDO 预处理语句'); + $this->assertStringContainsString('execute', $config, '应该使用 execute 执行预处理'); + } + + /** + * 测试 XSS 防护 + */ + public function testOutputUsesHtmlspecialchars(): void + { + $files = [ + __DIR__ . '/../../dashboard.php', + __DIR__ . '/../../view.php', + ]; + + foreach ($files as $file) { + if (file_exists($file)) { + $content = file_get_contents($file); + $this->assertStringContainsString('htmlspecialchars', $content, + basename($file) . ' 应该使用 htmlspecialchars 防止 XSS'); + } + } + } + + /** + * 测试 Session 安全 + */ + public function testSessionSecurity(): void + { + $config = file_get_contents(__DIR__ . '/../../config.php'); + + // 确保有 session 检查 + $this->assertStringContainsString('session', strtolower($config), '应该有 session 相关配置'); + } +} diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php new file mode 100644 index 0000000..2f7fd5a --- /dev/null +++ b/tests/Unit/ConfigTest.php @@ -0,0 +1,51 @@ +assertFileExists(__DIR__ . '/../../config.php', '配置文件应该存在'); + } + + /** + * 测试样式文件存在 + */ + public function testStyleFileExists(): void + { + $this->assertFileExists(__DIR__ . '/../../style.css', '样式文件应该存在'); + } + + /** + * 测试入口文件存在 + */ + public function testIndexFileExists(): void + { + $this->assertFileExists(__DIR__ . '/../../index.php', '入口文件应该存在'); + } + + /** + * 测试仪表盘文件存在 + */ + public function testDashboardFileExists(): void + { + $this->assertFileExists(__DIR__ . '/../../dashboard.php', '仪表盘文件应该存在'); + } + + /** + * 测试查看文件存在 + */ + public function testViewFileExists(): void + { + $this->assertFileExists(__DIR__ . '/../../view.php', '查看文件应该存在'); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..1b556a9 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,18 @@ +