本文目录导读:

我来详细介绍PHP SaaS启动器的搭建方案:
架构选择
基础架构
// 项目结构 saas-starter/ ├── app/ │ ├── Core/ │ │ ├── Database.php │ │ ├── Tenant.php │ │ └── Router.php │ ├── Models/ │ ├── Controllers/ │ └── Services/ ├── config/ ├── database/ ├── public/ └── tenant/
多租户架构实现
数据库配置
// app/Core/Database.php
class Database {
private static $connections = [];
public static function getConnection($tenantId = null) {
if ($tenantId) {
if (!isset(self::$connections[$tenantId])) {
$config = Tenant::getDatabaseConfig($tenantId);
self::$connections[$tenantId] = new PDO(
"mysql:host={$config['host']};dbname={$config['dbname']}",
$config['username'],
$config['password']
);
}
return self::$connections[$tenantId];
}
return self::getDefaultConnection();
}
}
租户管理类
// app/Core/Tenant.php
class Tenant {
private $id;
private $domain;
private $config;
public function __construct() {
$this->identify();
}
private function identify() {
// 1. 通过域名识别
$domain = $_SERVER['HTTP_HOST'];
// 2. 查询租户信息
$pdo = Database::getDefaultConnection();
$stmt = $pdo->prepare("SELECT * FROM tenants WHERE domain = ?");
$stmt->execute([$domain]);
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tenant) {
$this->id = $tenant['id'];
$this->config = $tenant;
}
}
public function getDatabaseName() {
return "tenant_{$this->id}";
}
public function getTablePrefix() {
return "t{$this->id}_";
}
}
三种多租户策略
单数据库单Schema
// 方式一:每个租户独立数据库
class TenantDatabase {
public function createSchema($tenantId) {
$dbname = "tenant_{$tenantId}";
$pdo->exec("CREATE DATABASE IF NOT EXISTS {$dbname}");
// 运行迁移脚本
$this->runMigrations($dbname);
}
}
共享数据库独立Schema
// 方式二:共享数据库,独立Schema
class SharedDatabase {
public function createSchema($tenantId) {
$schema = "tenant_{$tenantId}";
$pdo->exec("CREATE SCHEMA IF NOT EXISTS {$schema}");
$pdo->exec("CREATE TABLE {$schema}.users (id INT, name VARCHAR(100))");
}
}
共享表和租户ID
// 方式三:共享表,使用租户ID区分
class SharedTable {
private $tenantId;
public function query($sql, $params = []) {
$sql = str_replace('{{tenant_id}}', $this->tenantId, $sql);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
public function getUsers() {
return $this->query("SELECT * FROM users WHERE tenant_id = {{tenant_id}}");
}
}
路由和中间件
// app/Core/Router.php
class Router {
private static $routes = [];
public static function add($method, $path, $handler, $middleware = []) {
self::$routes[] = [
'method' => $method,
'path' => $path,
'handler' => $handler,
'middleware' => $middleware
];
}
public static function dispatch() {
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
foreach (self::$routes as $route) {
if ($route['method'] === $method && preg_match("#^{$route['path']}$#", $uri, $matches)) {
// 执行中间件
foreach ($route['middleware'] as $middleware) {
$result = $middleware();
if ($result) continue;
return;
}
// 调用控制器
return call_user_func_array($route['handler'], $matches);
}
}
}
}
// 使用
Router::add('GET', '/users', 'UserController@index', [
'auth',
'tenant.check'
]);
认证和授权
// app/Services/AuthService.php
class AuthService {
public function login($email, $password, $tenantId) {
// 检查用户存在
$pdo = Database::getConnection($tenantId);
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
// 验证密码
if (password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['tenant_id'] = $tenantId;
// 生成JWT token
$token = $this->generateJWT($user);
return $token;
}
return false;
}
public function check() {
return isset($_SESSION['user_id']);
}
}
自动化部署
#!/bin/bash
# scripts/deploy.sh
# 1. 创建租户目录
if [ ! -d "tenant/$TENANT_ID" ]; then
mkdir -p "tenant/$TENANT_ID"
# 2. 复制公共文件
cp -r public/ tenant/$TENANT_ID/
# 3. 修改配置文件
sed -i "s/TENANT_ID/$TENANT_ID/" tenant/$TENANT_ID/config.php
# 4. 创建数据库
mysql -u root -p -e "CREATE DATABASE tenant_$TENANT_ID"
fi
# 5. 运行迁移
php artisan migrate --tenant=$TENANT_ID
租户注册流程
// app/Controllers/TenantController.php
class TenantController {
public function register() {
// 1. 验证数据
$data = $this->validate();
// 2. 创建租户记录
$tenantId = $this->createTenant($data);
// 3. 创建数据库/Schema
$this->createDatabase($tenantId);
// 4. 运行迁移
$this->runMigrations($tenantId);
// 5. 创建管理员账号
$this->createAdminUser($tenantId, $data);
// 6. 配置域名
$this->setupDomain($tenantId, $data['domain']);
return redirect("/login?tenant={$tenantId}");
}
}
高级功能
队列处理
// app/Services/QueueService.php
class QueueService {
public function dispatch($job, $data, $tenantId) {
// 使用Redis队列
$this->redis->lpush("tenant:{$tenantId}:jobs", json_encode([
'job' => $job,
'data' => $data
]));
}
public function process($tenantId) {
while ($job = $this->redis->rpop("tenant:{$tenantId}:jobs")) {
$jobData = json_decode($job, true);
$this->execute($jobData['job'], $jobData['data']);
}
}
}
缓存管理
// app/Services/CacheService.php
class CacheService {
private $prefix;
public function __construct($tenantId) {
$this->prefix = "tenant:{$tenantId}:";
}
public function get($key) {
return $this->redis->get($this->prefix . $key);
}
public function set($key, $value, $ttl = null) {
$key = $this->prefix . $key;
if ($ttl) {
return $this->redis->setex($key, $ttl, $value);
}
return $this->redis->set($key, $value);
}
}
配置文件
// config/tenant.php
return [
'mode' => 'multi_db', // multi_db | shared_schema | shared_table
'database_driver' => 'mysql',
'auto_create_database' => true,
'auto_run_migrations' => true,
'cors' => [
'allowed_origins' => ['*'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE']
],
'limits' => [
'max_users' => 100,
'max_storage' => '1GB',
'max_domains' => 3
],
'features' => [
'api_access' => true,
'white_label' => false,
'advanced_reporting' => false
]
];
监控系统
// app/Services/MonitorService.php
class MonitorService {
public function track($tenantId, $action) {
// 记录租户活动
$data = [
'tenant_id' => $tenantId,
'action' => $action,
'time' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR']
];
$this->logToDatabase($data);
}
public function getUsage($tenantId) {
return [
'database_size' => $this->getDatabaseSize($tenantId),
'api_calls' => $this->getApiCalls($tenantId),
'users' => $this->getUserCount($tenantId),
'storage' => $this->getStorageUsage($tenantId)
];
}
}
部署和管理
# 管理命令 php artisan tenant:create --name=company1 --domain=company1.example.com php artisan tenant:migrate --id=1 php artisan tenant:seed --id=1 --role=admin php artisan tenant:backup --id=1 php artisan tenant:restore --id=1 --backup=2023-01-01
最佳实践建议
- 隔离性:确保租户数据完全隔离,包括数据库、缓存、文件系统
- 可扩展性:设计时考虑水平扩展,如分库分表
- 安全性:使用SSL、密码哈希、SQL注入防护
- 性能优化:使用缓存、数据库索引、查询优化
- 监控告警:实施租户资源使用监控和告警机制
- 计费系统:集成计费、订阅管理、用量统计
这个PHP SaaS启动器提供了完整的多租户支持,可以根据实际需求选择合适的架构方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播