request->get('@json'); $token = $data['token'] ?? ''; $permalink = $data['permalink']; $title = $data['title']; $excerpt = $data['excerpt']; $response = ['trackback' => [], 'pingback' => []]; if (!Common::timeTokenValidate($token, $this->options->secret, 3) || empty($permalink)) { throw new Exception(_t('禁止访问'), 403); } /** 忽略超时 */ if (function_exists('ignore_user_abort')) { ignore_user_abort(true); } if (function_exists('set_time_limit')) { set_time_limit(30); } if (!empty($data['pingback'])) { $links = $data['pingback']; $permalinkPart = parse_url($permalink); /** 发送pingback */ foreach ($links as $url) { $urlPart = parse_url($url); if (isset($urlPart['scheme'])) { if ('http' != $urlPart['scheme'] && 'https' != $urlPart['scheme']) { continue; } } else { $urlPart['scheme'] = 'http'; $url = Common::buildUrl($urlPart); } if ($permalinkPart['host'] == $urlPart['host'] && $permalinkPart['path'] == $urlPart['path']) { continue; } $spider = Client::get(); if ($spider) { $spider->setTimeout(10) ->send($url); if (!($xmlrpcUrl = $spider->getResponseHeader('x-pingback'))) { if ( preg_match( "/]*rel=[\"']pingback[\"'][^>]*href=[\"']([^\"']+)[\"'][^>]*>/i", $spider->getResponseBody(), $out ) ) { $xmlrpcUrl = $out[1]; } } if (!empty($xmlrpcUrl)) { $response['pingback'][] = $url; try { $xmlrpc = new \IXR\Client($xmlrpcUrl); $xmlrpc->pingback->ping($permalink, $url); unset($xmlrpc); } catch (\IXR\Exception $e) { continue; } } } unset($spider); } } /** 发送trackback */ if (!empty($data['trackback'])) { $links = $data['trackback']; foreach ($links as $url) { $client = Client::get(); $response['trackback'][] = $url; if ($client) { try { $client->setTimeout(5) ->setData([ 'blog_name' => $this->options->title . ' » ' . $title, 'url' => $permalink, 'excerpt' => $excerpt ]) ->send($url); unset($client); } catch (Client\Exception $e) { continue; } } } } $this->response->throwJson($response); } /** * 发送pingback * * $this->sendPing($post); * * * @param Contents $content 内容url * @param array|null $trackback */ public function sendPing(Contents $content, ?array $trackback = null) { $this->user->pass('contributor'); if ($client = Client::get()) { try { $input = [ 'do' => 'ping', 'permalink' => $content->permalink, 'excerpt' => $content->excerpt, 'title' => $content->title, 'token' => Common::timeToken($this->options->secret) ]; if (preg_match_all("|]*href=[\"'](.*?)[\"'][^>]*>(.*?)|", $content->content, $matches)) { $pingback = array_unique($matches[1]); if (!empty($pingback)) { $input['pingback'] = $pingback; } } if (!empty($trackback)) { $input['trackback'] = $trackback; } $client->setHeader('User-Agent', $this->options->generator) ->setTimeout(2) ->setJson($input) ->send($this->getServiceUrl('ping')); } catch (Client\Exception $e) { return; } } } /** * 获取真实的 URL * * @param string $do 动作名 * @return string */ private function getServiceUrl(string $do): string { $url = Common::url('/action/service', $this->options->index); if (defined('__TYPECHO_SERVICE_URL__')) { $rootPath = rtrim(parse_url($this->options->rootUrl, PHP_URL_PATH), '/'); $path = parse_url($url, PHP_URL_PATH); $parts = parse_url(__TYPECHO_SERVICE_URL__); if ( !empty($parts['path']) && $parts['path'] != '/' && rtrim($parts['path'], '/') != $rootPath ) { $path = Common::url($path, $parts['path']); } $parts['path'] = $path; $url = Common::buildUrl($parts); } return $url . '?do=' . $do; } /** * 请求异步服务 * * @param $method * @param mixed $params */ public function requestService($method, $params = null) { static $called; if (!$called) { Response::getInstance()->addResponder(function () { if (!empty($this->asyncRequests) && $client = Client::get()) { try { $client->setHeader('User-Agent', $this->options->generator) ->setTimeout(2) ->setJson([ 'requests' => $this->asyncRequests, 'token' => Common::timeToken($this->options->secret) ]) ->send($this->getServiceUrl('async')); } catch (Client\Exception $e) { return; } } }); $called = true; } $this->asyncRequests[] = [$method, $params]; } /** * 执行回调 * * @throws Exception */ public function asyncHandle() { /** 验证权限 */ $data = $this->request->get('@json'); $token = $data['token'] ?? ''; if (!Common::timeTokenValidate($token, $this->options->secret, 3)) { throw new Exception(_t('禁止访问'), 403); } /** 忽略超时 */ if (function_exists('ignore_user_abort')) { ignore_user_abort(true); } if (function_exists('set_time_limit')) { set_time_limit(30); } $requests = $data['requests'] ?? null; $plugin = self::pluginHandle(); if (!empty($requests)) { foreach ($requests as $request) { [$method, $params] = $request; $plugin->{$method}($params); } } } /** * 异步请求入口 */ public function action() { $this->on($this->request->isPost() && $this->request->is('do=ping'))->sendPingHandle(); $this->on($this->request->isPost() && $this->request->is('do=async'))->asyncHandle(); } }