Files
779776787 efca70ecb2 push
首次推送
2025-08-12 14:19:34 +08:00

189 lines
5.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
if (!defined('IN_APP')) {
die('Direct access is not allowed.');
}
/**
* 清理并规范化路径,防止目录遍历攻击
* @param string $path
* @return string
*/
function sanitize_path($path) {
// 移除协议、域名和 ../ & .\
$path = preg_replace('/^[\w]+:\/\/[^\/]+/', '', $path);
$path = str_replace(['../', '..\\'], '', $path);
return trim($path, '/\\');
}
/**
* 根据配置生成前端可用的URL
*
* @param string $controller 控制器名称 (例如: 'Proxy')
* @param string $action 方法名称 (例如: 'load')
* @param array $params URL查询参数数组 (例如: ['key' => 'value'])
* @return string 构建好的URL
*/
function WWW_URL($controller, $action, $params = []) {
$path_mod = C('PATH_MOD');
$rewrite = C('REWRITE');
$baseUrl = '';
$queryParams = $params;
if (strcasecmp($path_mod, 'PATH_INFO') === 0) {
$baseUrl = $rewrite ? '' : 'index.php';
$baseUrl .= '/' . $controller . '/' . $action;
} else { // NORMAL 模式
$baseUrl = 'index.php';
$queryParams['c'] = $controller;
$queryParams['a'] = $action;
}
$queryString = http_build_query($queryParams);
if (!empty($queryString)) {
return $baseUrl . '?' . $queryString;
}
return $baseUrl;
}
// 格式化路径用于VSCode
function formatPathForVSCode($path) {
// 统一使用正斜杠
$path = str_replace('\\', '/', $path);
// 处理Windows盘符 (如 C:/path → /C:/path)
if (preg_match('/^[A-Za-z]:/', $path)) {
$path = '/' . $path;
}
// 编码特殊字符但保留斜杠
$parts = explode('/', $path);
$encodedParts = array_map('rawurlencode', $parts);
$encodedPath = implode('/', $encodedParts);
return $encodedPath;
}
/**
* 检测当前是否运行在本地开发环境
*
* @return bool 如果是本地环境返回true,否则返回false
*/
function isLocalEnvironment() {
// 1. 检查服务器IP地址
$serverIP = $_SERVER['SERVER_ADDR'] ?? '';
$remoteIP = $_SERVER['REMOTE_ADDR'] ?? '';
$localIPs = ['127.0.0.1', '::1'];
if (in_array($serverIP, $localIPs)) {
return true;
}
// 2. 检查主机名
$host = $_SERVER['HTTP_HOST'] ?? '';
if (strpos($host, 'localhost') !== false ||
strpos($host, '.local') !== false ||
strpos($host, '127.0.0.1') !== false) {
return true;
}
// 3. 检查开发环境变量(如Laravel的APP_ENV
if (getenv('APP_ENV') === 'local' || getenv('APP_ENV') === 'development') {
return true;
}
// 4. 检查常见的开发域名模式
if (preg_match('/\.(test|dev|local)$/', $host)) {
return true;
}
// 5. 检查X-Forwarded-For头(适用于某些本地代理设置)
$forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
if ($forwardedFor && in_array(trim(explode(',', $forwardedFor)[0], $localIPs))) {
return true;
}
// 6. 检查是否通过VPN或内网访问
$ipLong = ip2long($remoteIP);
$privateRanges = [
['10.0.0.0', '10.255.255.255'],
['172.16.0.0', '172.31.255.255'],
['192.168.0.0', '192.168.255.255']
];
foreach ($privateRanges as $range) {
$start = ip2long($range[0]);
$end = ip2long($range[1]);
if ($ipLong >= $start && $ipLong <= $end) {
return true;
}
}
return false;
}
/**
* 发起一个 cURL HTTP 请求
*
* @param array $options cURL请求的配置数组
* @return array 成功时返回 ['body' => string, 'info' => array], 失败时返回 ['error' => string]
* 如果 RETURNHEADER 为 true, 成功时返回 ['header' => string, 'body' => string, 'info' => array]
*/
function httpCurl($options) {
if (empty($options['url'])) {
return ['error' => 'cURL Error: URL is required.'];
}
$url = $options['url'];
$postData = $options['data'] ?? null;
$headers = $options['header'] ?? [];
$timeout = $options['TIMEOUT'] ?? 15;
$returnHeader = $options['RETURNHEADER'] ?? false;
$returnTransfer = $options['RETURNTRANSFER'] ?? true;
$followLocation = $options['FOLLOWLOCATION'] ?? true;
if (!array_filter($headers, function($h) { return stripos($h, 'User-Agent:') === 0; })) {
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36';
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, $returnTransfer);
curl_setopt($ch, CURLOPT_HEADER, $returnHeader);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $followLocation);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
if (!empty($postData)) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
}
$response = curl_exec($ch);
$err = curl_error($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($err) {
return ['error' => $err];
}
$result = ['body' => $response, 'info' => $info];
if ($returnHeader) {
$headerSize = $info['header_size'];
$result['header'] = substr($response, 0, $headerSize);
$result['body'] = substr($response, $headerSize);
}
return $result;
}