GetCpolar留V3版去掉V2版
php
class GetCpolarV3
{
private static $baseUrl = "http://localhost:9200";
private string $token; //为了减少重复获取token的次数,使用静态变量缓存token
public string $response;//tunnels的响应字符串
public int $lastUpdateTimestamp; //最近更新时间戳
public array $cpolarInfo;//解析后的Cpolar信息数组
private CurlShareHandle $sh; // cURL共享句柄
function __construct() {
$this->sh = curl_share_init();
curl_share_setopt($this->sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
}
function __destruct() {
curl_share_close($this->sh);
}
/**
*
* 获取认证token
*/
private function getToken(string $varname = 'cpolarloginaccount') {
$url = self::$baseUrl . "/api/v1/user/login";
$credentials = varjpandorabox($varname); //pandorabox.php
$credentialsData = json_decode($credentials->data, true);
$loginData = [
"email" => $credentialsData['email'] ?? '',
"password" => $credentialsData['password'] ?? ''
];
$jsonContent = json_encode($loginData);
// 初始化第一个 cURL 句柄,并将它设置到共享句柄
$ch = curl_init();
curl_setopt($ch, CURLOPT_SHARE, $this->sh);
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonContent,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Content-Length: " . strlen($jsonContent)
],
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
//curl_close($ch); //Function curl_close() is deprecated since 8.5, as it has no effect since PHP 8.0
curl_reset($ch); // 重置 cURL 句柄以便复用
if ($error) {
throw new Exception("cURL Error: " . $error);
}
if ($httpCode >= 400) {
throw new Exception("HTTP Error: " . $httpCode);
}
$responseData = json_decode($response, true);
if (!isset($responseData['data']['token'])) {
throw new Exception("Token not found in response");
}
$this->token = $responseData['data']['token'];
}
/**
*
* 使用token等敏感信息获取隧道列表
*/
public function getTunnels()
{
if (empty($this->token)==true) {
$this->getToken();
}
//echo "Using token: " . $this->token . "\n";
$url = self::$baseUrl . "/api/v1/tunnels";
//echo "Fetching tunnels from: " . $url . "\n";
// 初始化第一个 cURL 句柄,并将它设置到共享句柄
$ch = curl_init();
curl_setopt($ch, CURLOPT_SHARE, $this->sh);
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $this->token,
"Content-Type: application/json"
],
CURLOPT_TIMEOUT => 10
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
//curl_close($ch); //Function curl_close() is deprecated since 8.5, as it has no effect since PHP 8.0
curl_reset($ch); // 重置 cURL 句柄以便复用
if ($error) {
throw new Exception("cURL Error: " . $error);
}
if ($httpCode >= 400) {
throw new Exception("HTTP Error: " . $httpCode);
}
return $this->response = $response;
}
/**
*
*
* 从JSON字符串解析Cpolar信息
*/
public function getCpolarInfoFromJsonString(string $response)
{
$cpolarInfo = [
'total' => 0,
'items' => []
];
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("JSON parse error: " . json_last_error_msg());
}
if (!isset($data['data']['items'])) {
throw new Exception("Invalid JSON structure");
}
$cpolarInfo['total'] = $data['data']['total'] ?? 0;
$items = $data['data']['items'];
foreach ($items as $item) {
$name = $item['name'] ?? '';
$public_url = $item['public_url'] ?? '';
$create_datetime = '';
// 处理publish_tunnels数组
if (isset($item['publish_tunnels']) && is_array($item['publish_tunnels'])) {
foreach ($item['publish_tunnels'] as $tunnel) {
$create_datetime = $tunnel['create_datetime'] ?? '';
break; // 只取第一个tunnel
}
}
// 替换协议
$newUrl = str_replace('tls://', 'https://', $public_url);
$cpolarInfo['items'][] = [
'name' => $name,
'create_datetime' => $create_datetime,
'pubulic_url' => $newUrl
];
}
$this->cpolarInfo = $cpolarInfo;
return $this->cpolarInfo;
}
public function getCpolarInfoS()
{
$this->getTunnels();
$this->lastUpdateTimestamp = time();//// 当前 Unix 时间戳(秒)
return $this->getCpolarInfoFromJsonString($this->response);
}
}
php
class GetCpolarV2
{
private static $baseUrl = "http://localhost:9200";
private string $token; //为了减少重复获取token的次数,使用静态变量缓存token
private CurlHandle $ch; // cURL共享句柄
public int $lastUpdateTimestamp; //最近更新时间戳
function __construct() {
$this->ch = curl_init();
}
/**
*
* 获取认证token
*/
private function getToken(string $varname = 'cpolarloginaccount') {
$url = self::$baseUrl . "/api/v1/user/login";
$credentials = varjpandorabox($varname); //pandorabox.php
$credentialsData = json_decode($credentials->data, true);
$loginData = [
"email" => $credentialsData['email'] ?? '',
"password" => $credentialsData['password'] ?? ''
];
$jsonContent = json_encode($loginData);
// 初始化第一个 cURL 句柄
//$ch = curl_init();
curl_reset($this->ch); // 重置 cURL 句柄以便复用
curl_setopt_array($this->ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonContent,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Content-Length: " . strlen($jsonContent)
],
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($this->ch);
//$httpCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
// $error = curl_error($this->ch);
//curl_close($this->ch); //Function curl_close() is deprecated since 8.5, as it has no effect since PHP 8.0
curl_reset($this->ch); // 重置 cURL 句柄以便复用
// if ($error) {
// throw new Exception("cURL Error: " . $error);
// }
// if ($httpCode >= 400) {
// throw new Exception("HTTP Error: " . $httpCode);
// }
$responseData = json_decode($response, true);
if (!isset($responseData['data']['token'])) {
throw new Exception("Token not found in response");
}
$this->token = $responseData['data']['token'];
}
/**
*
* 使用token等敏感信息获取隧道列表
*/
public function getTunnels()
{
if (empty($this->token)==true) {
$this->getToken();
}
//echo "Using token: " . $this->token . "\n";
$url = self::$baseUrl . "/api/v1/tunnels";
//echo "Fetching tunnels from: " . $url . "\n";
//$ch = curl_init();
curl_reset($this->ch); // 重置 cURL 句柄以便复用
curl_setopt_array($this->ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $this->token,
"Content-Type: application/json"
],
CURLOPT_TIMEOUT => 10
]);
$response = curl_exec($this->ch);
//$httpCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
//$error = curl_error($this->ch);
//curl_close($this->ch); //Function curl_close() is deprecated since 8.5, as it has no effect since PHP 8.0
curl_reset($this->ch); // 重置 cURL 句柄以便复用
// if ($error) {
// throw new Exception("cURL Error: " . $error);
// }
// if ($httpCode >= 400) {
// throw new Exception("HTTP Error: " . $httpCode);
// }
return $response;
}
public function getCpolarInfoS()
{
$res = $this->getTunnels();
$this->lastUpdateTimestamp = time();//// 当前 Unix 时间戳(秒)
return DynamicCpolar::getCpolarInfoFromJsonString($res);
}
}
php
final class GetCpolarV4
{
private const BASE = 'http://localhost:9200';
private static ?string $token = null;
private static int $tokenAt = 0;
private const TOKEN_TTL = 72000; // 20h
private CurlHandle $ch;
public string $response = '';
public array $cpolarInfo = [];
public int $lastUpdateTimestamp = 0;
public function __construct() {
$this->ch = curl_init();
// 只设一次"永不改变"的选项,之后用 CURLOPT_URL / HTTPHEADER 覆盖可变部分
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true, // ← 关键:只设一次,绝不被 reset 清掉
CURLOPT_TIMEOUT => 15,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
// 注意:这里【不要】curl_reset(),reset 会把上面全清了
]);
}
private function exec(string $method, string $path, ?array $body = null, ?string $bearer = null): array
{
curl_setopt_array($this->ch, [
CURLOPT_URL => self::BASE . $path,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $body ? json_encode($body, JSON_UNESCAPED_SLASHES) : null,
CURLOPT_HTTPHEADER => array_filter([
'Content-Type: application/json',
$bearer ? 'Authorization: Bearer ' . $bearer : null,
]),
]);
$raw = curl_exec($this->ch);
$code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
$err = curl_error($this->ch);
$errno= curl_errno($this->ch);
if ($raw === false || $errno !== 0) {
throw new RuntimeException("cURL({$errno}): {$err} @ {$path}");
}
if ($code >= 400) {
throw new RuntimeException("HTTP {$code} @ {$path}: " . mb_substr((string)$raw, 0, 200));
}
$j = json_decode($raw, true);
if (!is_array($j)) {
throw new RuntimeException("Bad JSON({$code}) @ {$path}: " . mb_substr($raw, 0, 200));
}
return $j;
}
private function token(): string
{
if (self::$token !== null && time() - self::$tokenAt < self::TOKEN_TTL) {
return self::$token;
}
$c = json_decode(varjpandorabox('cpolarloginaccount')->data ?? '{}', true);
$j = $this->exec('POST', '/api/v1/user/login', [
'email' => $c['email'] ?? '', 'password' => $c['password'] ?? ''
]);
if (!isset($j['data']['token'])) {
throw new RuntimeException('Token not found: ' . json_encode($j, JSON_UNESCAPED_UNICODE));
}
self::$token = $j['data']['token'];
self::$tokenAt = time();
return self::$token;
}
public function getCpolarInfoS(): array
{
$j = $this->exec('GET', '/api/v1/tunnels', null, $this->token());
$this->lastUpdateTimestamp = time();
$this->response = json_encode($j);
$items = [];
foreach (($j['data']['items'] ?? []) as $it) {
$ts = '';
foreach (($it['publish_tunnels'] ?? []) as $t) { $ts = $t['create_datetime'] ?? ''; break; }
$items[] = [
'name' => $it['name'] ?? '',
'create_datetime' => $ts,
'created_at_ts' => $ts ? (strtotime($ts) ?: 0) : 0, // ← V5 pick() 直接吃
'public_url' => str_replace(['tls://','tcp://'], ['https://','http://'], $it['public_url'] ?? ''),
];
}
return $this->cpolarInfo = ['total' => $j['data']['total'] ?? count($items), 'items' => $items];
}
}
php
/**
*
*/
public static function checkHttpsDomain(int $timeout = 2): bool
{
$token = self::getToken();
$url = self::$baseUrl . "/api/v1/tunnels";
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $token,
"Content-Type: application/json"
],
CURLOPT_TIMEOUT => $timeout
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$errno = curl_errno($ch);
//echo $response."\n";
if($response=='' || empty($response)){return false;}
$cp = json_decode($response,true);
//var_dump($cp);
if(!isset($cp['data']['items']) && isset($cp['data'])){return false;}
$exist = false;
foreach($cp['data']['items'] as $it)
{
if($it['name'] == 'Apache' && key_exists('status', $it)){ //key_exists同时判断 key 存在 + value 不为 null
if($it['status'] == 'active'){$exist=true;}
//echo $exist.PHP_EOL;
}
}
return $exist == true && $errno === 0 && $httpCode >= 200 && $httpCode < 400;
}