加密token

This commit is contained in:
Developer
2026-04-17 07:00:26 +08:00
parent 08dce0aed0
commit 20fb06cac9
176 changed files with 33424 additions and 3565 deletions

610
docs/api/kitchen.php Normal file
View File

@@ -0,0 +1,610 @@
<?php
/**
* 🍽️ 点餐助手API接口
*
* 支持点单CRUD操作JSON文件存储SSE实时推送
* 独立API文件直接访问: /api/kitchen.php?act=xxx
*
* 接口列表:
* GET ?act=create 创建点单POST优先
* POST ?act=create 创建点单JSON body
* GET ?act=get&id=xxx 获取点单
* POST ?act=update 更新点单
* GET ?act=list 点单列表
* GET ?act=delete&id=xxx 删除点单
* GET ?act=cleanup 清理过期数据
* GET ?act=index 接口说明
*
* @file kitchen.php
* @date 2026-04-17
* @version 1.0.0
* @desc 点餐助手API支持CRUD、SSE推送、过期清理
* @lastUpdate 2026-04-17 新增clear_all接口确保只清理kitchen数据
*/
// ─── CORS预检请求处理 ───
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Max-Age: 86400');
http_response_code(204);
exit;
}
$startTime = microtime(true);
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
// ─── POST请求参数解析 ───
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$postData = array();
if (stripos($contentType, 'application/json') !== false) {
$rawBody = file_get_contents('php://input');
$json = json_decode($rawBody, true);
if (is_array($json)) {
$postData = $json;
}
} else {
$postData = $_POST;
}
foreach ($postData as $key => $value) {
if (!isset($_GET[$key])) {
$_GET[$key] = $value;
}
}
}
$act = strtolower(trim($_GET['act'] ?? 'index'));
// ─── 数据目录配置 ───
$dataDir = dirname(__FILE__) . '/cache/kitchen/';
if (!is_dir($dataDir)) {
if (!@mkdir($dataDir, 0755, true)) {
$tmpDir = sys_get_temp_dir() . '/kitchen/';
if (!is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$dataDir = $tmpDir;
}
}
if (!is_writable($dataDir)) {
$tmpDir = sys_get_temp_dir() . '/kitchen/';
if (!is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$dataDir = $tmpDir;
}
$ordersFile = $dataDir . 'orders.json';
$counterFile = $dataDir . 'counter.json';
$updateFlagFile = $dataDir . 'last_update.json';
// ─── 默认过期天数 ───
$defaultExpireDays = 30;
// ─── 路由分发 ───
$result = array();
switch ($act) {
case 'create':
$result = create_order();
break;
case 'get':
$result = get_order();
break;
case 'update':
$result = update_order();
break;
case 'list':
$result = list_orders();
break;
case 'delete':
$result = delete_order();
break;
case 'cleanup':
$result = cleanup_expired();
break;
case 'clear_all':
$result = clear_all_orders();
break;
case 'stats':
$result = get_stats();
break;
case 'index':
default:
$result = array(
'code' => 200,
'message' => '🍽️ 点餐助手API',
'data' => array(
'version' => '1.0.0',
'description' => '点单CRUD操作JSON文件存储SSE实时推送',
'endpoints' => array(
'create' => 'POST ?act=create {order JSON}',
'get' => 'GET ?act=get&id=订单ID',
'update' => 'POST ?act=update {order JSON}',
'list' => 'GET ?act=list&page=1&limit=20&status=0',
'delete' => 'GET ?act=delete&id=订单ID',
'cleanup' => 'GET ?act=cleanup&days=30',
'clear_all' => 'POST ?act=clear_all&confirm=yes',
'stats' => 'GET ?act=stats',
'sse' => 'GET kitchen_sse.php?order_id=xxx',
),
'storage' => 'JSON文件 (' . $ordersFile . ')',
'expire' => $defaultExpireDays . '天',
)
);
break;
}
$result['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
// ══════════════════════════════════════════════════════════════
// 数据读写函数
// ══════════════════════════════════════════════════════════════
/**
* 读取所有订单数据
*/
function read_orders() {
global $ordersFile;
if (!file_exists($ordersFile)) {
return array();
}
$content = file_get_contents($ordersFile);
$data = json_decode($content, true);
return is_array($data) ? $data : array();
}
/**
* 写入所有订单数据(文件锁)
*/
function write_orders($orders) {
global $ordersFile;
$fp = fopen($ordersFile, 'c');
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, json_encode($orders, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
flock($fp, LOCK_UN);
}
fclose($fp);
touch_update_flag();
}
/**
* 读取计数器
*/
function read_counter() {
global $counterFile;
if (!file_exists($counterFile)) {
return array('total' => 0, 'today' => 0, 'today_date' => date('Y-m-d'));
}
$content = file_get_contents($counterFile);
$data = json_decode($content, true);
return is_array($data) ? $data : array('total' => 0, 'today' => 0, 'today_date' => date('Y-m-d'));
}
/**
* 写入计数器
*/
function write_counter($counter) {
global $counterFile;
file_put_contents($counterFile, json_encode($counter, JSON_UNESCAPED_UNICODE));
}
/**
* 更新SSE推送标记
*/
function touch_update_flag() {
global $updateFlagFile;
$data = array(
'timestamp' => microtime(true),
'time' => date('Y-m-d H:i:s'),
);
file_put_contents($updateFlagFile, json_encode($data));
}
/**
* 递增计数器
*/
function increment_counter() {
$counter = read_counter();
$today = date('Y-m-d');
if ($counter['today_date'] !== $today) {
$counter['today'] = 0;
$counter['today_date'] = $today;
}
$counter['total']++;
$counter['today']++;
write_counter($counter);
return $counter;
}
// ══════════════════════════════════════════════════════════════
// CRUD函数
// ══════════════════════════════════════════════════════════════
/**
* 创建点单
* POST ?act=create
* Body: {order JSON}
*/
function create_order() {
$orderJson = $_GET['order'] ?? $_GET['data'] ?? null;
if ($orderJson === null) {
$rawBody = file_get_contents('php://input');
$orderData = json_decode($rawBody, true);
} else {
$orderData = json_decode($orderJson, true);
}
if (!is_array($orderData)) {
return array('code' => 400, 'message' => '无效的订单数据需要JSON格式');
}
// 补全字段
if (empty($orderData['id'])) {
$orderData['id'] = uniqid('ord_', true);
}
if (empty($orderData['orderNo'])) {
$orderData['orderNo'] = generate_order_no();
}
if (!isset($orderData['status'])) {
$orderData['status'] = 1; // active
}
if (empty($orderData['createdAt'])) {
$orderData['createdAt'] = date('c');
}
if (empty($orderData['updatedAt'])) {
$orderData['updatedAt'] = date('c');
}
if (empty($orderData['createdBy'])) {
$orderData['createdBy'] = get_client_ip();
}
if (!isset($orderData['recordCount'])) {
$counter = increment_counter();
$orderData['recordCount'] = $counter['total'];
}
if (!isset($orderData['items'])) {
$orderData['items'] = array();
}
$orders = read_orders();
array_unshift($orders, $orderData);
// 限制最大存储量
if (count($orders) > 500) {
$orders = array_slice($orders, 0, 500);
}
write_orders($orders);
return array(
'code' => 200,
'message' => '创建成功',
'data' => $orderData,
);
}
/**
* 获取点单
* GET ?act=get&id=xxx
*/
function get_order() {
$id = trim($_GET['id'] ?? '');
if (empty($id)) {
return array('code' => 400, 'message' => '缺少订单ID参数');
}
$orders = read_orders();
foreach ($orders as $order) {
if (isset($order['id']) && $order['id'] === $id) {
return array(
'code' => 200,
'message' => '获取成功',
'data' => $order,
);
}
}
return array('code' => 404, 'message' => '订单不存在');
}
/**
* 更新点单
* POST ?act=update
* Body: {order JSON with id}
*/
function update_order() {
$orderJson = $_GET['order'] ?? $_GET['data'] ?? null;
if ($orderJson === null) {
$rawBody = file_get_contents('php://input');
$orderData = json_decode($rawBody, true);
} else {
$orderData = json_decode($orderJson, true);
}
if (!is_array($orderData) || empty($orderData['id'])) {
return array('code' => 400, 'message' => '无效的订单数据缺少id字段');
}
$orders = read_orders();
$found = false;
foreach ($orders as $i => $order) {
if (isset($order['id']) && $order['id'] === $orderData['id']) {
$orderData['updatedAt'] = date('c');
$orders[$i] = array_merge($order, $orderData);
$found = true;
break;
}
}
if (!$found) {
// 不存在则创建
array_unshift($orders, $orderData);
}
write_orders($orders);
return array(
'code' => 200,
'message' => $found ? '更新成功' : '订单不存在,已创建',
'data' => $orderData,
);
}
/**
* 点单列表
* GET ?act=list&page=1&limit=20&status=0&type=0
*/
function list_orders() {
$page = max(1, (int)($_GET['page'] ?? 1));
$limit = min(100, max(1, (int)($_GET['limit'] ?? 20)));
$status = $_GET['status'] ?? null;
$type = $_GET['type'] ?? null;
$orders = read_orders();
// 筛选
if ($status !== null) {
$statusVal = (int)$status;
$orders = array_filter($orders, function($o) use ($statusVal) {
return isset($o['status']) && (int)$o['status'] === $statusVal;
});
$orders = array_values($orders);
}
if ($type !== null) {
$typeVal = (int)$type;
$orders = array_filter($orders, function($o) use ($typeVal) {
return isset($o['type']) && (int)$o['type'] === $typeVal;
});
$orders = array_values($orders);
}
$total = count($orders);
$offset = ($page - 1) * $limit;
$list = array_slice($orders, $offset, $limit);
return array(
'code' => 200,
'message' => '获取成功',
'data' => array(
'list' => $list,
'total' => $total,
'page' => $page,
'limit' => $limit,
'pages' => ceil($total / $limit),
),
);
}
/**
* 删除点单
* GET ?act=delete&id=xxx
*/
function delete_order() {
$id = trim($_GET['id'] ?? '');
if (empty($id)) {
return array('code' => 400, 'message' => '缺少订单ID参数');
}
$orders = read_orders();
$originalCount = count($orders);
$orders = array_filter($orders, function($o) use ($id) {
return !isset($o['id']) || $o['id'] !== $id;
});
$orders = array_values($orders);
if (count($orders) === $originalCount) {
return array('code' => 404, 'message' => '订单不存在');
}
write_orders($orders);
return array(
'code' => 200,
'message' => '删除成功',
'data' => array('deleted_id' => $id),
);
}
/**
* 清理过期数据
* GET ?act=cleanup&days=30
*/
function cleanup_expired() {
global $defaultExpireDays;
$days = max(1, (int)($_GET['days'] ?? $defaultExpireDays));
$cutoff = date('c', strtotime("-{$days} days"));
$orders = read_orders();
$originalCount = count($orders);
$orders = array_filter($orders, function($o) use ($cutoff) {
$updatedAt = $o['updatedAt'] ?? $o['createdAt'] ?? '';
return $updatedAt >= $cutoff;
});
$orders = array_values($orders);
$deletedCount = $originalCount - count($orders);
if ($deletedCount > 0) {
write_orders($orders);
}
return array(
'code' => 200,
'message' => "清理完成,删除{$deletedCount}条过期数据",
'data' => array(
'deleted_count' => $deletedCount,
'remaining_count' => count($orders),
'cutoff_date' => $cutoff,
'expire_days' => $days,
),
);
}
/**
* 清空全部点餐助手数据
* POST ?act=clear_all&confirm=yes
* 仅清理 cache/kitchen/ 目录下的文件,不影响其他数据
*/
function clear_all_orders() {
global $dataDir, $ordersFile, $counterFile, $updateFlagFile;
$confirm = strtolower(trim($_GET['confirm'] ?? $_POST['confirm'] ?? ''));
if ($confirm !== 'yes') {
return array(
'code' => 400,
'message' => '需要确认参数 confirm=yes 才能清空数据',
);
}
$deletedFiles = array();
$errors = array();
$kitchenFiles = array(
'orders' => $ordersFile,
'counter' => $counterFile,
'update_flag' => $updateFlagFile,
);
foreach ($kitchenFiles as $name => $file) {
if (file_exists($file)) {
if (@unlink($file)) {
$deletedFiles[] = basename($file);
} else {
$errors[] = '无法删除: ' . basename($file);
}
}
}
$scanDir = $dataDir;
if (is_dir($scanDir)) {
$extraFiles = @scandir($scanDir);
if ($extraFiles !== false) {
foreach ($extraFiles as $f) {
if ($f === '.' || $f === '..') continue;
$fullPath = $scanDir . $f;
if (is_file($fullPath) && !in_array($f, $deletedFiles)) {
if (@unlink($fullPath)) {
$deletedFiles[] = $f;
} else {
$errors[] = '无法删除: ' . $f;
}
}
}
}
}
$message = '点餐助手数据已清空';
if (count($deletedFiles) > 0) {
$message .= ',已删除: ' . implode(', ', $deletedFiles);
}
if (count($errors) > 0) {
$message .= ',错误: ' . implode(', ', $errors);
}
return array(
'code' => 200,
'message' => $message,
'data' => array(
'deleted_files' => $deletedFiles,
'errors' => $errors,
'data_dir' => basename($dataDir),
'scope' => 'kitchen_only',
),
);
}
/**
* 统计信息
* GET ?act=stats
*/
function get_stats() {
$counter = read_counter();
$orders = read_orders();
$statusCount = array(0 => 0, 1 => 0, 2 => 0, 3 => 0);
$typeCount = array(0 => 0, 1 => 0);
foreach ($orders as $o) {
$s = (int)($o['status'] ?? 0);
$t = (int)($o['type'] ?? 0);
if (isset($statusCount[$s])) $statusCount[$s]++;
if (isset($typeCount[$t])) $typeCount[$t]++;
}
return array(
'code' => 200,
'message' => '获取成功',
'data' => array(
'total_orders' => $counter['total'],
'today_orders' => $counter['today'],
'stored_orders' => count($orders),
'by_status' => $statusCount,
'by_type' => $typeCount,
'storage_file' => basename($GLOBALS['ordersFile']),
),
);
}
// ══════════════════════════════════════════════════════════════
// 工具函数
// ══════════════════════════════════════════════════════════════
/**
* 生成订单号
*/
function generate_order_no() {
$ts = substr(microtime(true) . '', 5);
$rand = rand(100, 999);
return 'OD' . $ts . $rand;
}
/**
* 获取客户端IP
*/
function get_client_ip() {
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
return trim($ips[0]);
}
if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER['HTTP_X_REAL_IP'];
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}