PHP房屋租赁平台开发实践
技术架构选型
构建房屋租赁平台时,推荐采用以下技术组合:
服务端方案
- 运行环境:PHP 8.0+(强类型特性与性能提升)
- 开发框架:ThinkPHP 6 或 Yii2(国内生态友好)
- 数据持久化:MySQL 8.0 / PostgreSQL
- Web服务器:Nginx(配合PHP-FPM)
客户端方案
- 响应式布局:Tailwind CSS / Element UI
- 脚本引擎:原生JavaScript ES6+ 或 TypeScript
- 移动端适配:uni-app(跨端开发)
第三方服务集成
- 实名认证:阿里云金融级实人认证
- 电子合同:e签宝/法大大API
- 消息推送:极光推送/个推
- 对象存储:七牛云Kodo/腾讯云COS
核心业务模块
租户与房东体系
采用多角色权限设计,支持手机号一键登录与微信授权登录:
// 多角色登录控制器(ThinkPHP风格)
namespace app\controller;
use think\Request;
use app\service\AccountService;
class PassportController
{
protected $accountSvc;
public function __construct(AccountService $svc)
{
$this->accountSvc = $svc;
}
public function loginByMobile(Request $req)
{
$payload = $req->validate([
'mobile' => 'require|mobile',
'sms_code' => 'require|length:6',
'role' => 'in:tenant,landlord,admin'
]);
$token = $this->accountSvc->authenticate(
$payload['mobile'],
$payload['sms_code'],
$payload['role'] ?? 'tenant'
);
return json(['access_token' => $token, 'expires_in' => 7200]);
}
}
角色功能划分:
- 租户端:房源检索、VR看房预约、租金代缴、报修工单
- 房东端:房源挂牌、租客筛选、收租提醒、合同管理
- 运营端:资质审核、纠纷仲裁、数据大盘、风控策略
房源信息引擎
实现基于Elasticsearch的分布式搜索,支持Geo距离排序:
// 房源检索服务层
class DwellingSearchService
{
public function nearbyQuery(float $lng, float $lat, array $filters)
{
$must = [];
// 地理距离过滤:5公里半径
$must[] = [
'geo_distance' => [
'distance' => '5km',
'location' => ['lon' => $lng, 'lat' => $lat]
]
];
// 动态条件组合
if (!empty($filters['monthly_rent'])) {
$range = explode('-', $filters['monthly_rent']);
$must[] = [
'range' => [
'rent_monthly' => [
'gte' => $range[0] * 100,
'lte' => $range[1] * 100
]
]
];
}
return $this->esClient->search([
'index' => 'dwellings',
'body' => ['query' => ['bool' => ['must' => $must]]],
'sort' => [
'_geo_distance' => [
'location' => "$lat,$lng",
'order' => 'asc',
'unit' => 'km'
]
]
]);
}
}
租约与资金流转
设计状态机驱动的租约生命周期,集成分账系统保障资金安全:
| 状态节点 | 触发条件 | 资金操作 |
|---|---|---|
| 意向金冻结 | 提交看房申请 | 第三方支付预授权 |
| 押金托管 | 电子合同签署 | 资金进入监管账户 |
| 租金分账 | 账期自动结算 | T+1结算至房东 |
| 押金退还 | 验收无争议 | 原路退回租户 |
数据模型设计
核心实体关系采用租赁行业通用建模:
-- 房源主表(支持多户型拆分)
CREATE TABLE `dwelling_units` (
`unit_id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '房源编码',
`estate_id` bigint UNSIGNED NOT NULL COMMENT '所属小区',
`landlord_uid` bigint UNSIGNED NOT NULL COMMENT '产权人',
`unit_type` tinyint NOT NULL DEFAULT 1 COMMENT '1整租 2合租 3公寓',
`layout` varchar(10) NOT NULL COMMENT '户型如2室1厅',
`floor_area` decimal(6,2) UNSIGNED NOT NULL COMMENT '建筑面积㎡',
`orientation` set('E','S','W','N','ES','EN','WS','WN') DEFAULT NULL,
`monthly_price` int UNSIGNED NOT NULL COMMENT '月租金(分)',
`deposit_months` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '押几',
`pay_months` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '付几',
`facilities` json COMMENT '配套设施{wifi:1,ac:1...}',
`geo_hash` varchar(12) NOT NULL COMMENT '地理哈希',
`listing_status` tinyint NOT NULL DEFAULT 0 COMMENT '0下架 1上架 2已租',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`unit_id`),
KEY `idx_geo` (`geo_hash`),
KEY `idx_price` (`monthly_price`),
FULLTEXT KEY `idx_facility` (`facilities`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房源信息表';
-- 租约订单表(支持周期性任务)
CREATE TABLE `lease_agreements` (
`agreement_no` char(20) NOT NULL COMMENT '合同编号',
`unit_id` bigint UNSIGNED NOT NULL,
`tenant_uid` bigint UNSIGNED NOT NULL,
`lease_start` date NOT NULL,
`lease_end` date NOT NULL,
`rent_total` int UNSIGNED NOT NULL COMMENT '合同总额',
`payment_cycle` tinyint NOT NULL DEFAULT 1 COMMENT '月付/季付/年付',
`next_bill_date` date NOT NULL COMMENT '下次账单日',
`agreement_status` tinyint NOT NULL DEFAULT 0 COMMENT '0待签 1生效 2到期 3提前解约',
`pdf_url` varchar(255) DEFAULT NULL COMMENT '电子合同存档',
PRIMARY KEY (`agreement_no`),
KEY `idx_tenant` (`tenant_uid`,`agreement_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
工程化实践要点
安全防护策略
- 数据层:PDO参数化查询 + 数据库账号最小权限原则
- 传输层:TLS 1.3强制加密,敏感接口限流(令牌桶算法)
- 业务层:敏感操作二次验证(人脸识别/短信确认)
- 审计层:操作日志异步写入ClickHouse,支持行为溯源
// 图片上传安全处理(白名单+魔数校验)
public function uploadDwellingImage($file)
{
$allowedTypes = ['image/jpeg' => 'jpg', 'image/webp' => 'webp'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file->getPathname());
finfo_close($finfo);
if (!isset($allowedTypes[$mime])) {
throw new SecurityException('文件类型未授权');
}
// 重命名并迁移至私有存储桶
$objectKey = 'dwellings/' . date('Ym') . '/' . uuid() . '.' . $allowedTypes[$mime];
$this->ossClient->putObject($this->bucket, $objectKey, file_get_contents($file->getPathname()));
return $this->cdnDomain . '/' . $objectKey;
}
高可用优化
- 查询优化:热点数据多级缓存(OPcache → Redis → ES)
- 写入优化:账单生成等定时任务采用消息队列(RabbitMQ)异步处理
- 静态资源:CDN边缘节点缓存,图片自适应WebP格式
- 数据库:读写分离配置,慢查询自动告警
部署与运维
推荐容器化部署方案:
# docker-compose 生产配置片段
services:
php-fpm:
build: ./docker/php
volumes:
- ./:/var/www/html:ro
environment:
- APP_ENV=production
- DB_POOL_SIZE=20
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/ssl:/etc/nginx/ssl:ro
redis-cluster:
image: grokzen/redis-cluster:6.2
queue-worker:
build: ./docker/php
command: php think queue:work --queue=lease,bill,notice --sleep=3