侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Zend Framework教程之Zend_Controller_Plugin插件用法详解

框架(架构)  /  管理员 发布于 7年前   138

本文实例讲述了Zend Framework教程之Zend_Controller_Plugin插件用法。分享给大家供大家参考,具体如下:

通过Zend_Controller_Plugin可以向前端控制器增加附加的功能。便于w一些特殊功能。以下是Zend_Controller_Plugin的简单介绍。

Zend_Controller_Plugin的基本实现

├── Plugin
│   ├── Abstract.php
│   ├── ActionStack.php
│   ├── Broker.php
│   ├── ErrorHandler.php
│   └── PutHandler.php

Zend_Controller_Plugin_Abstract

abstract class Zend_Controller_Plugin_Abstract{ protected $_request; protected $_response; public function setRequest(Zend_Controller_Request_Abstract $request) {  $this->_request = $request;  return $this; } public function getRequest() {  return $this->_request; } public function setResponse(Zend_Controller_Response_Abstract $response) {  $this->_response = $response;  return $this; } public function getResponse() {  return $this->_response; } /**  * Called before Zend_Controller_Front begins evaluating the  * request against its routes.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function routeStartup(Zend_Controller_Request_Abstract $request) {} /**  * Called after Zend_Controller_Router exits.  *  * Called after Zend_Controller_Front exits from the router.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function routeShutdown(Zend_Controller_Request_Abstract $request) {} /**  * Called before Zend_Controller_Front enters its dispatch loop.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) {} /**  * Called before an action is dispatched by Zend_Controller_Dispatcher.  *  * This callback allows for proxy or filter behavior. By altering the  * request and resetting its dispatched flag (via  * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),  * the current action may be skipped.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function preDispatch(Zend_Controller_Request_Abstract $request) {} /**  * Called after an action is dispatched by Zend_Controller_Dispatcher.  *  * This callback allows for proxy or filter behavior. By altering the  * request and resetting its dispatched flag (via  * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),  * a new action may be specified for dispatching.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function postDispatch(Zend_Controller_Request_Abstract $request) {} /**  * Called before Zend_Controller_Front exits its dispatch loop.  *  * @return void  */ public function dispatchLoopShutdown() {}}

Zend_Controller_Plugin_Abstract声明定义了Zend_Controller运行过程中的几个关键事件位置。用户可以通过指定的方法,对指定位置的请求和相应对象进行相关操作。

Zend_Controller_Plugin_Abstract中方法的描述如下:

routeStartup() 在 Zend_Controller_Front 向注册的 路由器 发送请求前被调用。
routeShutdown()在 路由器 完成请求的路由后被调用。
dispatchLoopStartup() 在 Zend_Controller_Front 进入其分发循环(dispatch loop)前被调用。
preDispatch() 在动作由 分发器 分发前被调用。该回调方法允许代理或者过滤行为。通过修改请求和重设分发标志位(利用 Zend_Controller_Request_Abstract::setDispatched(false) )当前动作可以跳过或者被替换。
postDispatch() 在动作由 分发器 分发后被调用。该回调方法允许代理或者过滤行为。通过修改请求和重设分发标志位(利用 Zend_Controller_Request_Abstract::setDispatched(false) )可以指定新动作进行分发。
dispatchLoopShutdown() 在 Zend_Controller_Front 推出其分发循环后调用。

Zend_Controller_Plugin提供的默认插件:

Zend_Controller_Plugin_Broker:插件经纪人,用于注册,管理自定义的Zend_Controller插件。具体用法,可以参考类代码。
Zend_Controller_Plugin_ActionStack:用于管理动作堆栈。具体用法,可以参考类代码。
Zend_Controller_Plugin_ErrorHandler:用来处理抛出的异常。具体用法,可以参考类代码。
Zend_Controller_Plugin_PutHandler:用于处理请求操作 PUT 。具体用法,可以参考类代码。

Zend_Controller_Plugin_Broker

