HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
Yii2Debug.php
Go to the documentation of this file.
1 <?php
2 
12 class Yii2Debug extends CApplicationComponent
13 {
21  public $allowedIPs = array('127.0.0.1', '::1');
32  public $panels = array();
36  public $logPath;
41  public $historySize = 50;
45  public $enabled = true;
49  public $moduleId = 'debug';
53  public $internalUrls = true;
57  public $highlightCode = true;
61  public $showConfig = false;
66  public $hiddenConfigOptions = array(
67  'components/db/username',
68  'components/db/password',
69  );
70 
71  private $_tag;
72 
77  public function init()
78  {
79  parent::init();
80  if (!$this->enabled) return;
81 
82  Yii::setPathOfAlias('yii2-debug', dirname(__FILE__));
83  Yii::app()->setImport(array(
84  'yii2-debug.*',
85  'yii2-debug.panels.*',
86  ));
87 
88  if ($this->logPath === null) {
89  $this->logPath = Yii::app()->getRuntimePath() . '/debug';
90  }
91 
92  $panels = array();
93  foreach (CMap::mergeArray($this->corePanels(), $this->panels) as $id => $config) {
94  if (!isset($config['highlightCode'])) $config['highlightCode'] = $this->highlightCode;
95  $panels[$id] = Yii::createComponent($config, $this, $id);
96  }
97  $this->panels = $panels;
98 
99  Yii::app()->setModules(array(
100  $this->moduleId => array(
101  'class' => 'Yii2DebugModule',
102  'owner' => $this,
103  ),
104  ));
105 
106  if ($this->internalUrls && (Yii::app()->getUrlManager()->urlFormat == 'path')) {
107  $rules = array();
108  foreach ($this->coreUrlRules() as $key => $value) {
109  $rules[$this->moduleId . '/' . $key] = $this->moduleId . '/' . $value;
110  }
111  Yii::app()->getUrlManager()->addRules($rules, false);
112  }
113 
114  Yii::app()->attachEventHandler('onEndRequest', array($this, 'onEndRequest'));
115  $this->initToolbar();
116  }
117 
121  public function getTag()
122  {
123  if ($this->_tag === null) $this->_tag = uniqid();
124  return $this->_tag;
125  }
126 
130  protected function corePanels()
131  {
132  return array(
133  'config' => array(
134  'class' => 'Yii2ConfigPanel',
135  ),
136  'request' => array(
137  'class' => 'Yii2RequestPanel',
138  ),
139  'log' => array(
140  'class' => 'Yii2LogPanel',
141  ),
142  'profiling' => array(
143  'class' => 'Yii2ProfilingPanel',
144  ),
145  'db' => array(
146  'class' => 'Yii2DbPanel',
147  ),
148  );
149  }
150 
151  protected function coreUrlRules()
152  {
153  return array(
154  '' => 'default/index',
155  '<tag:[0-9a-f]+>/<action:toolbar|explain>' => 'default/<action>',
156  '<tag:[0-9a-f]+>/<panel:\w+>' => 'default/view',
157  'latest/<panel:\w+>' => 'default/view',
158  '<action:\w+>' => 'default/<action>',
159  );
160  }
161 
165  protected function initToolbar()
166  {
167  if (!$this->checkAccess()) return;
168  $assetsUrl = CHtml::asset(dirname(__FILE__) . '/assets');
169  /* @var CClientScript $cs */
170  $cs = Yii::app()->getClientScript();
171  $cs->registerCoreScript('jquery');
172  $url = Yii::app()->createUrl($this->moduleId . '/default/toolbar', array('tag' => $this->getTag()));
173  $cs->registerScript(__CLASS__ . '#toolbar', <<<JS
174 (function($){
175  $('<div>').appendTo('body').load('$url', function(){
176  if (window.localStorage && localStorage.getItem('yii2-debug-toolbar') == 'minimized') {
177  $('#yii2-debug-toolbar').hide();
178  $('#yii2-debug-toolbar-min').show();
179  } else {
180  $('#yii2-debug-toolbar-min').hide();
181  $('#yii2-debug-toolbar').show();
182  }
183  $('#yii2-debug-toolbar .yii2-debug-toolbar-toggler').click(function(){
184  $('#yii2-debug-toolbar').hide();
185  $('#yii2-debug-toolbar-min').show();
186  if (window.localStorage) {
187  localStorage.setItem('yii2-debug-toolbar', 'minimized');
188  }
189  });
190  $('#yii2-debug-toolbar-min .yii2-debug-toolbar-toggler').click(function(){
191  $('#yii2-debug-toolbar-min').hide();
192  $('#yii2-debug-toolbar').show();
193  if (window.localStorage) {
194  localStorage.setItem('yii2-debug-toolbar', 'maximized');
195  }
196  });
197  });
198 })(jQuery);
199 JS
200  );
201  }
202 
206  protected function onEndRequest($event)
207  {
208  $this->processDebug();
209  }
210 
214  protected function processDebug()
215  {
216  $path = $this->logPath;
217  if (!is_dir($path)) mkdir($path);
218 
219  $indexFile = "$path/index.data";
220  $manifest = array();
221  if (is_file($indexFile)) {
222  $manifest = unserialize(file_get_contents($indexFile));
223  }
224 
225  $data = array();
226  foreach ($this->panels as $panel) {
227  $data[$panel->getId()] = $panel->save();
228  if (isset($panel->filterData)) {
229  $data[$panel->getId()] = $panel->evaluateExpression(
230  $panel->filterData,
231  array('data' => $data[$panel->getId()])
232  );
233  }
234  $panel->load($data[$panel->getId()]);
235  }
236 
237  $statusCode = null;
238  if (isset($this->panels['request']) && isset($this->panels['request']->data['statusCode'])) {
239  $statusCode = $this->panels['request']->data['statusCode'];
240  }
241 
242  $request = Yii::app()->getRequest();
243  $manifest[$this->getTag()] = $data['summary'] = array(
244  'tag' => $this->getTag(),
245  'url' => $request->getHostInfo() . $request->getUrl(),
246  'ajax' => $request->getIsAjaxRequest(),
247  'method' => $request->getRequestType(),
248  'code' => $statusCode,
249  'ip' => $request->getUserHostAddress(),
250  'time' => time(),
251  );
252  $this->resizeHistory($manifest);
253 
254  file_put_contents("$path/{$this->getTag()}.data", serialize($data));
255  file_put_contents($indexFile, serialize($manifest));
256  }
257 
262  protected function resizeHistory(&$manifest)
263  {
264  $tags = array_keys($manifest);
265  $count = 0;
266  foreach ($tags as $tag) {
267  if (!$this->getLock($tag)) $count++;
268  }
269  if ($count > $this->historySize + 10) {
270  $path = $this->logPath;
271  $n = $count - $this->historySize;
272  foreach ($tags as $tag) {
273  if (!$this->getLock($tag)) {
274  @unlink("$path/$tag.data");
275  unset($manifest[$tag]);
276  if (--$n <= 0) break;
277  }
278  }
279  }
280  }
281 
286  public function checkAccess()
287  {
288  if (
289  $this->accessExpression !== null &&
290  !$this->evaluateExpression($this->accessExpression)
291  ) {
292  return false;
293  }
294  $ip = Yii::app()->getRequest()->getUserHostAddress();
295  foreach ($this->allowedIPs as $filter) {
296  if (
297  $filter === '*' || $filter === $ip || (
298  ($pos = strpos($filter, '*')) !== false &&
299  !strncmp($ip, $filter, $pos)
300  )
301  ) {
302  return true;
303  }
304  }
305  return false;
306  }
307 
312  public static function dump($data)
313  {
314  Yii::log(serialize($data), CLogger::LEVEL_INFO, Yii2LogPanel::CATEGORY_DUMP);
315  }
316 
320  private $_locks;
321 
326  public function getLock($tag)
327  {
328  if ($this->_locks === null) {
329  $locksFile = $this->logPath . '/locks.data';
330  if (is_file($locksFile)) {
331  $this->_locks = array_flip(unserialize(file_get_contents($locksFile)));
332  } else {
333  $this->_locks = array();
334  }
335  }
336  return isset($this->_locks[$tag]);
337  }
338 
343  public function setLock($tag, $value)
344  {
345  $value = !!$value;
346  if ($this->getLock($tag) !== $value) {
347  if ($value) {
348  $this->_locks[$tag] = true;
349  } else {
350  unset($this->_locks[$tag]);
351  }
352  $locksFile = $this->logPath . '/locks.data';
353  file_put_contents($locksFile, serialize(array_keys($this->_locks)));
354  }
355  }
356 
362  public static function prepareData($data)
363  {
364  static $parents = array();
365 
366  $result = array();
367  if (is_array($data) || $data instanceof CMap) {
368  foreach ($data as $key => $value) {
369  $result[$key] = self::prepareData($value);
370  }
371  } elseif (is_object($data)) {
372  if (!in_array($data, $parents, true)) {
373  array_push($parents, $data);
374  $result['class'] = get_class($data);
375  if ($data instanceof CActiveRecord) {
376  foreach ($data->attributes as $field => $value) {
377  $result[$field] = $value;
378  }
379  }
380  foreach (get_object_vars($data) as $key => $value) {
381  $result[$key] = self::prepareData($value);
382  }
383  array_pop($parents);
384  } else {
385  $result = get_class($data) . '()';
386  }
387  } else {
388  $result = $data;
389  }
390  return $result;
391  }
392 }