YiiDebugToolbarRoute.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. /**
  3. * YiiDebugToolbarRouter class file.
  4. *
  5. * @author Sergey Malyshev <malyshev.php@gmail.com>
  6. */
  7. /**
  8. * YiiDebugToolbarRouter represents an ...
  9. *
  10. * Description of YiiDebugToolbarRouter
  11. *
  12. * @author Sergey Malyshev <malyshev.php@gmail.com>
  13. * @version $Id$
  14. * @package YiiDebugToolbar
  15. * @since 1.1.7
  16. */
  17. class YiiDebugToolbarRoute extends CLogRoute
  18. {
  19. private $_panels = array(
  20. //'YiiDebugToolbarPanelServer',
  21. 'YiiDebugToolbarPanelRequest',
  22. 'YiiDebugToolbarPanelSettings',
  23. 'YiiDebugToolbarPanelViews',
  24. 'YiiDebugToolbarPanelSql',
  25. 'YiiDebugToolbarPanelLogging',
  26. );
  27. /**
  28. * The filters are given in an array, each filter being:
  29. * - a normal IP (192.168.0.10 or '::1')
  30. * - an incomplete IP (192.168.0.* or 192.168.0.)
  31. * - a CIDR mask (192.168.0.0/24)
  32. * - "*" for everything.
  33. */
  34. public $ipFilters=array('127.0.0.1','::1');
  35. /**
  36. * Whitelist for response content types. DebugToolbarRoute won't write any
  37. * output if the server generates output that isn't listed here (json, xml,
  38. * files, ...)
  39. * @var array of content type strings (in lower case)
  40. */
  41. public $contentTypeWhitelist = array(
  42. // Yii framework doesn't seem to send content-type header by default.
  43. '',
  44. 'text/html',
  45. 'application/xhtml+xml',
  46. );
  47. private $_toolbarWidget,
  48. $_startTime,
  49. $_endTime;
  50. private $_proxyMap = array(
  51. 'viewRenderer' => 'YiiDebugViewRenderer'
  52. );
  53. public function setPanels(array $pannels)
  54. {
  55. $selfPanels = array_fill_keys($this->_panels, array());
  56. $this->_panels = array_merge($selfPanels, $pannels);
  57. }
  58. public function getPanels()
  59. {
  60. return $this->_panels;
  61. }
  62. public function getStartTime()
  63. {
  64. return $this->_startTime;
  65. }
  66. public function getEndTime()
  67. {
  68. return $this->_endTime;
  69. }
  70. public function getLoadTime()
  71. {
  72. return ($this->endTime-$this->startTime);
  73. }
  74. protected function getToolbarWidget()
  75. {
  76. if (null === $this->_toolbarWidget)
  77. {
  78. $this->_toolbarWidget = Yii::createComponent(array(
  79. 'class'=>'YiiDebugToolbar',
  80. 'panels'=> $this->panels
  81. ), $this);
  82. }
  83. return $this->_toolbarWidget;
  84. }
  85. public function init()
  86. {
  87. Yii::app()->controllerMap = array_merge(array(
  88. 'debug' => array(
  89. 'class' => 'YiiDebugController'
  90. )
  91. ), Yii::app()->controllerMap);
  92. Yii::setPathOfAlias('yii-debug-toolbar', dirname(__FILE__));
  93. Yii::app()->setImport(array(
  94. 'yii-debug-toolbar.*'
  95. ));
  96. $route = Yii::app()->getUrlManager()->parseUrl(Yii::app()->getRequest());
  97. $this->enabled = strpos(trim($route, '/'), 'debug') !== 0;
  98. $this->enabled && $this->enabled = ($this->allowIp(Yii::app()->request->userHostAddress)
  99. && !Yii::app()->getRequest()->getIsAjaxRequest() && (Yii::app() instanceof CWebApplication))
  100. && $this->checkContentTypeWhitelist();
  101. if ($this->enabled) {
  102. Yii::app()->attachEventHandler('onBeginRequest', array($this, 'onBeginRequest'));
  103. Yii::app()->attachEventHandler('onEndRequest', array($this, 'onEndRequest'));
  104. $this->categories = '';
  105. $this->levels='';
  106. }
  107. $this->_startTime = microtime(true);
  108. parent::init();
  109. }
  110. protected function onBeginRequest(CEvent $event)
  111. {
  112. $this->initComponents();
  113. $this->getToolbarWidget()
  114. ->init();
  115. }
  116. protected function initComponents()
  117. {
  118. foreach ($this->_proxyMap as $name=>$class) {
  119. $instance = Yii::app()->getComponent($name);
  120. if (null !== ($instance)) {
  121. Yii::app()->setComponent($name, null);
  122. }
  123. $this->_proxyMap[$name] = array(
  124. 'class'=>$class,
  125. 'instance' => $instance
  126. );
  127. }
  128. Yii::app()->setComponents($this->_proxyMap, false);
  129. }
  130. /**
  131. * Processes the current request.
  132. * It first resolves the request into controller and action,
  133. * and then creates the controller to perform the action.
  134. */
  135. private function processRequest()
  136. {
  137. if (is_array(Yii::app()->catchAllRequest) && isset(Yii::app()->catchAllRequest[0])) {
  138. $route = Yii::app()->catchAllRequest[0];
  139. foreach(array_splice(Yii::app()->catchAllRequest,1) as $name=>$value)
  140. $_GET[$name] = $value;
  141. } else {
  142. $route = Yii::app()->getUrlManager()->parseUrl(Yii::app()->getRequest());
  143. }
  144. Yii::app()->runController($route);
  145. }
  146. protected function onEndRequest(CEvent $event)
  147. {
  148. $this->_endTime = microtime(true);
  149. }
  150. public function collectLogs($logger, $processLogs=false)
  151. {
  152. $logs = $logger->getLogs();
  153. $this->logs = empty($this->logs) ? $logs : array_merge($this->logs, $logs);
  154. $this->processLogs($this->logs);
  155. $this->logs = array();
  156. }
  157. protected function processLogs($logs)
  158. {
  159. $this->getToolbarWidget()->run();
  160. }
  161. private function checkContentTypeWhitelist()
  162. {
  163. $contentType = '';
  164. foreach (headers_list() as $header) {
  165. list($key, $value) = explode(':', $header);
  166. $value = ltrim($value, ' ');
  167. if (strtolower($key) === 'content-type') {
  168. // Split encoding if exists
  169. $contentType = explode(";", strtolower($value));
  170. $contentType = current($contentType);
  171. break;
  172. }
  173. }
  174. return in_array( $contentType, $this->contentTypeWhitelist );
  175. }
  176. /**
  177. * Checks to see if the user IP is allowed by {@link ipFilters}.
  178. * @param string $ip the user IP
  179. * @return boolean whether the user IP is allowed by {@link ipFilters}.
  180. */
  181. protected function allowIp($ip)
  182. {
  183. foreach ($this->ipFilters as $filter)
  184. {
  185. $filter = trim($filter);
  186. // normal or incomplete IPv4
  187. if (preg_match('/^[\d\.]*\*?$/', $filter)) {
  188. $filter = rtrim($filter, '*');
  189. if (strncmp($ip, $filter, strlen($filter)) === 0)
  190. {
  191. return true;
  192. }
  193. }
  194. // CIDR
  195. else if (preg_match('/^([\d\.]+)\/(\d+)$/', $filter, $match))
  196. {
  197. if (self::matchIpMask($ip, $match[1], $match[2]))
  198. {
  199. return true;
  200. }
  201. }
  202. // IPv6
  203. else if ($ip === $filter)
  204. {
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. /**
  211. * Check if an IP matches a CIDR mask.
  212. *
  213. * @param integer|string $ip IP to check.
  214. * @param integer|string $matchIp Radical of the mask (e.g. 192.168.0.0).
  215. * @param integer $maskBits Size of the mask (e.g. 24).
  216. */
  217. protected static function matchIpMask($ip, $maskIp, $maskBits)
  218. {
  219. $mask =~ (pow(2, 32-$maskBits)-1);
  220. if (false === is_int($ip))
  221. {
  222. $ip = ip2long($ip);
  223. }
  224. if (false === is_int($maskIp))
  225. {
  226. $maskIp = ip2long($maskIp);
  227. }
  228. if (($ip & $mask) === ($maskIp & $mask))
  229. {
  230. return true;
  231. } else {
  232. return false;
  233. }
  234. }
  235. }