_plugins, true)) {   require_once 'Zend/Controller/Exception.php';   throw new Zend_Controller_Exception('Plugin already registered');  }  $stackIndex = (int) $stackIndex;  if ($stackIndex) {   if (isset($this->_plugins[$stackIndex])) {    require_once 'Zend/Controller/Exception.php';    throw new Zend_Controller_Exception('Plugin with stackIndex "' . $stackIndex . '" already registered');   }   $this->_plugins[$stackIndex] = $plugin;  } else {   $stackIndex = count($this->_plugins);   while (isset($this->_plugins[$stackIndex])) {    ++$stackIndex;   }   $this->_plugins[$stackIndex] = $plugin;  }  $request = $this->getRequest();  if ($request) {   $this->_plugins[$stackIndex]->setRequest($request);  }  $response = $this->getResponse();  if ($response) {   $this->_plugins[$stackIndex]->setResponse($response);  }  ksort($this->_plugins);  return $this; } /**  * Unregister a plugin.  *  * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin object or class name  * @return Zend_Controller_Plugin_Broker  */ public function unregisterPlugin($plugin) {  if ($plugin instanceof Zend_Controller_Plugin_Abstract) {   // Given a plugin object, find it in the array   $key = array_search($plugin, $this->_plugins, true);   if (false === $key) {    require_once 'Zend/Controller/Exception.php';    throw new Zend_Controller_Exception('Plugin never registered.');   }   unset($this->_plugins[$key]);  } elseif (is_string($plugin)) {   // Given a plugin class, find all plugins of that class and unset them   foreach ($this->_plugins as $key => $_plugin) {    $type = get_class($_plugin);    if ($plugin == $type) {     unset($this->_plugins[$key]);    }   }  }  return $this; } /**  * Is a plugin of a particular class registered?  *  * @param string $class  * @return bool  */ public function hasPlugin($class) {  foreach ($this->_plugins as $plugin) {   $type = get_class($plugin);   if ($class == $type) {    return true;   }  }  return false; } /**  * Retrieve a plugin or plugins by class  *  * @param string $class Class name of plugin(s) desired  * @return false|Zend_Controller_Plugin_Abstract|array Returns false if none found, plugin if only one found, and array of plugins if multiple plugins of same class found  */ public function getPlugin($class) {  $found = array();  foreach ($this->_plugins as $plugin) {   $type = get_class($plugin);   if ($class == $type) {    $found[] = $plugin;   }  }  switch (count($found)) {   case 0:    return false;   case 1:    return $found[0];   default:    return $found;  } } /**  * Retrieve all plugins  *  * @return array  */ public function getPlugins() {  return $this->_plugins; } /**  * Set request object, and register with each plugin  *  * @param Zend_Controller_Request_Abstract $request  * @return Zend_Controller_Plugin_Broker  */ public function setRequest(Zend_Controller_Request_Abstract $request) {  $this->_request = $request;  foreach ($this->_plugins as $plugin) {   $plugin->setRequest($request);  }  return $this; } /**  * Get request object  *  * @return Zend_Controller_Request_Abstract $request  */ public function getRequest() {  return $this->_request; } /**  * Set response object  *  * @param Zend_Controller_Response_Abstract $response  * @return Zend_Controller_Plugin_Broker  */ public function setResponse(Zend_Controller_Response_Abstract $response) {  $this->_response = $response;  foreach ($this->_plugins as $plugin) {   $plugin->setResponse($response);  }  return $this; } /**  * Get response object  *  * @return Zend_Controller_Response_Abstract $response  */ public function getResponse() {  return $this->_response; } /**  * Called before Zend_Controller_Front begins evaluating the  * request against its routes.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function routeStartup(Zend_Controller_Request_Abstract $request) {  foreach ($this->_plugins as $plugin) {   try {    $plugin->routeStartup($request);   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);    }   }  } } /**  * Called before Zend_Controller_Front exits its iterations over  * the route set.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function routeShutdown(Zend_Controller_Request_Abstract $request) {  foreach ($this->_plugins as $plugin) {   try {    $plugin->routeShutdown($request);   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);    }   }  } } /**  * Called before Zend_Controller_Front enters its dispatch loop.  *  * During the dispatch loop, Zend_Controller_Front keeps a  * Zend_Controller_Request_Abstract object, and uses  * Zend_Controller_Dispatcher to dispatch the  * Zend_Controller_Request_Abstract object to controllers/actions.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) {  foreach ($this->_plugins as $plugin) {   try {    $plugin->dispatchLoopStartup($request);   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);    }   }  } } /**  * Called before an action is dispatched by Zend_Controller_Dispatcher.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function preDispatch(Zend_Controller_Request_Abstract $request) {  foreach ($this->_plugins as $plugin) {   try {    $plugin->preDispatch($request);   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);     // skip rendering of normal dispatch give the error handler a try     $this->getRequest()->setDispatched(false);    }   }  } } /**  * Called after an action is dispatched by Zend_Controller_Dispatcher.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function postDispatch(Zend_Controller_Request_Abstract $request) {  foreach ($this->_plugins as $plugin) {   try {    $plugin->postDispatch($request);   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);    }   }  } } /**  * Called before Zend_Controller_Front exits its dispatch loop.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function dispatchLoopShutdown() {  foreach ($this->_plugins as $plugin) {   try {    $plugin->dispatchLoopShutdown();   } catch (Exception $e) {    if (Zend_Controller_Front::getInstance()->throwExceptions()) {     throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e);    } else {     $this->getResponse()->setException($e);    }   }  } }}

Zend_Controller_Plugin_ActionStack

setRegistry($registry);  if (null !== $key) {   $this->setRegistryKey($key);  } else {   $key = $this->getRegistryKey();  }  $registry[$key] = array(); } /**  * Set registry object  *  * @param Zend_Registry $registry  * @return Zend_Controller_Plugin_ActionStack  */ public function setRegistry(Zend_Registry $registry) {  $this->_registry = $registry;  return $this; } /**  * Retrieve registry object  *  * @return Zend_Registry  */ public function getRegistry() {  return $this->_registry; } /**  * Retrieve registry key  *  * @return string  */ public function getRegistryKey() {  return $this->_registryKey; } /**  * Set registry key  *  * @param string $key  * @return Zend_Controller_Plugin_ActionStack  */ public function setRegistryKey($key) {  $this->_registryKey = (string) $key;  return $this; } /**  * Set clearRequestParams flag  *  * @param bool $clearRequestParams  * @return Zend_Controller_Plugin_ActionStack  */ public function setClearRequestParams($clearRequestParams) {  $this->_clearRequestParams = (bool) $clearRequestParams;  return $this; } /**  * Retrieve clearRequestParams flag  *  * @return bool  */ public function getClearRequestParams() {  return $this->_clearRequestParams; } /**  * Retrieve action stack  *  * @return array  */ public function getStack() {  $registry = $this->getRegistry();  $stack = $registry[$this->getRegistryKey()];  return $stack; } /**  * Save stack to registry  *  * @param array $stack  * @return Zend_Controller_Plugin_ActionStack  */ protected function _saveStack(array $stack) {  $registry = $this->getRegistry();  $registry[$this->getRegistryKey()] = $stack;  return $this; } /**  * Push an item onto the stack  *  * @param Zend_Controller_Request_Abstract $next  * @return Zend_Controller_Plugin_ActionStack  */ public function pushStack(Zend_Controller_Request_Abstract $next) {  $stack = $this->getStack();  array_push($stack, $next);  return $this->_saveStack($stack); } /**  * Pop an item off the action stack  *  * @return false|Zend_Controller_Request_Abstract  */ public function popStack() {  $stack = $this->getStack();  if (0 == count($stack)) {   return false;  }  $next = array_pop($stack);  $this->_saveStack($stack);  if (!$next instanceof Zend_Controller_Request_Abstract) {   require_once 'Zend/Controller/Exception.php';   throw new Zend_Controller_Exception('ArrayStack should only contain request objects');  }  $action = $next->getActionName();  if (empty($action)) {   return $this->popStack($stack);  }  $request = $this->getRequest();  $controller = $next->getControllerName();  if (empty($controller)) {   $next->setControllerName($request->getControllerName());  }  $module = $next->getModuleName();  if (empty($module)) {   $next->setModuleName($request->getModuleName());  }  return $next; } /**  * postDispatch() plugin hook -- check for actions in stack, and dispatch if any found  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ public function postDispatch(Zend_Controller_Request_Abstract $request) {  // Don't move on to next request if this is already an attempt to  // forward  if (!$request->isDispatched()) {   return;  }  $this->setRequest($request);  $stack = $this->getStack();  if (empty($stack)) {   return;  }  $next = $this->popStack();  if (!$next) {   return;  }  $this->forward($next); } /**  * Forward request with next action  *  * @param array $next  * @return void  */ public function forward(Zend_Controller_Request_Abstract $next) {  $request = $this->getRequest();  if ($this->getClearRequestParams()) {   $request->clearParams();  }  $request->setModuleName($next->getModuleName())    ->setControllerName($next->getControllerName())    ->setActionName($next->getActionName())    ->setParams($next->getParams())    ->setDispatched(false); }}

