Client.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php
  2. namespace IXR;
  3. use Typecho\Http\Client as HttpClient;
  4. /**
  5. * IXR客户端
  6. * reload by typecho team(http://www.typecho.org)
  7. *
  8. * @package IXR
  9. */
  10. class Client
  11. {
  12. /** 默认客户端 */
  13. private const DEFAULT_USERAGENT = 'Typecho XML-RPC PHP Library';
  14. /**
  15. * 地址
  16. *
  17. * @var string
  18. */
  19. private $url;
  20. /**
  21. * 消息体
  22. *
  23. * @var Message
  24. */
  25. private $message;
  26. /**
  27. * 调试开关
  28. *
  29. * @var boolean
  30. */
  31. private $debug = false;
  32. /**
  33. * 请求前缀
  34. *
  35. * @var string|null
  36. */
  37. private $prefix;
  38. /**
  39. * @var Error
  40. */
  41. private $error;
  42. /**
  43. * 客户端构造函数
  44. *
  45. * @param string $url 服务端地址
  46. * @param string|null $prefix
  47. * @return void
  48. */
  49. public function __construct(
  50. string $url,
  51. ?string $prefix = null
  52. ) {
  53. $this->url = $url;
  54. $this->prefix = $prefix;
  55. }
  56. /**
  57. * 设置调试模式
  58. * @deprecated
  59. */
  60. public function setDebug()
  61. {
  62. $this->debug = true;
  63. }
  64. /**
  65. * 执行请求
  66. *
  67. * @param string $method
  68. * @param array $args
  69. * @return bool
  70. */
  71. private function rpcCall(string $method, array $args): bool
  72. {
  73. $request = new Request($method, $args);
  74. $xml = $request->getXml();
  75. $client = HttpClient::get();
  76. if (!$client) {
  77. $this->error = new Error(-32300, 'transport error - could not open socket');
  78. return false;
  79. }
  80. try {
  81. $client->setHeader('Content-Type', 'text/xml')
  82. ->setHeader('User-Agent', self::DEFAULT_USERAGENT)
  83. ->setData($xml)
  84. ->send($this->url);
  85. } catch (HttpClient\Exception $e) {
  86. $this->error = new Error(-32700, $e->getMessage());
  87. return false;
  88. }
  89. $contents = $client->getResponseBody();
  90. if ($this->debug) {
  91. echo '<pre>' . htmlspecialchars($contents) . "\n</pre>\n\n";
  92. }
  93. // Now parse what we've got back
  94. $this->message = new Message($contents);
  95. if (!$this->message->parse()) {
  96. // XML error
  97. $this->error = new Error(-32700, 'parse error. not well formed');
  98. return false;
  99. }
  100. // Is the message a fault?
  101. if ($this->message->messageType == 'fault') {
  102. $this->error = new Error($this->message->faultCode, $this->message->faultString);
  103. return false;
  104. }
  105. // Message must be OK
  106. return true;
  107. }
  108. /**
  109. * 增加前缀
  110. * <code>
  111. * $rpc->metaWeblog->newPost();
  112. * </code>
  113. *
  114. * @param string $prefix 前缀
  115. * @return Client
  116. */
  117. public function __get(string $prefix): Client
  118. {
  119. return new self($this->url, $this->prefix . $prefix . '.');
  120. }
  121. /**
  122. * 增加魔术特性
  123. * by 70
  124. *
  125. * @return mixed
  126. * @throws Exception
  127. */
  128. public function __call($method, $args)
  129. {
  130. $return = $this->rpcCall($this->prefix . $method, $args);
  131. if ($return) {
  132. return $this->getResponse();
  133. } else {
  134. throw new Exception($this->getErrorMessage(), $this->getErrorCode());
  135. }
  136. }
  137. /**
  138. * 获得返回值
  139. *
  140. * @return mixed
  141. */
  142. public function getResponse()
  143. {
  144. // methodResponses can only have one param - return that
  145. return $this->message->params[0];
  146. }
  147. /**
  148. * 是否为错误
  149. *
  150. * @return bool
  151. */
  152. public function isError(): bool
  153. {
  154. return isset($this->error);
  155. }
  156. /**
  157. * 获取错误代码
  158. *
  159. * @return int
  160. */
  161. private function getErrorCode(): int
  162. {
  163. return $this->error->code;
  164. }
  165. /**
  166. * 获取错误消息
  167. *
  168. * @return string
  169. */
  170. private function getErrorMessage(): string
  171. {
  172. return $this->error->message;
  173. }
  174. }