api实现

This commit is contained in:
Developer
2026-04-09 08:54:36 +08:00
parent 2eaf317705
commit 8d27c67d3a
319 changed files with 70169 additions and 4677 deletions

237
docs/api/response.php Normal file
View File

@@ -0,0 +1,237 @@
<?php
/**
* 🚀 API响应格式处理
*
* 支持多种响应格式提高App读取效率
* - JSON: 通用格式,兼容性好
* - MessagePack: 二进制格式体积小30-50%,解析更快
* - Gzip: 压缩JSON减少传输大小
* - CBOR: 二进制JSONRFC 8949标准
*/
class ApiResponse {
private static $supportedFormats = array('json', 'msgpack', 'gzip', 'cbor');
public static function getFormat() {
$format = strtolower(trim($_GET['_format'] ?? 'json'));
if (!in_array($format, self::$supportedFormats)) {
$format = 'json';
}
if ($format === 'msgpack' && !function_exists('msgpack_pack')) {
$format = 'json';
}
if ($format === 'cbor' && !class_exists('CBOR\CBOREncoder')) {
$format = 'json';
}
return $format;
}
public static function output($data, $format = null) {
if ($format === null) {
$format = self::getFormat();
}
$startTime = microtime(true);
switch ($format) {
case 'msgpack':
self::outputMsgpack($data);
break;
case 'gzip':
self::outputGzip($data);
break;
case 'cbor':
self::outputCbor($data);
break;
case 'json':
default:
self::outputJson($data);
break;
}
}
private static function outputJson($data) {
header('Content-Type: application/json; charset=utf-8');
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (isset($_GET['_pretty']) && $_GET['_pretty'] === '1') {
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
}
$size = strlen($json);
header('X-Response-Size: ' . $size);
header('X-Response-Format: json');
echo $json;
}
private static function outputMsgpack($data) {
if (!function_exists('msgpack_pack')) {
self::outputJson($data);
return;
}
header('Content-Type: application/msgpack');
$packed = msgpack_pack($data);
$size = strlen($packed);
$jsonData = json_encode($data, JSON_UNESCAPED_UNICODE);
$jsonSize = strlen($jsonData);
$saved = round((1 - $size / $jsonSize) * 100, 1);
header('X-Response-Size: ' . $size);
header('X-Json-Size: ' . $jsonSize);
header('X-Size-Saved: ' . $saved . '%');
header('X-Response-Format: msgpack');
echo $packed;
}
private static function outputGzip($data) {
if (!function_exists('gzencode')) {
self::outputJson($data);
return;
}
header('Content-Type: application/json');
header('Content-Encoding: gzip');
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$gzip = gzencode($json, 6);
$size = strlen($gzip);
$jsonSize = strlen($json);
$saved = round((1 - $size / $jsonSize) * 100, 1);
header('X-Response-Size: ' . $size);
header('X-Json-Size: ' . $jsonSize);
header('X-Size-Saved: ' . $saved . '%');
header('X-Response-Format: gzip');
echo $gzip;
}
private static function outputCbor($data) {
if (!class_exists('CBOR\CBOREncoder')) {
self::outputJson($data);
return;
}
header('Content-Type: application/cbor');
try {
$cbor = CBOR\CBOREncoder::encode($data);
$size = strlen($cbor);
$jsonData = json_encode($data, JSON_UNESCAPED_UNICODE);
$jsonSize = strlen($jsonData);
$saved = round((1 - $size / $jsonSize) * 100, 1);
header('X-Response-Size: ' . $size);
header('X-Json-Size: ' . $jsonSize);
header('X-Size-Saved: ' . $saved . '%');
header('X-Response-Format: cbor');
echo $cbor;
} catch (Exception $e) {
self::outputJson($data);
}
}
public static function getAcceptFormat() {
$accept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : '';
if (strpos($accept, 'application/msgpack') !== false) {
return 'msgpack';
}
if (strpos($accept, 'application/cbor') !== false) {
return 'cbor';
}
if (strpos($accept, 'application/json') !== false) {
return 'json';
}
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {
return 'gzip';
}
return 'json';
}
public static function getStats($data) {
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
$jsonSize = strlen($json);
$stats = array(
'json' => array(
'size' => $jsonSize,
'size_readable' => self::formatBytes($jsonSize)
)
);
if (function_exists('gzencode')) {
$gzip = gzencode($json, 6);
$gzipSize = strlen($gzip);
$stats['gzip'] = array(
'size' => $gzipSize,
'size_readable' => self::formatBytes($gzipSize),
'saved' => round((1 - $gzipSize / $jsonSize) * 100, 1) . '%'
);
}
if (function_exists('msgpack_pack')) {
$msgpack = msgpack_pack($data);
$msgpackSize = strlen($msgpack);
$stats['msgpack'] = array(
'size' => $msgpackSize,
'size_readable' => self::formatBytes($msgpackSize),
'saved' => round((1 - $msgpackSize / $jsonSize) * 100, 1) . '%'
);
}
return $stats;
}
private static function formatBytes($bytes) {
if ($bytes >= 1048576) {
return number_format($bytes / 1048576, 2) . ' MB';
} elseif ($bytes >= 1024) {
return number_format($bytes / 1024, 2) . ' KB';
} else {
return $bytes . ' B';
}
}
}
if (php_sapi_name() === 'cli' && isset($argv[0]) && basename($argv[0]) === 'response.php') {
header('Content-Type: text/plain');
echo "支持的响应格式:\n";
echo "- json: JSON格式默认\n";
echo "- gzip: Gzip压缩JSON\n";
if (function_exists('msgpack_pack')) {
echo "- msgpack: MessagePack二进制格式 ✅\n";
} else {
echo "- msgpack: MessagePack二进制格式 ❌ (需要安装msgpack扩展)\n";
}
if (class_exists('CBOR\CBOREncoder')) {
echo "- cbor: CBOR二进制格式 ✅\n";
} else {
echo "- cbor: CBOR二进制格式 ❌ (需要安装cbor库)\n";
}
echo "\n使用方式:\n";
echo " api.php?act=list&_format=json # JSON格式\n";
echo " api.php?act=list&_format=gzip # Gzip压缩\n";
echo " api.php?act=list&_format=msgpack # MessagePack格式\n";
echo " api.php?act=list&_format=cbor # CBOR格式\n";
echo " api.php?act=list&_pretty=1 # 格式化JSON调试用\n";
}