Zend_Controller_Plugin_ErrorHandler

setErrorHandler($options); } /**  * setErrorHandler() - setup the error handling options  *  * @param array $options  * @return Zend_Controller_Plugin_ErrorHandler  */ public function setErrorHandler(Array $options = array()) {  if (isset($options['module'])) {   $this->setErrorHandlerModule($options['module']);  }  if (isset($options['controller'])) {   $this->setErrorHandlerController($options['controller']);  }  if (isset($options['action'])) {   $this->setErrorHandlerAction($options['action']);  }  return $this; } /**  * Set the module name for the error handler  *  * @param string $module  * @return Zend_Controller_Plugin_ErrorHandler  */ public function setErrorHandlerModule($module) {  $this->_errorModule = (string) $module;  return $this; } /**  * Retrieve the current error handler module  *  * @return string  */ public function getErrorHandlerModule() {  if (null === $this->_errorModule) {   $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule();  }  return $this->_errorModule; } /**  * Set the controller name for the error handler  *  * @param string $controller  * @return Zend_Controller_Plugin_ErrorHandler  */ public function setErrorHandlerController($controller) {  $this->_errorController = (string) $controller;  return $this; } /**  * Retrieve the current error handler controller  *  * @return string  */ public function getErrorHandlerController() {  return $this->_errorController; } /**  * Set the action name for the error handler  *  * @param string $action  * @return Zend_Controller_Plugin_ErrorHandler  */ public function setErrorHandlerAction($action) {  $this->_errorAction = (string) $action;  return $this; } /**  * Retrieve the current error handler action  *  * @return string  */ public function getErrorHandlerAction() {  return $this->_errorAction; } /**  * Route shutdown hook -- Ccheck for router exceptions  *  * @param Zend_Controller_Request_Abstract $request  */ public function routeShutdown(Zend_Controller_Request_Abstract $request) {  $this->_handleError($request); } /**  * Pre dispatch hook -- check for exceptions and dispatch error handler if  * necessary  *  * @param Zend_Controller_Request_Abstract $request  */ public function preDispatch(Zend_Controller_Request_Abstract $request) {  $this->_handleError($request); } /**  * Post dispatch hook -- check for exceptions and dispatch error handler if  * necessary  *  * @param Zend_Controller_Request_Abstract $request  */ public function postDispatch(Zend_Controller_Request_Abstract $request) {  $this->_handleError($request); } /**  * Handle errors and exceptions  *  * If the 'noErrorHandler' front controller flag has been set,  * returns early.  *  * @param Zend_Controller_Request_Abstract $request  * @return void  */ protected function _handleError(Zend_Controller_Request_Abstract $request) {  $frontController = Zend_Controller_Front::getInstance();  if ($frontController->getParam('noErrorHandler')) {   return;  }  $response = $this->getResponse();  if ($this->_isInsideErrorHandlerLoop) {   $exceptions = $response->getException();   if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {    // Exception thrown by error handler; tell the front controller to throw it    $frontController->throwExceptions(true);    throw array_pop($exceptions);   }  }  // check for an exception AND allow the error handler controller the option to forward  if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) {   $this->_isInsideErrorHandlerLoop = true;   // Get exception information   $error   = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);   $exceptions  = $response->getException();   $exception  = $exceptions[0];   $exceptionType = get_class($exception);   $error->exception = $exception;   switch ($exceptionType) {    case 'Zend_Controller_Router_Exception':     if (404 == $exception->getCode()) {      $error->type = self::EXCEPTION_NO_ROUTE;     } else {      $error->type = self::EXCEPTION_OTHER;     }     break;    case 'Zend_Controller_Dispatcher_Exception':     $error->type = self::EXCEPTION_NO_CONTROLLER;     break;    case 'Zend_Controller_Action_Exception':     if (404 == $exception->getCode()) {      $error->type = self::EXCEPTION_NO_ACTION;     } else {      $error->type = self::EXCEPTION_OTHER;     }     break;    default:     $error->type = self::EXCEPTION_OTHER;     break;   }   // Keep a copy of the original request   $error->request = clone $request;   // get a count of the number of exceptions encountered   $this->_exceptionCountAtFirstEncounter = count($exceptions);   // Forward to the error handler   $request->setParam('error_handler', $error)     ->setModuleName($this->getErrorHandlerModule())     ->setControllerName($this->getErrorHandlerController())     ->setActionName($this->getErrorHandlerAction())     ->setDispatched(false);  } }}

Zend_Controller_Plugin_PutHandler

_request->isPut()) {   $putParams = array();   parse_str($this->_request->getRawBody(), $putParams);   $request->setParams($putParams);  } }}

