Refactor codes

This commit is contained in:
joyqi
2021-08-22 23:27:07 +08:00
parent 5163c43610
commit b0df985d66
16 changed files with 821 additions and 844 deletions
+4 -9
View File
@@ -1,18 +1,13 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR Base64编码
*
* @package IXR
*/
class IXR_Base64
class Base64
{
/**
* 编码数据
@@ -26,7 +21,7 @@ class IXR_Base64
*
* @param string $data
*/
public function __construct($data)
public function __construct(string $data)
{
$this->data = $data;
}
+65 -76
View File
@@ -1,11 +1,9 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
use Typecho\Common;
use Typecho\Http\Client as HttpClient;
/**
* IXR客户端
@@ -13,10 +11,10 @@
*
* @package IXR
*/
class IXR_Client
class Client
{
/** 默认客户端 */
const DEFAULT_USERAGENT = 'The Incutio XML-RPC PHP Library(Reload By Typecho)';
private const DEFAULT_USERAGENT = 'Typecho XML-RPC PHP Library';
/**
* 服务端地址
@@ -58,21 +56,12 @@ class IXR_Client
*/
private $useragent;
/**
* 回执结构体
*
* @access private
* @var string
*/
private $response;
/**
* 消息体
*
* @access private
* @var string
* @var Message
*/
private $message = false;
private $message;
/**
* 调试开关
@@ -86,48 +75,53 @@ class IXR_Client
* 请求前缀
*
* @access private
* @var string
* @var string|null
*/
private $prefix = NULL;
private $prefix = null;
// Storage place for an error message
private $error = false;
/**
* @var Error
*/
private $error;
/**
* 客户端构造函数
*
* @access public
* @param string $server 服务端地址
* @param string $path 路径名称
* @param string|null $path 路径名称
* @param integer $port 端口名称
* @param string $useragent 客户端
* @param string|null $useragent 客户端
* @param string|null $prefix
* @return void
*/
public function __construct($server, $path = false, $port = 80, $useragent = self::DEFAULT_USERAGENT, $prefix = NULL)
{
public function construct(
string $server,
?string $path = null,
int $port = 80,
string $useragent = self::DEFAULT_USERAGENT,
?string $prefix = null
) {
if (!$path) {
$this->url = $server;
// Assume we have been given a Url instead
$bits = parse_url($server);
$this->server = $bits['host'];
$this->port = isset($bits['port']) ? $bits['port'] : 80;
$this->path = isset($bits['path']) ? $bits['path'] : '/';
$this->port = $bits['port'] ?? 80;
$this->path = $bits['path'] ?? '/';
// Make absolutely sure we have a path
if (isset($bits['query'])) {
$this->path .= '?' . $bits['query'];
}
} else {
/** Typecho_Common */
require_once 'Typecho/Common.php';
$this->url = Typecho_Common::buildUrl(array(
'scheme' => 'http',
'host' => $server,
'path' => $path,
'port' => $port
));
$this->url = Common::buildUrl([
'scheme' => 'http',
'host' => $server,
'path' => $path,
'port' => $port
]);
$this->server = $server;
$this->path = $path;
@@ -144,7 +138,7 @@ class IXR_Client
* @access public
* @return void
*/
public function __setDebug()
public function setDebug()
{
$this->debug = true;
}
@@ -152,44 +146,44 @@ class IXR_Client
/**
* 执行请求
*
* @access public
* @return void
* @param string $method
* @param ...$args
* @return bool
* @throws HttpClient\Exception
*/
public function __rpcCall()
private function rpcCall(string $method, ...$args): bool
{
$args = func_get_args();
$method = array_shift($args);
$request = new IXR_Request($method, $args);
$request = new Request($method, $args);
$xml = $request->getXml();
$client = Typecho_Http_Client::get();
$client = HttpClient::get();
if (!$client) {
$this->error = new IXR_Error(-32300, 'transport error - could not open socket');
$this->error = new Error(-32300, 'transport error - could not open socket');
return false;
}
$client->setHeader('Content-Type', 'text/xml')
->setHeader('User-Agent', $this->useragent)
->setData($xml)
->send($this->url);
->setHeader('User-Agent', $this->useragent)
->setData($xml)
->send($this->url);
$contents = $client->getResponseBody();
if ($this->debug) {
echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
echo '<pre>' . htmlspecialchars($contents) . "\n</pre>\n\n";
}
// Now parse what we've got back
$this->message = new IXR_Message($contents);
$this->message = new Message($contents);
if (!$this->message->parse()) {
// XML error
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
$this->error = new Error(-32700, 'parse error. not well formed');
return false;
}
// Is the message a fault?
if ($this->message->messageType == 'fault') {
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
$this->error = new Error($this->message->faultCode, $this->message->faultString);
return false;
}
@@ -205,40 +199,38 @@ class IXR_Client
*
* @access public
* @param string $prefix 前缀
* @return IXR_Client
* @return Client
*/
public function __get($prefix)
public function get(string $prefix): Client
{
return new IXR_Client($this->server, $this->path, $this->port, $this->useragent, $this->prefix . $prefix . '.');
return new self($this->server, $this->path, $this->port, $this->useragent, $this->prefix . $prefix . '.');
}
/**
* 增加魔术特性
* by 70
*
* @access public
* @return mixed
* @throws Exception
*/
public function __call($method, $args)
{
array_unshift($args, $this->prefix . $method);
$return = call_user_func_array(array($this, '__rpcCall'), $args);
$return = call_user_func_array([$this, 'rpcCall'], $args);
if ($return) {
return $this->__getResponse();
return $this->getResponse();
} else {
require_once 'IXR/Exception.php';
throw new IXR_Exception($this->__getErrorMessage(), $this->__getErrorCode());
throw new Exception($this->getErrorMessage(), $this->getErrorCode());
}
}
/**
* 获得返回值
*
* @access public
* @return void
* @return mixed
*/
public function __getResponse()
public function getResponse()
{
// methodResponses can only have one param - return that
return $this->message->params[0];
@@ -247,21 +239,19 @@ class IXR_Client
/**
* 是否为错误
*
* @access public
* @return void
* @return bool
*/
public function __isError()
public function isError(): bool
{
return (is_object($this->error));
return isset($this->error);
}
/**
* 获取错误代码
*
* @access public
* @return void
* @return int
*/
public function __getErrorCode()
private function getErrorCode(): int
{
return $this->error->code;
}
@@ -269,10 +259,9 @@ class IXR_Client
/**
* 获取错误消息
*
* @access public
* @return void
* @return string
*/
public function __getErrorMessage()
private function getErrorMessage(): string
{
return $this->error->message;
}
+54 -23
View File
@@ -1,33 +1,44 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR日期
*
* @package IXR
*/
class IXR_Date {
var $year;
var $month;
var $day;
var $hour;
var $minute;
var $second;
function __construct($time) {
class Date
{
private $year;
private $month;
private $day;
private $hour;
private $minute;
private $second;
/**
* @param int|string $time
*/
public function __construct($time)
{
// $time can be a PHP timestamp or an ISO one
if (is_numeric($time)) {
$this->parseTimestamp($time);
$this->parseTimestamp(intval($time));
} else {
$this->parseIso($time);
}
}
function parseTimestamp($timestamp) {
/**
* @param int $timestamp
*/
private function parseTimestamp(int $timestamp)
{
$this->year = date('Y', $timestamp);
$this->month = date('m', $timestamp);
$this->day = date('d', $timestamp);
@@ -35,7 +46,12 @@ class IXR_Date {
$this->minute = date('i', $timestamp);
$this->second = date('s', $timestamp);
}
function parseIso($iso) {
/**
* @param string $iso
*/
private function parseIso(string $iso)
{
$this->year = substr($iso, 0, 4);
$this->month = substr($iso, 4, 2);
$this->day = substr($iso, 6, 2);
@@ -43,13 +59,28 @@ class IXR_Date {
$this->minute = substr($iso, 12, 2);
$this->second = substr($iso, 15, 2);
}
function getIso() {
return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
/**
* @return string
*/
public function getIso(): string
{
return $this->year . $this->month . $this->day . 'T' . $this->hour . ':' . $this->minute . ':' . $this->second;
}
function getXml() {
return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
/**
* @return string
*/
public function getXml(): string
{
return '<dateTime.iso8601>' . $this->getIso() . '</dateTime.iso8601>';
}
function getTimestamp() {
/**
* @return false|int
*/
public function getTimestamp()
{
return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
}
}
+7 -13
View File
@@ -1,18 +1,13 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR错误
*
* @package IXR
*/
class IXR_Error
class Error
{
/**
* 错误代码
@@ -26,7 +21,7 @@ class IXR_Error
* 错误消息
*
* @access public
* @var string
* @var string|null
*/
public $message;
@@ -35,10 +30,10 @@ class IXR_Error
*
* @access public
* @param integer $code 错误代码
* @param string $message 错误消息
* @param string|null $message 错误消息
* @return void
*/
public function __construct($code, $message)
public function __construct(int $code, ?string $message)
{
$this->code = $code;
$this->message = $message;
@@ -52,7 +47,7 @@ class IXR_Error
*/
public function getXml()
{
$xml = <<<EOD
return <<<EOD
<methodResponse>
<fault>
<value>
@@ -71,6 +66,5 @@ class IXR_Error
</methodResponse>
EOD;
return $xml;
}
}
+9 -10
View File
@@ -1,17 +1,16 @@
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* IXR异常类
*
* @package IXR
*/
class IXR_Exception extends Exception
{}
class Exception extends \Exception
{
}
+114 -82
View File
@@ -1,57 +1,79 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR消息
*
* @package IXR
*/
class IXR_Message {
var $message;
var $messageType; // methodCall / methodResponse / fault
var $faultCode;
var $faultString;
var $methodName;
var $params;
class Message
{
/**
* @var string
*/
public $message;
/**
* @var string
*/
public $messageType; // methodCall / methodResponse / fault
public $faultCode;
public $faultString;
/**
* @var string
*/
public $methodName;
/**
* @var array
*/
public $params = [];
// Current variable stacks
var $_arraystructs = array(); // The stack used to keep track of the current array/struct
var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
var $_currentStructName = array(); // A stack as well
var $_param;
var $_value;
var $_currentTag;
var $_currentTagContents;
// The XML parser
var $_parser;
function __construct ($message) {
private $arrayStructs = []; // The stack used to keep track of the current array/struct
private $arrayStructsTypes = []; // Stack keeping track of if things are structs or array
private $currentStructName = []; // A stack as well
private $currentTagContents;
/**
* @param string $message
*/
public function __construct(string $message)
{
$this->message = $message;
}
function parse() {
/**
* @return bool
*/
public function parse(): bool
{
// first remove the XML declaration
$this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
$this->message = preg_replace('/<\?xml(.*)?\?' . '>/', '', $this->message);
if (trim($this->message) == '') {
return false;
}
$this->_parser = xml_parser_create();
$parser = xml_parser_create();
// Set XML parser to take the case of tags in to account
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
// Set XML parser callback functions
xml_set_object($this->_parser, $this);
xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
xml_set_character_data_handler($this->_parser, 'cdata');
if (!xml_parse($this->_parser, $this->message)) {
xml_set_object($parser, $this);
xml_set_element_handler($parser, [$this, 'tagOpen'], [$this, 'tagClose']);
xml_set_character_data_handler($parser, [$this, 'cdata']);
if (!xml_parse($parser, $this->message)) {
/* die(sprintf('XML error: %s at line %d',
xml_error_string(xml_get_error_code($this->_parser)),
xml_get_current_line_number($this->_parser))); */
xml_error_string(xml_get_error_code($this->parser)),
xml_get_current_line_number($this->parser))); */
return false;
}
xml_parser_free($this->_parser);
xml_parser_free($parser);
// Grab the error messages, if any
if ($this->messageType == 'fault') {
$this->faultCode = $this->params[0]['faultCode'];
@@ -59,9 +81,15 @@ class IXR_Message {
}
return true;
}
function tag_open($parser, $tag, $attr) {
$this->currentTag = $tag;
switch($tag) {
/**
* @param $parser
* @param $tag
* @param $attr
*/
private function tagOpen($parser, string $tag, $attr)
{
switch ($tag) {
case 'methodCall':
case 'methodResponse':
case 'fault':
@@ -69,94 +97,98 @@ class IXR_Message {
break;
/* Deal with stacks of arrays and structs */
case 'data': // data is to all intents and puposes more interesting than array
$this->_arraystructstypes[] = 'array';
$this->_arraystructs[] = array();
$this->arrayStructsTypes[] = 'array';
$this->arrayStructs[] = [];
break;
case 'struct':
$this->_arraystructstypes[] = 'struct';
$this->_arraystructs[] = array();
$this->arrayStructsTypes[] = 'struct';
$this->arrayStructs[] = [];
break;
}
}
function cdata($parser, $cdata) {
$this->_currentTagContents .= $cdata;
/**
* @param $parser
* @param string $cdata
*/
private function cdata($parser, string $cdata)
{
$this->currentTagContents .= $cdata;
}
function tag_close($parser, $tag) {
$valueFlag = false;
switch($tag) {
/**
* @param $parser
* @param string $tag
*/
private function tagClose($parser, string $tag)
{
switch ($tag) {
case 'int':
case 'i4':
$value = (int)trim($this->_currentTagContents);
$this->_currentTagContents = '';
$valueFlag = true;
$value = (int) trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'double':
$value = (double)trim($this->_currentTagContents);
$this->_currentTagContents = '';
$valueFlag = true;
$value = (double) trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'string':
$value = (string)trim($this->_currentTagContents);
$this->_currentTagContents = '';
$valueFlag = true;
$value = (string)trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'dateTime.iso8601':
$value = new IXR_Date(trim($this->_currentTagContents));
$value = new Date(trim($this->currentTagContents));
// $value = $iso->getTimestamp();
$this->_currentTagContents = '';
$valueFlag = true;
$this->currentTagContents = '';
break;
case 'value':
// "If no type is indicated, the type is string."
if (trim($this->_currentTagContents) != '') {
$value = (string)$this->_currentTagContents;
$this->_currentTagContents = '';
$valueFlag = true;
if (trim($this->currentTagContents) != '') {
$value = (string) $this->currentTagContents;
$this->currentTagContents = '';
}
break;
case 'boolean':
$value = (boolean)trim($this->_currentTagContents);
$this->_currentTagContents = '';
$valueFlag = true;
$value = (bool) trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'base64':
$value = base64_decode($this->_currentTagContents);
$this->_currentTagContents = '';
$valueFlag = true;
$value = base64_decode($this->currentTagContents);
$this->currentTagContents = '';
break;
/* Deal with stacks of arrays and structs */
case 'data':
case 'struct':
$value = array_pop($this->_arraystructs);
array_pop($this->_arraystructstypes);
$valueFlag = true;
$value = array_pop($this->arrayStructs);
array_pop($this->arrayStructsTypes);
break;
case 'member':
array_pop($this->_currentStructName);
array_pop($this->currentStructName);
break;
case 'name':
$this->_currentStructName[] = trim($this->_currentTagContents);
$this->_currentTagContents = '';
$this->currentStructName[] = trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'methodName':
$this->methodName = trim($this->_currentTagContents);
$this->_currentTagContents = '';
$this->methodName = trim($this->currentTagContents);
$this->currentTagContents = '';
break;
}
if ($valueFlag) {
if (isset($value)) {
/*
if (!is_array($value) && !is_object($value)) {
$value = trim($value);
}
*/
if (count($this->_arraystructs) > 0) {
if (count($this->arrayStructs) > 0) {
// Add value to struct or array
if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
if ($this->arrayStructsTypes[count($this->arrayStructsTypes) - 1] == 'struct') {
// Add to struct
$this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
$this->arrayStructs[count($this->arrayStructs) - 1]
[$this->currentStructName[count($this->currentStructName) - 1]] = $value;
} else {
// Add to array
$this->_arraystructs[count($this->_arraystructs)-1][] = $value;
$this->arrayStructs[count($this->arrayStructs) - 1][] = $value;
}
} else {
// Just add as a paramater
+31 -19
View File
@@ -1,43 +1,55 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR请求体
*
* @package IXR
*/
class IXR_Request {
var $method;
var $args;
var $xml;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
class Request
{
/**
* @var string
*/
private $xml;
/**
* @param string $method
* @param array $args
*/
public function __construct(string $method, array $args)
{
$this->xml = <<<EOD
<?xml version="1.0"?>
<methodCall>
<methodName>{$this->method}</methodName>
<methodName>{$method}</methodName>
<params>
EOD;
foreach ($this->args as $arg) {
foreach ($args as $arg) {
$this->xml .= '<param><value>';
$v = new IXR_Value($arg);
$v = new Value($arg);
$this->xml .= $v->getXml();
$this->xml .= "</value></param>\n";
}
$this->xml .= '</params></methodCall>';
}
function getLength() {
/**
* @return int
*/
public function getLength(): int
{
return strlen($this->xml);
}
function getXml() {
/**
* @return string
*/
public function getXml(): string
{
return $this->xml;
}
}
+169 -252
View File
@@ -1,42 +1,20 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR服务器
*
* @package IXR
*/
class IXR_Server
class Server
{
/**
* 输入参数
*
* @access private
* @var array
*/
private $data;
/**
* 回调函数
*
* @access private
* @var array
*/
private $callbacks = array();
/**
* 消息体
*
* @access private
* @var IXR_Message
*/
private $message;
private $callbacks;
/**
* 默认参数
@@ -49,234 +27,23 @@ class IXR_Server
/**
* 构造函数
*
* @access public
* @param mixed $callbacks 回调函数
* @param mixed $data 输入参数
* @return void
* @param array $callbacks 回调函数
*/
public function __construct($callbacks = false, $data = false)
public function __construct(array $callbacks = [])
{
$this->setCapabilities();
if ($callbacks) {
$this->callbacks = $callbacks;
}
$this->callbacks = $callbacks;
$this->setCallbacks();
$this->serve($data);
}
/**
* 呼叫内部方法
*
* @access private
* @param string $methodname 方法名
* @param mixed $args 参数
* @return mixed
*/
private function call($methodname, $args)
{
// hook
if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.beforeCall')) {
$this->call('hook.beforeCall', array($methodname));
}
if (!$this->hasMethod($methodname)) {
return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
}
$method = $this->callbacks[$methodname];
// Are we dealing with a function or a method?
if (is_string($method) && substr($method, 0, 5) == 'this:') {
// It's a class method - check it exists
$method = substr($method, 5);
if (!method_exists($this, $method)) {
return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
}
// Call the method
$result = $this->$method($args);
} else {
if (is_array($method)) {
list($object, $func) = $method;
if (!is_callable($method)) {
return new IXR_Error(-32601, 'server error. requested class method "'.$object . '.' . $func.'" does not exist.');
}
$result = call_user_func_array(array($object, $func), $args);
} elseif (!function_exists($method)) {
// It's a function - does it exist?
return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
} else {
// Call the function
$result = $method($args);
}
}
// hook
if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.afterCall')) {
$this->call('hook.afterCall', array($methodname));
}
return $result;
}
/**
* 抛出错误
*
* @access private
* @param integer $error 错误代码
* @param string $message 错误消息
* @return void
*/
private function error($error, $message = false)
{
// Accepts either an error object or an error code and message
if ($message && !is_object($error)) {
$error = new IXR_Error($error, $message);
}
$this->output($error->getXml());
}
/**
* 输出xml
*
* @access private
* @param string $xml 输出xml
* @return 输出xml
*/
private function output($xml)
{
$xml = '<?xml version="1.0"?>'."\n".$xml;
$length = strlen($xml);
header('Connection: close');
header('Content-Length: '.$length);
header('Content-Type: text/xml');
header('Date: '.date('r'));
echo $xml;
exit;
}
/**
* 是否存在方法
*
* @access private
* @param string $method 方法名
* @return mixed
*/
private function hasMethod($method)
{
return in_array($method, array_keys($this->callbacks));
}
/**
* 设置默认参数
*
* @access public
* @return void
*/
private function setCapabilities()
{
// Initialises capabilities array
$this->capabilities = array(
'xmlrpc' => array(
'specUrl' => 'http://www.xmlrpc.com/spec',
'specVersion' => 1
),
'faults_interop' => array(
'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
'specVersion' => 20010516
),
'system.multicall' => array(
'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
'specVersion' => 1
),
);
}
/**
* 设置默认方法
*
* @access private
* @return void
*/
private function setCallbacks()
{
$this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
$this->callbacks['system.listMethods'] = 'this:listMethods';
$this->callbacks['system.multicall'] = 'this:multiCall';
}
/**
* 服务入口
*
* @access private
* @param mixed $data 输入参数
* @return void
*/
private function serve($data = false)
{
if (!isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
$GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents("php://input");
}
if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
$GLOBALS['HTTP_RAW_POST_DATA'] = trim($GLOBALS['HTTP_RAW_POST_DATA']);
}
if (!$data) {
global $HTTP_RAW_POST_DATA;
if (!$HTTP_RAW_POST_DATA) {
die('XML-RPC server accepts POST requests only.');
}
$data = $HTTP_RAW_POST_DATA;
}
$this->message = new IXR_Message($data);
if (!$this->message->parse()) {
$this->error(-32700, 'parse error. not well formed');
}
if ($this->message->messageType != 'methodCall') {
$this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
}
if (0 === strpos($this->message->methodName, 'hook.')) {
die('THIS METHOD MUST BE CALLED INSIDE.');
}
$result = $this->call($this->message->methodName, $this->message->params);
// Is the result an error?
if (is_a($result, 'IXR_Error')) {
$this->error($result);
}
// Encode the result
$r = new IXR_Value($result);
$resultxml = $r->getXml();
// Create the XML
$xml = <<<EOD
<methodResponse>
<params>
<param>
<value>
$resultxml
</value>
</param>
</params>
</methodResponse>
EOD;
// hook
if ($this->hasMethod('hook.beforeOutput')) {
$this->call('hook.beforeOutput', array());
}
// Send it
$this->output($xml);
$this->serve();
}
/**
* 获取默认参数
*
* @access public
* @param mixed $args 输入参数
* @return array
*/
public function getCapabilities($args)
public function getCapabilities(): array
{
return $this->capabilities;
}
@@ -285,10 +52,9 @@ EOD;
* 列出所有方法
*
* @access public
* @param mixed $args 输入参数
* @return mixed
* @return array
*/
public function listMethods($args)
public function listMethods(): array
{
// Returns a list of methods - uses array_reverse to ensure user defined
// methods are listed before server defined methods
@@ -305,24 +71,175 @@ EOD;
public function multiCall($methodcalls)
{
// See http://www.xmlrpc.com/discuss/msgReader$1208
$return = array();
$return = [];
foreach ($methodcalls as $call) {
$method = $call['methodName'];
$params = $call['params'];
if ($method == 'system.multicall') {
$result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
$result = new Error(-32600, 'Recursive calls to system.multicall are forbidden');
} else {
$result = $this->call($method, $params);
}
if (is_a($result, 'IXR_Error')) {
$return[] = array(
'faultCode' => $result->code,
if (is_a($result, 'Error')) {
$return[] = [
'faultCode' => $result->code,
'faultString' => $result->message
);
];
} else {
$return[] = array($result);
$return[] = [$result];
}
}
return $return;
}
/**
* 呼叫内部方法
*
* @param string $methodName 方法名
* @param array $args 参数
* @return mixed
*/
private function call(string $methodName, array $args)
{
if (!$this->hasMethod($methodName)) {
return new Error(-32601, 'server error. requested method ' . $methodName . ' does not exist.');
}
$method = $this->callbacks[$methodName];
if (!is_callable($method)) {
return new Error(
-32601,
'server error. requested class method "' . $methodName . '" does not exist.'
);
}
return call_user_func_array($method, $args);
}
/**
* 抛出错误
*
* @access private
* @param integer|Error $error 错误代码
* @param string|null $message 错误消息
* @return void
*/
private function error($error, ?string $message = null)
{
// Accepts either an error object or an error code and message
if (!$error instanceof Error) {
$error = new Error($error, $message);
}
$this->output($error->getXml());
}
/**
* 输出xml
*
* @access private
* @param string $xml 输出xml
*/
private function output(string $xml)
{
$xml = '<?xml version="1.0"?>' . "\n" . $xml;
$length = strlen($xml);
header('Connection: close');
header('Content-Length: ' . $length);
header('Content-Type: text/xml');
header('Date: ' . date('r'));
echo $xml;
exit;
}
/**
* 是否存在方法
*
* @access private
* @param string $method 方法名
* @return mixed
*/
private function hasMethod(string $method)
{
return in_array($method, array_keys($this->callbacks));
}
/**
* 设置默认参数
*
* @access public
* @return void
*/
private function setCapabilities()
{
// Initialises capabilities array
$this->capabilities = [
'xmlrpc' => [
'specUrl' => 'http://www.xmlrpc.com/spec',
'specVersion' => 1
],
'faults_interop' => [
'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
'specVersion' => 20010516
],
'system.multicall' => [
'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
'specVersion' => 1
],
];
}
/**
* 设置默认方法
*
* @access private
* @return void
*/
private function setCallbacks()
{
$this->callbacks['system.getCapabilities'] = [$this, 'getCapabilities'];
$this->callbacks['system.listMethods'] = [$this, 'listMethods'];
$this->callbacks['system.multicall'] = [$this, 'multiCall'];
}
/**
* 服务入口
*/
private function serve()
{
$message = new Message(file_get_contents('php://input') ?: '');
if (!$message->parse()) {
$this->error(-32700, 'parse error. not well formed');
} elseif ($message->messageType != 'methodCall') {
$this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
}
$result = $this->call($message->methodName, $message->params);
// Is the result an error?
if ($result instanceof Error) {
$this->error($result);
}
// Encode the result
$r = new Value($result);
$resultXml = $r->getXml();
// Create the XML
$xml = <<<EOD
<methodResponse>
<params>
<param>
<value>
$resultXml
</value>
</param>
</params>
</methodResponse>
EOD;
// Send it
$this->output($xml);
}
}
+66 -55
View File
@@ -1,21 +1,24 @@
<?php
/*
IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
Site: http://scripts.incutio.com/xmlrpc/
Manual: http://scripts.incutio.com/xmlrpc/manual.php
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
*/
namespace IXR;
/**
* IXR值
*
* @package IXR
*/
class IXR_Value {
var $data;
var $type;
function __construct ($data, $type = false) {
class Value
{
private $data;
private $type;
/**
* @param mixed $data
* @param bool|string $type
*/
public function __construct($data, $type = false)
{
$this->data = $data;
if (!$type) {
$type = $this->calculateType();
@@ -24,16 +27,62 @@ class IXR_Value {
if ($type == 'struct') {
/* Turn all the values in the array in to new IXR_Value objects */
foreach ($this->data as $key => $value) {
$this->data[$key] = new IXR_Value($value);
$this->data[$key] = new Value($value);
}
}
if ($type == 'array') {
for ($i = 0, $j = count($this->data); $i < $j; $i++) {
$this->data[$i] = new IXR_Value($this->data[$i]);
$this->data[$i] = new Value($this->data[$i]);
}
}
}
function calculateType() {
public function getXml(): string
{
/* Return XML for this value */
switch ($this->type) {
case 'boolean':
return '<boolean>' . (($this->data) ? '1' : '0') . '</boolean>';
break;
case 'int':
return '<int>' . $this->data . '</int>';
break;
case 'double':
return '<double>' . $this->data . '</double>';
break;
case 'string':
return '<string>' . htmlspecialchars($this->data) . '</string>';
break;
case 'array':
$return = '<array><data>' . "\n";
foreach ($this->data as $item) {
$return .= ' <value>' . $item->getXml() . "</value>\n";
}
$return .= '</data></array>';
return $return;
break;
case 'struct':
$return = '<struct>' . "\n";
foreach ($this->data as $name => $value) {
$return .= " <member><name>$name</name><value>";
$return .= $value->getXml() . "</value></member>\n";
}
$return .= '</struct>';
return $return;
break;
case 'date':
case 'base64':
return $this->data->getXml();
break;
}
return false;
}
/**
* @return string
*/
private function calculateType(): string
{
if ($this->data === true || $this->data === false) {
return 'boolean';
}
@@ -52,7 +101,6 @@ class IXR_Value {
}
// If it is a normal PHP object convert it in to a struct
if (is_object($this->data)) {
$this->data = get_object_vars($this->data);
return 'struct';
}
@@ -66,46 +114,9 @@ class IXR_Value {
return 'array';
}
}
function getXml() {
/* Return XML for this value */
switch ($this->type) {
case 'boolean':
return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
break;
case 'int':
return '<int>'.$this->data.'</int>';
break;
case 'double':
return '<double>'.$this->data.'</double>';
break;
case 'string':
return '<string>'.htmlspecialchars($this->data).'</string>';
break;
case 'array':
$return = '<array><data>'."\n";
foreach ($this->data as $item) {
$return .= ' <value>'.$item->getXml()."</value>\n";
}
$return .= '</data></array>';
return $return;
break;
case 'struct':
$return = '<struct>'."\n";
foreach ($this->data as $name => $value) {
$return .= " <member><name>$name</name><value>";
$return .= $value->getXml()."</value></member>\n";
}
$return .= '</struct>';
return $return;
break;
case 'date':
case 'base64':
return $this->data->getXml();
break;
}
return false;
}
function isStruct($array) {
private function isStruct($array): bool
{
/* Nasty function to check if an array is a struct or not */
$expected = 0;
foreach ($array as $key => $value) {
+14 -21
View File
@@ -1,13 +1,6 @@
<?php
/**
* cookie支持
*
* @category typecho
* @package Cookie
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id$
*/
namespace Typecho;
/**
* cookie支持
@@ -16,7 +9,7 @@
* @category typecho
* @package Cookie
*/
class Typecho_Cookie
class Cookie
{
/**
* 前缀
@@ -24,7 +17,7 @@ class Typecho_Cookie
* @var string
* @access private
*/
private static $_prefix = '';
private static $prefix = '';
/**
* 路径
@@ -32,7 +25,7 @@ class Typecho_Cookie
* @var string
* @access private
*/
private static $_path = '/';
private static $path = '/';
/**
* 获取前缀
@@ -42,7 +35,7 @@ class Typecho_Cookie
*/
public static function getPrefix(): string
{
return self::$_prefix;
return self::$prefix;
}
/**
@@ -55,11 +48,11 @@ class Typecho_Cookie
*/
public static function setPrefix(string $url)
{
self::$_prefix = md5($url);
self::$prefix = md5($url);
$parsed = parse_url($url);
/** 在路径后面强制加上斜杠 */
self::$_path = empty($parsed['path']) ? '/' : Typecho_Common::url(null, $parsed['path']);
self::$path = empty($parsed['path']) ? '/' : Common::url(null, $parsed['path']);
}
/**
@@ -70,7 +63,7 @@ class Typecho_Cookie
*/
public static function getPath(): string
{
return self::$_path;
return self::$path;
}
/**
@@ -85,7 +78,7 @@ class Typecho_Cookie
*/
public static function get(string $key, ?string $default = null)
{
$key = self::$_prefix . $key;
$key = self::$prefix . $key;
$value = $_COOKIE[$key] ?? $default;
return is_array($value) ? $default : $value;
}
@@ -103,8 +96,8 @@ class Typecho_Cookie
*/
public static function set(string $key, $value, int $expire = 0)
{
$key = self::$_prefix . $key;
setrawcookie($key, rawurlencode($value), $expire, self::$_path);
$key = self::$prefix . $key;
setrawcookie($key, rawurlencode($value), $expire, self::$path);
$_COOKIE[$key] = $value;
}
@@ -119,12 +112,12 @@ class Typecho_Cookie
*/
public static function delete(string $key)
{
$key = self::$_prefix . $key;
$key = self::$prefix . $key;
if (!isset($_COOKIE[$key])) {
return;
}
setcookie($key, '', time() - 2592000, self::$_path);
setcookie($key, '', time() - 2592000, self::$path);
unset($_COOKIE[$key]);
}
}
+7 -4
View File
@@ -1,5 +1,7 @@
<?php
namespace Typecho;
/**
* 日期处理
*
@@ -7,7 +9,7 @@
* @category typecho
* @package Date
*/
class Typecho_Date
class Date
{
/**
* 期望时区偏移
@@ -48,9 +50,10 @@ class Typecho_Date
*
* @param integer|null $time 时间戳
*/
public function __construct(?int $time = NULL)
public function __construct(?int $time = null)
{
$this->timeStamp = (NULL === $time ? self::time() : $time) + (self::$timezoneOffset - self::$serverTimezoneOffset);
$this->timeStamp = (null === $time ? self::time() : $time)
+ (self::$timezoneOffset - self::$serverTimezoneOffset);
}
/**
@@ -90,7 +93,7 @@ class Typecho_Date
*/
public function word(): string
{
return Typecho_I18n::dateWord($this->timeStamp, self::time() + (self::$timezoneOffset - self::$serverTimezoneOffset));
return I18n::dateWord($this->timeStamp, self::time() + (self::$timezoneOffset - self::$serverTimezoneOffset));
}
/**
+71 -76
View File
@@ -1,43 +1,31 @@
<?php
/**
* 格式化聚合XML数据,整合自Univarsel Feed Writer
*
* @author Anis uddin Ahmad <anisniit@gmail.com>
* @category typecho
* @package Feed
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id: Feed.php 219 2008-05-27 09:06:15Z magike.net $
*/
namespace Typecho;
/**
* Typecho_Feed
*
* @author qining
* @category typecho
* @package Feed
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
*/
class Typecho_Feed
class Feed
{
/** 定义RSS 1.0类型 */
const RSS1 = 'RSS 1.0';
public const RSS1 = 'RSS 1.0';
/** 定义RSS 2.0类型 */
const RSS2 = 'RSS 2.0';
public const RSS2 = 'RSS 2.0';
/** 定义ATOM 1.0类型 */
const ATOM1 = 'ATOM 1.0';
public const ATOM1 = 'ATOM 1.0';
/** 定义RSS时间格式 */
const DATE_RFC822 = 'r';
public const DATE_RFC822 = 'r';
/** 定义ATOM时间格式 */
const DATE_W3CDTF = 'c';
public const DATE_W3CDTF = 'c';
/** 定义行结束符 */
const EOL = "\n";
public const EOL = "\n";
/**
* feed状态
@@ -45,7 +33,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_type;
private $type;
/**
* 字符集编码
@@ -53,7 +41,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_charset;
private $charset;
/**
* 语言状态
@@ -61,7 +49,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_lang;
private $lang;
/**
* 聚合地址
@@ -69,7 +57,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_feedUrl;
private $feedUrl;
/**
* 基本地址
@@ -77,7 +65,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_baseUrl;
private $baseUrl;
/**
* 聚合标题
@@ -85,7 +73,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_title;
private $title;
/**
* 聚合副标题
@@ -93,7 +81,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_subTitle;
private $subTitle;
/**
* 版本信息
@@ -101,7 +89,7 @@ class Typecho_Feed
* @access private
* @var string
*/
private $_version;
private $version;
/**
* 所有的items
@@ -109,7 +97,7 @@ class Typecho_Feed
* @access private
* @var array
*/
private $_items = [];
private $items = [];
/**
* 创建Feed对象
@@ -119,10 +107,10 @@ class Typecho_Feed
*/
public function __construct($version, $type = self::RSS2, $charset = 'UTF-8', $lang = 'en')
{
$this->_version = $version;
$this->_type = $type;
$this->_charset = $charset;
$this->_lang = $lang;
$this->version = $version;
$this->type = $type;
$this->charset = $charset;
$this->lang = $lang;
}
/**
@@ -136,7 +124,7 @@ class Typecho_Feed
*/
public function setTitle(string $title)
{
$this->_title = $title;
$this->title = $title;
}
/**
@@ -150,7 +138,7 @@ class Typecho_Feed
*/
public function setSubTitle(string $subTitle)
{
$this->_subTitle = $subTitle;
$this->subTitle = $subTitle;
}
/**
@@ -164,7 +152,7 @@ class Typecho_Feed
*/
public function setFeedUrl(string $feedUrl)
{
$this->_feedUrl = $feedUrl;
$this->feedUrl = $feedUrl;
}
/**
@@ -178,7 +166,7 @@ class Typecho_Feed
*/
public function setBaseUrl(string $baseUrl)
{
$this->_baseUrl = $baseUrl;
$this->baseUrl = $baseUrl;
}
/**
@@ -203,7 +191,7 @@ class Typecho_Feed
*/
public function addItem(array $item)
{
$this->_items[] = $item;
$this->items[] = $item;
}
/**
@@ -212,11 +200,11 @@ class Typecho_Feed
* @access public
* @return string
*/
public function __toString()
public function __toString(): string
{
$result = '<?xml version="1.0" encoding="' . $this->_charset . '"?>' . self::EOL;
$result = '<?xml version="1.0" encoding="' . $this->charset . '"?>' . self::EOL;
if (self::RSS1 == $this->_type) {
if (self::RSS1 == $this->type) {
$result .= '<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
@@ -226,7 +214,7 @@ xmlns:dc="http://purl.org/dc/elements/1.1/">' . self::EOL;
$links = [];
$lastUpdate = 0;
foreach ($this->_items as $item) {
foreach ($this->items as $item) {
$content .= '<item rdf:about="' . $item['link'] . '">' . self::EOL;
$content .= '<title>' . htmlspecialchars($item['title']) . '</title>' . self::EOL;
$content .= '<link>' . $item['link'] . '</link>' . self::EOL;
@@ -244,10 +232,10 @@ xmlns:dc="http://purl.org/dc/elements/1.1/">' . self::EOL;
}
}
$result .= '<channel rdf:about="' . $this->_feedUrl . '">
<title>' . htmlspecialchars($this->_title) . '</title>
<link>' . $this->_baseUrl . '</link>
<description>' . htmlspecialchars($this->_subTitle) . '</description>
$result .= '<channel rdf:about="' . $this->feedUrl . '">
<title>' . htmlspecialchars($this->title) . '</title>
<link>' . $this->baseUrl . '</link>
<description>' . htmlspecialchars($this->subTitle) . '</description>
<items>
<rdf:Seq>' . self::EOL;
@@ -260,8 +248,7 @@ xmlns:dc="http://purl.org/dc/elements/1.1/">' . self::EOL;
</channel>' . self::EOL;
$result .= $content . '</rdf:RDF>';
} else if (self::RSS2 == $this->_type) {
} elseif (self::RSS2 == $this->type) {
$result .= '<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
@@ -273,13 +260,14 @@ xmlns:wfw="http://wellformedweb.org/CommentAPI/">
$content = '';
$lastUpdate = 0;
foreach ($this->_items as $item) {
foreach ($this->items as $item) {
$content .= '<item>' . self::EOL;
$content .= '<title>' . htmlspecialchars($item['title']) . '</title>' . self::EOL;
$content .= '<link>' . $item['link'] . '</link>' . self::EOL;
$content .= '<guid>' . $item['link'] . '</guid>' . self::EOL;
$content .= '<pubDate>' . $this->dateFormat($item['date']) . '</pubDate>' . self::EOL;
$content .= '<dc:creator>' . htmlspecialchars($item['author']->screenName) . '</dc:creator>' . self::EOL;
$content .= '<dc:creator>' . htmlspecialchars($item['author']->screenName)
. '</dc:creator>' . self::EOL;
if (!empty($item['category']) && is_array($item['category'])) {
foreach ($item['category'] as $category) {
@@ -288,11 +276,12 @@ xmlns:wfw="http://wellformedweb.org/CommentAPI/">
}
if (!empty($item['excerpt'])) {
$content .= '<description><![CDATA[' . strip_tags($item['excerpt']) . ']]></description>' . self::EOL;
$content .= '<description><![CDATA[' . strip_tags($item['excerpt'])
. ']]></description>' . self::EOL;
}
if (!empty($item['content'])) {
$content .= '<content:encoded xml:lang="' . $this->_lang . '"><![CDATA['
$content .= '<content:encoded xml:lang="' . $this->lang . '"><![CDATA['
. self::EOL .
$item['content'] . self::EOL .
']]></content:encoded>' . self::EOL;
@@ -318,28 +307,27 @@ xmlns:wfw="http://wellformedweb.org/CommentAPI/">
}
}
$result .= '<title>' . htmlspecialchars($this->_title) . '</title>
<link>' . $this->_baseUrl . '</link>
<atom:link href="' . $this->_feedUrl . '" rel="self" type="application/rss+xml" />
<language>' . $this->_lang . '</language>
<description>' . htmlspecialchars($this->_subTitle) . '</description>
$result .= '<title>' . htmlspecialchars($this->title) . '</title>
<link>' . $this->baseUrl . '</link>
<atom:link href="' . $this->feedUrl . '" rel="self" type="application/rss+xml" />
<language>' . $this->lang . '</language>
<description>' . htmlspecialchars($this->subTitle) . '</description>
<lastBuildDate>' . $this->dateFormat($lastUpdate) . '</lastBuildDate>
<pubDate>' . $this->dateFormat($lastUpdate) . '</pubDate>' . self::EOL;
$result .= $content . '</channel>
</rss>';
} else if (self::ATOM1 == $this->_type) {
} elseif (self::ATOM1 == $this->type) {
$result .= '<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0"
xml:lang="' . $this->_lang . '"
xml:base="' . $this->_baseUrl . '"
xml:lang="' . $this->lang . '"
xml:base="' . $this->baseUrl . '"
>' . self::EOL;
$content = '';
$lastUpdate = 0;
foreach ($this->_items as $item) {
foreach ($this->items as $item) {
$content .= '<entry>' . self::EOL;
$content .= '<title type="html"><![CDATA[' . $item['title'] . ']]></title>' . self::EOL;
$content .= '<link rel="alternate" type="text/html" href="' . $item['link'] . '" />' . self::EOL;
@@ -353,26 +341,31 @@ xml:base="' . $this->_baseUrl . '"
if (!empty($item['category']) && is_array($item['category'])) {
foreach ($item['category'] as $category) {
$content .= '<category scheme="' . $category['permalink'] . '" term="' . $category['name'] . '" />' . self::EOL;
$content .= '<category scheme="' . $category['permalink'] . '" term="'
. $category['name'] . '" />' . self::EOL;
}
}
if (!empty($item['excerpt'])) {
$content .= '<summary type="html"><![CDATA[' . htmlspecialchars($item['excerpt']) . ']]></summary>' . self::EOL;
$content .= '<summary type="html"><![CDATA[' . htmlspecialchars($item['excerpt'])
. ']]></summary>' . self::EOL;
}
if (!empty($item['content'])) {
$content .= '<content type="html" xml:base="' . $item['link'] . '" xml:lang="' . $this->_lang . '"><![CDATA['
$content .= '<content type="html" xml:base="' . $item['link']
. '" xml:lang="' . $this->lang . '"><![CDATA['
. self::EOL .
$item['content'] . self::EOL .
']]></content>' . self::EOL;
}
if (isset($item['comments']) && strlen($item['comments']) > 0) {
$content .= '<link rel="replies" type="text/html" href="' . $item['link'] . '#comments" thr:count="' . $item['comments'] . '" />' . self::EOL;
$content .= '<link rel="replies" type="text/html" href="' . $item['link']
. '#comments" thr:count="' . $item['comments'] . '" />' . self::EOL;
if (!empty($item['commentsFeedUrl'])) {
$content .= '<link rel="replies" type="application/atom+xml" href="' . $item['commentsFeedUrl'] . '" thr:count="' . $item['comments'] . '"/>' . self::EOL;
$content .= '<link rel="replies" type="application/atom+xml" href="'
. $item['commentsFeedUrl'] . '" thr:count="' . $item['comments'] . '"/>' . self::EOL;
}
}
@@ -387,13 +380,13 @@ xml:base="' . $this->_baseUrl . '"
}
}
$result .= '<title type="text">' . htmlspecialchars($this->_title) . '</title>
<subtitle type="text">' . htmlspecialchars($this->_subTitle) . '</subtitle>
$result .= '<title type="text">' . htmlspecialchars($this->title) . '</title>
<subtitle type="text">' . htmlspecialchars($this->subTitle) . '</subtitle>
<updated>' . $this->dateFormat($lastUpdate) . '</updated>
<generator uri="http://typecho.org/" version="' . $this->_version . '">Typecho</generator>
<link rel="alternate" type="text/html" href="' . $this->_baseUrl . '" />
<id>' . $this->_feedUrl . '</id>
<link rel="self" type="application/atom+xml" href="' . $this->_feedUrl . '" />
<generator uri="http://typecho.org/" version="' . $this->version . '">Typecho</generator>
<link rel="alternate" type="text/html" href="' . $this->baseUrl . '" />
<id>' . $this->feedUrl . '</id>
<link rel="self" type="application/atom+xml" href="' . $this->feedUrl . '" />
';
$result .= $content . '</feed>';
}
@@ -412,10 +405,12 @@ xml:base="' . $this->_baseUrl . '"
*/
public function dateFormat(int $stamp): string
{
if (self::RSS2 == $this->_type) {
if (self::RSS2 == $this->type) {
return date(self::DATE_RFC822, $stamp);
} else if (self::RSS1 == $this->_type || self::ATOM1 == $this->_type) {
} elseif (self::RSS1 == $this->type || self::ATOM1 == $this->type) {
return date(self::DATE_W3CDTF, $stamp);
}
return '';
}
}
+22 -22
View File
@@ -1,26 +1,23 @@
<?php
/**
* Typecho Blog Platform
*
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id: I18n.php 106 2008-04-11 02:23:54Z magike.net $
*/
namespace Typecho;
use Typecho\I18n\GetTextMulti;
/**
* 国际化字符翻译
*
* @package I18n
*/
class Typecho_I18n
class I18n
{
/**
* 是否已经载入的标志位
*
* @access private
* @var boolean|Typecho_I18n_GetTextMulti
* @var GetTextMulti
*/
private static $_loaded = false;
private static $loaded;
/**
* 语言文件
@@ -28,7 +25,7 @@ class Typecho_I18n
* @access private
* @var string
*/
private static $_lang = null;
private static $lang = null;
/**
* 翻译文字
@@ -42,7 +39,7 @@ class Typecho_I18n
public static function translate(string $string): string
{
self::init();
return self::$_loaded ? self::$_loaded->translate($string) : $string;
return self::$loaded ? self::$loaded->translate($string) : $string;
}
/**
@@ -53,8 +50,8 @@ class Typecho_I18n
private static function init()
{
/** GetText支持 */
if (false === self::$_loaded && self::$_lang && file_exists(self::$_lang)) {
self::$_loaded = new Typecho_I18n_GetTextMulti(self::$_lang);
if (!isset(self::$loaded) && self::$lang && file_exists(self::$lang)) {
self::$loaded = new GetTextMulti(self::$lang);
}
}
@@ -70,7 +67,7 @@ class Typecho_I18n
public static function ngettext(string $single, string $plural, int $number): string
{
self::init();
return self::$_loaded ? self::$_loaded->ngettext($single, $plural, $number) : ($number > 1 ? $plural : $single);
return self::$loaded ? self::$loaded->ngettext($single, $plural, $number) : ($number > 1 ? $plural : $single);
}
/**
@@ -78,8 +75,8 @@ class Typecho_I18n
*
* @access public
*
* @param string $from 起始时间
* @param string $now 终止时间
* @param int $from 起始时间
* @param int $now 终止时间
*
* @return string
*/
@@ -109,9 +106,12 @@ class Typecho_I18n
}
/** 如果是昨天 */
if ($between > 0 && $between < 172800
if (
$between > 0
&& $between < 172800
&& (date('z', $from) + 1 == date('z', $now) // 在同一年的情况
|| date('z', $from) + 1 == date('L') + 365 + date('z', $now))) { // 跨年的情况
|| date('z', $from) + 1 == date('L') + 365 + date('z', $now))
) { // 跨年的情况
return _t('昨天 %s', date('H:i', $from));
}
@@ -140,7 +140,7 @@ class Typecho_I18n
*/
public static function addLang(string $lang)
{
self::$_loaded->addFile($lang);
self::$loaded->addFile($lang);
}
/**
@@ -151,7 +151,7 @@ class Typecho_I18n
*/
public static function getLang(): ?string
{
return self::$_lang;
return self::$lang;
}
/**
@@ -165,6 +165,6 @@ class Typecho_I18n
*/
public static function setLang(string $lang)
{
self::$_lang = $lang;
self::$lang = $lang;
}
}
+170 -159
View File
@@ -1,4 +1,7 @@
<?php
namespace Typecho\I18n;
/*
Copyright (c) 2003 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
@@ -21,21 +24,6 @@
*/
/**
* Provides a simple gettext replacement that works independently from
* the system's gettext abilities.
* It can read MO files and use them for translating strings.
* The files are passed to gettext_reader as a Stream (see streams.php)
*
* This version has the ability to cache all strings and translations to
* speed up the string lookup.
* While the cache is enabled by default, it can be switched off with the
* second parameter in the constructor (e.g. whenusing very large MO files
* that you don't want to keep in memory)
*/
//reload by 70 (typecho group)
/**
* This file is part of PHP-gettext
*
@@ -43,22 +31,32 @@
* @category typecho
* @package I18n
*/
class Typecho_I18n_GetText
class GetText
{
//public:
public $error = 0; // public variable that holds error code (0 if no error)
//private:
private $BYTEORDER = 0; // 0: low endian, 1: big endian
private $BYTE_ORDER = 0; // 0: low endian, 1: big endian
private $STREAM = null;
private $short_circuit = false;
private $enable_cache = false;
private $originals = null; // offset of original table
private $translations = null; // offset of translation table
private $pluralheader = null; // cache header field for plural forms
private $pluralHeader = null; // cache header field for plural forms
private $total = 0; // total string count
private $table_originals = null; // table for original strings (offsets)
private $table_translations = null; // table for translated strings (offsets)
private $cache_translations = null; // original -> translation mapping
@@ -69,7 +67,7 @@ class Typecho_I18n_GetText
* @param string $file file name
* @param boolean enable_cache Enable or disable caching of strings (default on)
*/
public function __construct($file, $enable_cache = true)
public function __construct(string $file, $enable_cache = true)
{
// If there isn't a StreamReader, turn on short circuit mode.
if (!file_exists($file)) {
@@ -84,21 +82,114 @@ class Typecho_I18n_GetText
$unpacked = unpack('c', $this->read(4));
$magic = array_shift($unpacked);
if (- 34 == $magic) {
$this->BYTEORDER = 0;
} elseif (- 107 == $magic) {
$this->BYTEORDER = 1;
if (-34 == $magic) {
$this->BYTE_ORDER = 0;
} elseif (-107 == $magic) {
$this->BYTE_ORDER = 1;
} else {
$this->error = 1; // not MO file
return false;
}
// FIXME: Do we care about revision? We should.
$revision = $this->readint();
$revision = $this->readInt();
$this->total = $this->readint();
$this->originals = $this->readint();
$this->translations = $this->readint();
$this->total = $this->readInt();
$this->originals = $this->readInt();
$this->translations = $this->readInt();
}
/**
* Translates a string
*
* @access public
* @param string string to be translated
* @param integer|null $num found string number
* @return string translated string (or original, if not found)
*/
public function translate($string, ?int &$num): string
{
if ($this->short_circuit) {
return $string;
}
$this->loadTables();
if ($this->enable_cache) {
// Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations)) {
return $this->cache_translations[$string];
} else {
return $string;
}
} else {
// Caching not enabled, try to find string
$num = $this->findString($string);
if ($num == -1) {
return $string;
} else {
return $this->getTranslationString($num);
}
}
}
/**
* Plural version of gettext
*
* @access public
* @param string single
* @param string plural
* @param string number
* @param integer|null $num found string number
* @return string plural form
*/
public function ngettext($single, $plural, $number, ?int &$num): string
{
$number = intval($number);
if ($this->short_circuit) {
if ($number != 1) {
return $plural;
} else {
return $single;
}
}
// find out the appropriate form
$select = $this->selectString($number);
// this should contains all strings separated by NULLs
$key = $single . chr(0) . $plural;
if ($this->enable_cache) {
if (!array_key_exists($key, $this->cache_translations)) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->cache_translations[$key];
$list = explode(chr(0), $result);
return $list[$select];
}
} else {
$num = $this->findString($key);
if ($num == -1) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->getTranslationString($num);
$list = explode(chr(0), $result);
return $list[$select];
}
}
}
/**
* 关闭文件句柄
*
* @access public
* @return void
*/
public function __destruct()
{
fclose($this->STREAM);
}
/**
@@ -106,7 +197,7 @@ class Typecho_I18n_GetText
*
* @param mixed $count
* @access private
* @return void
* @return false|string
*/
private function read($count)
{
@@ -116,7 +207,7 @@ class Typecho_I18n_GetText
return fread($this->STREAM, $count);
}
return null;
return false;
}
/**
@@ -125,42 +216,12 @@ class Typecho_I18n_GetText
* @access private
* @return Integer from the Stream
*/
private function readint()
private function readInt(): int
{
$end = unpack($this->BYTEORDER == 0 ? 'V' : 'N', $this->read(4));
$end = unpack($this->BYTE_ORDER == 0 ? 'V' : 'N', $this->read(4));
return array_shift($end);
}
/**
* Translates a string
*
* @access public
* @param string string to be translated
* @param integer $num found string number
* @return string translated string (or original, if not found)
*/
public function translate($string, &$num)
{
if ($this->short_circuit)
return $string;
$this->load_tables();
if ($this->enable_cache) {
// Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations))
return $this->cache_translations[$string];
else
return $string;
} else {
// Caching not enabled, try to find string
$num = $this->find_string($string);
if ($num == - 1)
return $string;
else
return $this->get_translation_string($num);
}
}
/**
* Loads the translation tables from the MO file into the cache
* If caching is enabled, also loads all strings into a cache
@@ -168,23 +229,26 @@ class Typecho_I18n_GetText
*
* @access private
*/
private function load_tables()
private function loadTables()
{
if (is_array($this->cache_translations) &&
if (
is_array($this->cache_translations) &&
is_array($this->table_originals) &&
is_array($this->table_translations))
is_array($this->table_translations)
) {
return;
}
/* get original and translations tables */
fseek($this->STREAM, $this->originals);
$this->table_originals = $this->readintarray($this->total * 2);
$this->table_originals = $this->readIntArray($this->total * 2);
fseek($this->STREAM, $this->translations);
$this->table_translations = $this->readintarray($this->total * 2);
$this->table_translations = $this->readIntArray($this->total * 2);
if ($this->enable_cache) {
$this->cache_translations = ['' => null];
/* read all strings in the cache */
for ($i = 0; $i < $this->total; $i ++) {
for ($i = 0; $i < $this->total; $i++) {
if ($this->table_originals[$i * 2 + 1] > 0) {
fseek($this->STREAM, $this->table_originals[$i * 2 + 2]);
$original = fread($this->STREAM, $this->table_originals[$i * 2 + 1]);
@@ -200,11 +264,11 @@ class Typecho_I18n_GetText
* Reads an array of Integers from the Stream
*
* @param int count How many elements should be read
* @return Array of Integers
* @return array of Integers
*/
private function readintarray($count)
private function readIntArray($count): array
{
return unpack(($this->BYTEORDER == 0 ? 'V' : 'N') . $count, $this->read(4 * $count));
return unpack(($this->BYTE_ORDER == 0 ? 'V' : 'N') . $count, $this->read(4 * $count));
}
/**
@@ -216,36 +280,37 @@ class Typecho_I18n_GetText
* @param int end (internally used in recursive function)
* @return int string number (offset in originals table)
*/
private function find_string($string, $start = - 1, $end = - 1)
private function findString($string, $start = -1, $end = -1): int
{
if (($start == - 1) or ($end == - 1)) {
// find_string is called with only one parameter, set start end end
if (($start == -1) or ($end == -1)) {
// findString is called with only one parameter, set start end end
$start = 0;
$end = $this->total;
}
if (abs($start - $end) <= 1) {
// We're done, now we either found the string, or it doesn't exist
$txt = $this->get_original_string($start);
if ($string == $txt)
$txt = $this->getOriginalString($start);
if ($string == $txt) {
return $start;
else
return - 1;
} else {
return -1;
}
} elseif ($start > $end) {
// start > end -> turn around and start over
return $this->find_string($string, $end, $start);
return $this->findString($string, $end, $start);
} else {
// Divide table in two parts
$half = (int)(($start + $end) / 2);
$cmp = strcmp($string, $this->get_original_string($half));
if ($cmp == 0)
$cmp = strcmp($string, $this->getOriginalString($half));
if ($cmp == 0) {
// string is exactly in the middle => return it
return $half;
elseif ($cmp < 0)
} elseif ($cmp < 0) {
// The string is in the upper half
return $this->find_string($string, $start, $half);
else
// The string is in the lower half
return $this->find_string($string, $half, $end);
return $this->findString($string, $start, $half);
} else { // The string is in the lower half
return $this->findString($string, $half, $end);
}
}
}
@@ -256,12 +321,13 @@ class Typecho_I18n_GetText
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
*/
private function get_original_string($num)
private function getOriginalString($num): string
{
$length = $this->table_originals[$num * 2 + 1];
$offset = $this->table_originals[$num * 2 + 2];
if (!$length)
if (!$length) {
return '';
}
fseek($this->STREAM, $offset);
$data = fread($this->STREAM, $length);
return (string)$data;
@@ -274,65 +340,18 @@ class Typecho_I18n_GetText
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
*/
private function get_translation_string($num)
private function getTranslationString($num): string
{
$length = $this->table_translations[$num * 2 + 1];
$offset = $this->table_translations[$num * 2 + 2];
if (!$length)
if (!$length) {
return '';
}
fseek($this->STREAM, $offset);
$data = fread($this->STREAM, $length);
return (string)$data;
}
/**
* Plural version of gettext
*
* @access public
* @param string single
* @param string plural
* @param string number
* @param integer $num found string number
* @return translated plural form
*/
public function ngettext($single, $plural, $number, &$num)
{
$number = intval($number);
if ($this->short_circuit) {
if ($number != 1)
return $plural;
else
return $single;
}
// find out the appropriate form
$select = $this->select_string($number);
// this should contains all strings separated by NULLs
$key = $single . chr(0) . $plural;
if ($this->enable_cache) {
if (!array_key_exists($key, $this->cache_translations)) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->cache_translations[$key];
$list = explode(chr(0), $result);
return $list[$select];
}
} else {
$num = $this->find_string($key);
if ($num == - 1) {
return ($number != 1) ? $plural : $single;
} else {
$result = $this->get_translation_string($num);
$list = explode(chr(0), $result);
return $list[$select];
}
}
}
/**
* Detects which plural form to take
*
@@ -340,9 +359,9 @@ class Typecho_I18n_GetText
* @param n count
* @return int array index of the right plural form
*/
private function select_string($n)
private function selectString($n): int
{
$string = $this->get_plural_forms();
$string = $this->getPluralForms();
$string = str_replace('nplurals', "\$total", $string);
$string = str_replace("n", $n, $string);
$string = str_replace('plural', "\$plural", $string);
@@ -351,7 +370,9 @@ class Typecho_I18n_GetText
$plural = 0;
eval("$string");
if ($plural >= $total) $plural = $total - 1;
if ($plural >= $total) {
$plural = $total - 1;
}
return $plural;
}
@@ -361,36 +382,26 @@ class Typecho_I18n_GetText
* @access private
* @return string plural form header
*/
private function get_plural_forms()
private function getPluralForms(): string
{
// lets assume message number 0 is header
// this is true, right?
$this->load_tables();
$this->loadTables();
// cache header field for plural forms
if (!is_string($this->pluralheader)) {
if (!is_string($this->pluralHeader)) {
if ($this->enable_cache) {
$header = $this->cache_translations[""];
} else {
$header = $this->get_translation_string(0);
$header = $this->getTranslationString(0);
}
if (preg_match("/plural\-forms: ([^\n]*)\n/i", $header, $regs))
if (preg_match("/plural\-forms: ([^\n]*)\n/i", $header, $regs)) {
$expr = $regs[1];
else
} else {
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
$this->pluralheader = $expr;
}
$this->pluralHeader = $expr;
}
return $this->pluralheader;
}
/**
* 关闭文件句柄
*
* @access public
* @return void
*/
public function __destruct()
{
fclose($this->STREAM);
return $this->pluralHeader;
}
}
+16 -21
View File
@@ -1,11 +1,6 @@
<?php
/**
* Typecho Blog Platform
*
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id$
*/
namespace Typecho\I18n;
/**
* 用于解决一个多个mo文件带来的读写问题
@@ -15,15 +10,15 @@
* @category typecho
* @package I18n
*/
class Typecho_I18n_GetTextMulti
class GetTextMulti
{
/**
* 所有的文件读写句柄
*
* @access private
* @var Typecho_I18n_GetText[]
* @var GetText[]
*/
private $_handles = [];
private $handlers = [];
/**
* 构造函数
@@ -32,7 +27,7 @@ class Typecho_I18n_GetTextMulti
* @param string $fileName 语言文件名
* @return void
*/
public function __construct($fileName)
public function __construct(string $fileName)
{
$this->addFile($fileName);
}
@@ -44,9 +39,9 @@ class Typecho_I18n_GetTextMulti
* @param string $fileName 语言文件名
* @return void
*/
public function addFile($fileName)
public function addFile(string $fileName)
{
$this->_handles[] = new Typecho_I18n_GetText($fileName, true);
$this->handlers[] = new GetText($fileName, true);
}
/**
@@ -56,9 +51,9 @@ class Typecho_I18n_GetTextMulti
* @param string string to be translated
* @return string translated string (or original, if not found)
*/
public function translate($string)
public function translate(string $string): string
{
foreach ($this->_handles as $handle) {
foreach ($this->handlers as $handle) {
$string = $handle->translate($string, $count);
if (- 1 != $count) {
break;
@@ -75,14 +70,14 @@ class Typecho_I18n_GetTextMulti
* @param string single
* @param string plural
* @param string number
* @return translated plural form
* @return string translated plural form
*/
public function ngettext($single, $plural, $number)
public function ngettext($single, $plural, $number): string
{
$count = - 1;
foreach ($this->_handles as $handle) {
$string = $handle->ngettext($single, $plural, $number, $count);
foreach ($this->handlers as $handler) {
$string = $handler->ngettext($single, $plural, $number, $count);
if (- 1 != $count) {
break;
}
@@ -99,9 +94,9 @@ class Typecho_I18n_GetTextMulti
*/
public function __destruct()
{
foreach ($this->_handles as $handle) {
foreach ($this->handlers as $handler) {
/** 显示的释放内存 */
unset($handle);
unset($handler);
}
}
}
+2 -2
View File
@@ -41,13 +41,13 @@ class Router
*
* @access public
*
* @param string $pathInfo 全路径
* @param string|null $pathInfo 全路径
* @param mixed $parameter 输入参数
*
* @return false|Widget
* @throws \Exception
*/
public static function match(string $pathInfo, $parameter = null)
public static function match(?string $pathInfo, $parameter = null)
{
foreach (self::$routingTable as $key => $route) {
if (preg_match($route['regx'], $pathInfo, $matches)) {