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();
}
}