更多关于zend相关内容感兴趣的读者可查看本站专题:《Zend FrameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

希望本文所述对大家PHP程序设计有所帮助。

您可能感兴趣的文章:

  • Zend Framework教程之Zend_Db_Table用法详解
  • zf框架的db类select查询器join链表使用示例(zend框架)
  • PHP 源代码分析 Zend HashTable详解
  • Zend Framework入门知识点小结
  • Zend Framework缓存Cache用法简单实例
  • Zend Framework连接Mysql数据库实例分析
  • Zend Framework+smarty用法实例详解
  • Zend Framework教程之Application和Bootstrap用法详解
  • Zend Framework教程之Loader以及PluginLoader用法详解
  • Zend Framework教程之Autoloading用法详解
  • Zend Framework教程之Resource Autoloading用法实例
  • Zend Framework教程之MVC框架的Controller用法分析
  • Zend Framework教程之路由功能Zend_Controller_Router详解
  • Zend Framework教程之Zend_Db_Table_Row用法实例分析


  • 上一条:
    Zend Framework教程之路由功能Zend_Controller_Router详解
    下一条:
    Zend Framework教程之响应对象的封装Zend_Controller_Response实例详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Filament v3.1版本发布(0个评论)
    • docker + gitea搭建一个git服务器流程步骤(0个评论)
    • websocket的三种架构方式使用优缺点浅析(0个评论)
    • ubuntu20.4系统中宿主机安装nginx服务,docker容器中安装php8.2实现运行laravel10框架网站(0个评论)
    • phpstudy_pro(小皮面板)中安装最新php8.2.9版本流程步骤(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-05
    • 2020-02
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-11
    • 2021-03
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-08
    • 2023-08
    • 2023-10
    • 2023-12
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客