本文目录导读:

针对PHP项目跨小程序数据互通查询,核心在于统一用户身份标识和设计合理的数据共享架构,以下是完整的解决方案:
核心难点分析
不同小程序的用户体系独立(openid不同),需要解决:
- 用户身份统一(同一个人在不同小程序中的身份绑定)
- 数据权限控制
- 实时数据同步
关键解决方案
统一用户标识(UnionID机制)
微信小程序方案
// 用户登录时获取UnionID(需微信开放平台)
public function login($code, $appid) {
$wxApi = new WechatAPI();
$session = $wxApi->getSessionKey($code, $appid);
// 获取unionid
$unionid = $session['unionid'] ?? '';
// 根据unionid查询或创建统一用户
$user = UserModel::where('unionid', $unionid)->first();
if (!$user) {
$user = UserModel::create([
'unionid' => $unionid,
'openid_' . $appid => $session['openid'],
'nickname' => '新用户'
]);
}
return $user->token;
}
数据架构设计
-- 统一用户表
CREATE TABLE unified_users (
id INT PRIMARY KEY AUTO_INCREMENT,
unionid VARCHAR(64) UNIQUE,
phone VARCHAR(20),
email VARCHAR(100),
created_at TIMESTAMP
);
-- 小程序用户关联表
CREATE TABLE mini_program_users (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT FOREIGN KEY REFERENCES unified_users(id),
appid VARCHAR(32),
openid VARCHAR(64) UNIQUE,
platform VARCHAR(20), -- 'wechat', 'alipay', 'baidu'
created_at TIMESTAMP
);
-- 跨小程序数据表(以订单为例)
CREATE TABLE shared_orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT FOREIGN KEY REFERENCES unified_users(id),
order_no VARCHAR(64) UNIQUE,
amount DECIMAL(10,2),
source_appid VARCHAR(32),
status TINYINT,
created_at TIMESTAMP
);
数据查询API设计
// 跨小程序查询接口
class DataQueryController {
// 查询用户所有小程序的订单
public function queryOrders() {
$userId = $this->getUserIdFromToken();
// 跨小程序数据查询(统一用户ID)
$orders = SharedOrderModel::where('user_id', $userId)
->select('order_no', 'amount', 'status', 'source_appid')
->orderBy('created_at', 'desc')
->get();
return response()->json([
'code' => 0,
'data' => $orders
]);
}
// 按条件查询
public function queryByCondition($params) {
$userId = $this->getUserIdFromToken();
$query = SharedOrderModel::where('user_id', $userId);
// 支持按小程序来源查询
if (!empty($params['appid'])) {
$query->where('source_appid', $params['appid']);
}
// 支持按时间范围查询
if (!empty($params['start_date'])) {
$query->where('created_at', '>=', $params['start_date']);
}
return $query->get();
}
}
实时数据同步方案
消息队列(推荐)
// 数据变更事件
class DataSyncEvent {
public function handle($data) {
// 发送到消息队列
RabbitMQ::publish('data_sync', [
'user_id' => $data['user_id'],
'type' => 'order',
'action' => 'create',
'payload' => $data
]);
}
}
// 消费者处理
class DataSyncConsumer {
public function process($message) {
// 同步到所有相关小程序的数据表
foreach ($message['appids'] as $appid) {
$this->syncToApp($appid, $message);
}
}
}
数据库视图
-- 创建跨小程序查询视图
CREATE VIEW user_orders_view AS
SELECT
uo.user_id,
uo.order_no,
uo.amount,
uo.status,
'app1' as source
FROM app1_orders uo
UNION ALL
SELECT
uo.user_id,
uo.order_no,
uo.amount,
uo.status,
'app2' as source
FROM app2_orders uo;
缓存优化
// 使用Redis缓存跨小程序数据
class DataCacheService {
private $redis;
// 缓存用户所有小程序的数据
public function cacheUserData($userId, $data) {
$key = "user:{$userId}:cross_data";
$this->redis->setex($key, 3600, json_encode($data));
}
// 分片查询优化
public function queryWithCache($userId, $page, $size) {
$key = "user:{$userId}:cross_data:{$page}";
if ($cached = $this->redis->get($key)) {
return json_decode($cached, true);
}
$data = DB::table('shared_orders')
->where('user_id', $userId)
->paginate($size);
$this->redis->setex($key, 300, json_encode($data));
return $data;
}
}
权限与安全
class DataPermissionCheck {
// 跨小程序数据访问权限验证
public function validateAccess($requestAppId, $targetUserId) {
// 1. 获取当前用户
$currentUser = $this->getCurrentUser();
// 2. 检查是否关联
$relation = MiniProgramUser::where('user_id', $currentUser->id)
->where('appid', $requestAppId)
->first();
if (!$relation) {
throw new \Exception('无权访问该小程序数据');
}
// 3. 检查数据归属
if ($currentUser->id !== $targetUserId) {
throw new \Exception('无权访问其他用户数据');
}
return true;
}
}
完整示例代码
// 跨小程序订单查询完整实现
class CrossMiniProgramService {
// 获取用户跨小程序订单列表
public function getCrossOrders($userId, $params = []) {
// 1. 验证用户身份
$user = UserModel::findOrFail($userId);
// 2. 构建查询
$query = SharedOrderModel::where('user_id', $user->id);
// 3. 过滤条件
if (!empty($params['appid'])) {
$query->where('source_appid', $params['appid']);
}
if (!empty($params['status'])) {
$query->where('status', $params['status']);
}
// 4. 排序与分页
$orders = $query->orderBy('created_at', 'desc')
->paginate($params['page_size'] ?? 10);
// 5. 格式化输出
return [
'list' => $orders->items(),
'total' => $orders->total(),
'has_more' => $orders->hasMorePages()
];
}
// 同步数据到其他小程序
public function syncDataToApps($userId, $data, $type) {
// 获取用户绑定的所有小程序
$apps = MiniProgramUser::where('user_id', $userId)->get();
foreach ($apps as $app) {
// 调用各小程序API同步数据
$this->callMiniProgramAPI($app->appid, $data, $type);
}
}
}
推荐方案
| 场景 | 推荐方案 | 优点 |
|---|---|---|
| 小规模数据(<10万) | 数据库视图 + 统一用户 | 实现简单,维护方便 |
| 中等规模(10-100万) | 消息队列同步 + Redis缓存 | 性能好,实时性高 |
| 大规模(>100万) | 分库分表 + Elasticsearch | 扩展性强,查询效率高 |
注意事项
- UnionID获取:需要在微信开放平台绑定所有小程序
- 数据一致性:使用事务或最终一致性方案
- 性能优化:合理使用缓存,避免全表扫描
- 安全防护:严格验证跨域请求和数据权限
- 版本兼容:API设计时考虑向后兼容
通过以上方案,可以高效实现PHP项目中跨小程序数据的互通查询,根据实际业务规模选择合适的架构方案。