diff --git a/framework/yii/assets.php b/framework/yii/assets.php index 63f7560..0e0d2e6 100644 --- a/framework/yii/assets.php +++ b/framework/yii/assets.php @@ -35,13 +35,6 @@ return array( ), 'depends' => array('yii'), ), - 'yii/debug' => array( - 'sourcePath' => __DIR__ . '/assets', - 'js' => array( - 'yii.debug.js', - ), - 'depends' => array('yii'), - ), 'yii/punycode' => array( 'sourcePath' => __DIR__ . '/assets', 'js' => array( @@ -55,4 +48,17 @@ return array( ), 'depends' => array('yii/jquery'), ), + 'yii/debug' => array( + 'sourcePath' => __DIR__ . '/debug/assets', + 'css' => array( + 'main.css', + ), + 'js' => array( + 'yii.debug.js', + ), + 'depends' => array( + 'yii', + 'yii/bootstrap/responsive', + ), + ), ); diff --git a/framework/yii/base/Action.php b/framework/yii/base/Action.php index 8778cab..429d074 100644 --- a/framework/yii/base/Action.php +++ b/framework/yii/base/Action.php @@ -7,6 +7,8 @@ namespace yii\base; +use Yii; + /** * Action is the base class for all controller action classes. * @@ -75,6 +77,10 @@ class Action extends Component throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.'); } $args = $this->controller->bindActionParams($this, $params); + Yii::info('Running "' . get_class($this) . '::run()" with parameters: ' . var_export($args, true), __METHOD__); + if (Yii::$app->requestedParams === null) { + Yii::$app->requestedParams = $args; + } return call_user_func_array(array($this, 'run'), $args); } } diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index 55f1ab0..ae12244 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -78,6 +78,18 @@ abstract class Application extends Module * Defaults to 256KB. */ public $memoryReserveSize = 262144; + /** + * @var string the requested route + */ + public $requestedRoute; + /** + * @var Action the requested Action. If null, it means the request cannot be resolved into an action. + */ + public $requestedAction; + /** + * @var array the parameters supplied to the requested action. + */ + public $requestedParams; /** * @var string Used to reserve memory for fatal error handler. diff --git a/framework/yii/base/Controller.php b/framework/yii/base/Controller.php index 471fc63..c0c5f2f 100644 --- a/framework/yii/base/Controller.php +++ b/framework/yii/base/Controller.php @@ -107,6 +107,10 @@ class Controller extends Component { $action = $this->createAction($id); if ($action !== null) { + Yii::trace("Route to run: " . $action->getUniqueId(), __METHOD__); + if (Yii::$app->requestedAction === null) { + Yii::$app->requestedAction = $action; + } $oldAction = $this->action; $this->action = $action; $result = null; diff --git a/framework/yii/base/InlineAction.php b/framework/yii/base/InlineAction.php index 75728e0..3a12bc8 100644 --- a/framework/yii/base/InlineAction.php +++ b/framework/yii/base/InlineAction.php @@ -7,6 +7,8 @@ namespace yii\base; +use Yii; + /** * InlineAction represents an action that is defined as a controller method. * @@ -44,6 +46,10 @@ class InlineAction extends Action public function runWithParams($params) { $args = $this->controller->bindActionParams($this, $params); + Yii::info("Running '" . get_class($this->controller) . '::' . $this->actionMethod . "()' with parameters: " . var_export($args, true), __METHOD__); + if (Yii::$app->requestedParams === null) { + Yii::$app->requestedParams = $args; + } return call_user_func_array(array($this->controller, $this->actionMethod), $args); } } diff --git a/framework/yii/bootstrap/assets.php b/framework/yii/bootstrap/assets.php index 95b8d40..0c4a6bc 100644 --- a/framework/yii/bootstrap/assets.php +++ b/framework/yii/bootstrap/assets.php @@ -1,4 +1,9 @@ array( diff --git a/framework/yii/console/Application.php b/framework/yii/console/Application.php index c5e22ab..a69abe0 100644 --- a/framework/yii/console/Application.php +++ b/framework/yii/console/Application.php @@ -92,6 +92,7 @@ class Application extends \yii\base\Application public function handleRequest($request) { list ($route, $params) = $request->resolve(); + $this->requestedRoute = $route; $result = $this->runAction($route, $params); if ($result instanceof Response) { return $result; diff --git a/framework/yii/debug/LogTarget.php b/framework/yii/debug/LogTarget.php index 71478ce..9c00300 100644 --- a/framework/yii/debug/LogTarget.php +++ b/framework/yii/debug/LogTarget.php @@ -21,13 +21,16 @@ class LogTarget extends Target */ public $module; public $tag; - public $historySize = 20; + /** + * @param \yii\debug\Module $module + * @param array $config + */ public function __construct($module, $config = array()) { parent::__construct($config); $this->module = $module; - $this->tag = date('Ymd-His', microtime(true)); + $this->tag = uniqid(); } /** @@ -36,16 +39,32 @@ class LogTarget extends Target */ public function export() { - $path = Yii::$app->getRuntimePath() . '/debug'; + $path = $this->module->dataPath; if (!is_dir($path)) { mkdir($path); } - $file = "$path/{$this->tag}.log"; + $indexFile = "$path/index.json"; + if (!is_file($indexFile)) { + $manifest = array(); + } else { + $manifest = json_decode(file_get_contents($indexFile), true); + } + $request = Yii::$app->getRequest(); + $manifest[$this->tag] = array( + 'url' => $request->getAbsoluteUrl(), + 'ajax' => $request->getIsAjax(), + 'method' => $request->getMethod(), + 'ip' => $request->getUserIP(), + 'time' => time(), + ); + + $dataFile = "$path/{$this->tag}.json"; $data = array(); - foreach ($this->module->panels as $panel) { - $data[$panel->id] = $panel->save(); + foreach ($this->module->panels as $id => $panel) { + $data[$id] = $panel->save(); } - file_put_contents($file, json_encode($data)); + file_put_contents($dataFile, json_encode($data)); + file_put_contents($indexFile, json_encode($manifest)); } /** @@ -58,36 +77,9 @@ class LogTarget extends Target */ public function collect($messages, $final) { - $this->messages = array_merge($this->messages, $this->filterMessages($messages)); + $this->messages = array_merge($this->messages, $messages); if ($final) { $this->export($this->messages); - $this->gc(); - } - } - - protected function gc() - { - if (mt_rand(0, 10000) > 100) { - return; - } - $iterator = new \DirectoryIterator(Yii::$app->getRuntimePath() . '/debug'); - $files = array(); - foreach ($iterator as $file) { - /** @var \DirectoryIterator $file */ - if (preg_match('/^[\d\-]+\.log$/', $file->getFileName()) && $file->isFile()) { - $files[] = $file->getPathname(); - } - } - sort($files); - if (count($files) > $this->historySize) { - $n = count($files) - $this->historySize; - foreach ($files as $i => $file) { - if ($i < $n) { - unlink($file); - } else { - break; - } - } } } } diff --git a/framework/yii/debug/Module.php b/framework/yii/debug/Module.php index c084fad..07ff330 100644 --- a/framework/yii/debug/Module.php +++ b/framework/yii/debug/Module.php @@ -28,27 +28,38 @@ class Module extends \yii\base\Module public $controllerNamespace = 'yii\debug\controllers'; /** + * @var LogTarget + */ + public $logTarget; + /** * @var array|Panel[] */ public $panels = array(); + /** + * @var string the directory storing the debugger data files. This can be specified using a path alias. + */ + public $dataPath = '@runtime/debug'; + public $historySize = 50; public function init() { parent::init(); + $this->dataPath = Yii::getAlias($this->dataPath); + $this->logTarget = Yii::$app->getLog()->targets['debug'] = new LogTarget($this); + Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar')); + foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) { - $config['id'] = $id; + $config['module'] = $this; $this->panels[$id] = Yii::createObject($config); } - - Yii::$app->getLog()->targets['debug'] = new LogTarget($this); - Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar')); } public function beforeAction($action) { Yii::$app->getView()->off(View::EVENT_END_BODY, array($this, 'renderToolbar')); unset(Yii::$app->getLog()->targets['debug']); + $this->logTarget = null; $ip = Yii::$app->getRequest()->getUserIP(); foreach ($this->allowedIPs as $filter) { @@ -63,7 +74,7 @@ class Module extends \yii\base\Module { /** @var View $view */ $id = 'yii-debug-toolbar'; - $tag = Yii::$app->getLog()->targets['debug']->tag; + $tag = $this->logTarget->tag; $url = Yii::$app->getUrlManager()->createUrl('debug/default/toolbar', array( 'tag' => $tag, )); @@ -88,6 +99,12 @@ class Module extends \yii\base\Module 'log' => array( 'class' => 'yii\debug\panels\LogPanel', ), + 'profiling' => array( + 'class' => 'yii\debug\panels\ProfilingPanel', + ), + 'db' => array( + 'class' => 'yii\debug\panels\DbPanel', + ), ); } } diff --git a/framework/yii/debug/Panel.php b/framework/yii/debug/Panel.php index 4db7f62..70ddc92 100644 --- a/framework/yii/debug/Panel.php +++ b/framework/yii/debug/Panel.php @@ -15,7 +15,10 @@ use yii\base\Component; */ class Panel extends Component { - public $id; + /** + * @var Module + */ + public $module; public $data; public function getName() diff --git a/framework/yii/debug/assets/main.css b/framework/yii/debug/assets/main.css new file mode 100644 index 0000000..10c64df --- /dev/null +++ b/framework/yii/debug/assets/main.css @@ -0,0 +1,46 @@ +#yii-debug-toolbar { + position: fixed; + left: 0; + right: 0; + bottom: 0; + margin: 0; + padding: 0; + z-index: 1000000; + font: 11px Verdana, Arial, sans-serif; + text-align: left; + height: 38px; + border-top: 1px solid #ccc; + background: rgb(237,237,237); + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); + background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); +} + +.yii-debug-toolbar-block { + float: left; + margin: 0; + border-right: 1px solid #e4e4e4; + padding: 4px 8px; + line-height: 32px; +} + +.yii-debug-toolbar-block a { + text-decoration: none; + color: black !important; +} + +.yii-debug-toolbar-block span { +} + +.yii-debug-toolbar-block img { + vertical-align: middle; +} + +span.indent { + color: #ccc; +} diff --git a/framework/yii/assets/yii.debug.js b/framework/yii/debug/assets/yii.debug.js similarity index 100% rename from framework/yii/assets/yii.debug.js rename to framework/yii/debug/assets/yii.debug.js diff --git a/framework/yii/debug/controllers/DefaultController.php b/framework/yii/debug/controllers/DefaultController.php index b63bc4b..80be184 100644 --- a/framework/yii/debug/controllers/DefaultController.php +++ b/framework/yii/debug/controllers/DefaultController.php @@ -21,16 +21,22 @@ class DefaultController extends Controller public $module; public $layout = 'main'; - public function actionIndex($tag, $panel = null) + public function actionIndex($tag = null, $panel = null) { - $this->loadData($tag); + if ($tag === null) { + $tags = array_keys($this->getManifest()); + $tag = end($tags); + } + $meta = $this->loadData($tag); if (isset($this->module->panels[$panel])) { $activePanel = $this->module->panels[$panel]; } else { - $activePanel = reset($this->module->panels); + $activePanel = $this->module->panels['request']; } return $this->render('index', array( 'tag' => $tag, + 'meta' => $meta, + 'manifest' => $this->getManifest(), 'panels' => $this->module->panels, 'activePanel' => $activePanel, )); @@ -45,19 +51,53 @@ class DefaultController extends Controller )); } + public function actionPhpinfo() + { + phpinfo(); + } + + private $_manifest; + + protected function getManifest() + { + if ($this->_manifest === null) { + $indexFile = $this->module->dataPath . '/index.json'; + if (is_file($indexFile)) { + $this->_manifest = json_decode(file_get_contents($indexFile), true); + } else { + $this->_manifest = array(); + } + if (count($this->_manifest) > $this->module->historySize) { + $n = count($this->_manifest) - $this->module->historySize; + foreach (array_keys($this->_manifest) as $tag) { + $file = $this->module->dataPath . "/$tag.json"; + @unlink($file); + unset($this->_manifest[$tag]); + if (--$n <= 0) { + break; + } + } + file_put_contents($indexFile, json_encode($this->_manifest)); + } + } + return $this->_manifest; + } + protected function loadData($tag) { - $file = Yii::$app->getRuntimePath() . "/debug/$tag.log"; - if (preg_match('/^[\w\-]+$/', $tag) && is_file($file)) { - $data = json_decode(file_get_contents($file), true); + $manifest = $this->getManifest(); + if (isset($manifest[$tag])) { + $dataFile = $this->module->dataPath . "/$tag.json"; + $data = json_decode(file_get_contents($dataFile), true); foreach ($this->module->panels as $id => $panel) { - if (isset($data[$panel->id])) { - $panel->load($data[$panel->id]); + if (isset($data[$id])) { + $panel->load($data[$id]); } else { // remove the panel since it has not received any data unset($this->module->panels[$id]); } } + return $manifest[$tag]; } else { throw new HttpException(404, "Unable to find debug data tagged with '$tag'."); } diff --git a/framework/yii/debug/panels/ConfigPanel.php b/framework/yii/debug/panels/ConfigPanel.php index 9e19c90..695856c 100644 --- a/framework/yii/debug/panels/ConfigPanel.php +++ b/framework/yii/debug/panels/ConfigPanel.php @@ -19,22 +19,64 @@ class ConfigPanel extends Panel { public function getName() { - return 'Config'; + return 'Configuration'; } public function getSummary() { + $yiiLogo = 'data:image/png;base64,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'; return << - PHP: {$this->data['phpVersion']}, - Yii: {$this->data['phpVersion']} + + + {$this->data['application']['yii']} + + +
+ PHP {$this->data['php']['version']}
EOD; } public function getDetail() { - return '

Config

'; + $app = array( + 'Yii Version' => $this->data['application']['yii'], + 'Application Name' => $this->data['application']['name'], + 'Environment' => $this->data['application']['env'], + 'Debug Mode' => $this->data['application']['debug'] ? 'Yes' : 'No', + ); + $php = array( + 'PHP Version' => $this->data['php']['version'], + 'Xdebug' => $this->data['php']['xdebug'] ? 'Enabled' : 'Disabled', + 'APC' => $this->data['php']['apc'] ? 'Enabled' : 'Disabled', + 'Memcache' => $this->data['php']['memcache'] ? 'Enabled' : 'Disabled', + ); + return "

Configuration

\n" + . $this->renderData('Application Configuration', $app) . "\n" + . $this->renderData('PHP Configuration', $php) . "\n" + . '
' . Html::a('Complete phpinfo()', array('phpinfo'), array('class' => 'btn btn-info')) . "
\n"; + } + + protected function renderData($caption, $values) + { + if (empty($values)) { + return "

$caption

\n

Empty.

"; + } + $rows = array(); + foreach ($values as $name => $value) { + $rows[] = '' . Html::encode($name) . '
' . Html::encode($value) . '
'; + } + $rows = implode("\n", $rows); + return <<$caption + + + +$rows + +
NameValue
+EOD; } public function save() @@ -42,6 +84,18 @@ EOD; return array( 'phpVersion' => PHP_VERSION, 'yiiVersion' => Yii::getVersion(), + 'application' => array( + 'yii' => Yii::getVersion(), + 'name' => Yii::$app->name, + 'env' => YII_ENV, + 'debug' => YII_DEBUG, + ), + 'php' => array( + 'version' => PHP_VERSION, + 'xdebug' => extension_loaded('xdebug'), + 'apc' => extension_loaded('apc'), + 'memcache' => extension_loaded('memcache'), + ), ); } } diff --git a/framework/yii/debug/panels/DbPanel.php b/framework/yii/debug/panels/DbPanel.php new file mode 100644 index 0000000..57cd4d9 --- /dev/null +++ b/framework/yii/debug/panels/DbPanel.php @@ -0,0 +1,21 @@ + + * @since 2.0 + */ +class DbPanel extends Panel +{ + public function getName() + { + return 'Database'; + } +} diff --git a/framework/yii/debug/panels/LogPanel.php b/framework/yii/debug/panels/LogPanel.php index e9de619..d84c493 100644 --- a/framework/yii/debug/panels/LogPanel.php +++ b/framework/yii/debug/panels/LogPanel.php @@ -11,6 +11,7 @@ use Yii; use yii\debug\Panel; use yii\helpers\Html; use yii\log\Logger; +use yii\log\Target; /** * @author Qiang Xue @@ -25,12 +26,29 @@ class LogPanel extends Panel public function getSummary() { - $count = count($this->data['messages']); - return <<data['messages'], Logger::LEVEL_ERROR)); + if ($errorCount === 1) { + $output[] = '1 error'; + } elseif ($errorCount > 1) { + $output[] = "$errorCount errors"; + } + $warningCount = count(Target::filterMessages($this->data['messages'], Logger::LEVEL_WARNING)); + if ($warningCount === 1) { + $output[] = '1 warning'; + } elseif ($warningCount > 1) { + $output[] = "$warningCount warnings"; + } + if (!empty($output)) { + $log = implode(', ', $output); + return << -Log messages: $count +$log EOD; + } else { + return ''; + } } public function getDetail() @@ -40,10 +58,21 @@ EOD; $time = date('H:i:s.', $log[3]) . sprintf('%03d', (int)(($log[3] - (int)$log[3]) * 1000)); $level = Logger::getLevelName($log[1]); $message = Html::encode(wordwrap($log[0])); - $rows[] = "$time$level{$log[2]}$message"; + if ($log[1] == Logger::LEVEL_ERROR) { + $class = ' class="error"'; + } elseif ($log[1] == Logger::LEVEL_WARNING) { + $class = ' class="warning"'; + } elseif ($log[1] == Logger::LEVEL_INFO) { + $class = ' class="info"'; + } else { + $class = ''; + } + $rows[] = "$time$level{$log[2]}$message"; } $rows = implode("\n", $rows); return <<Log Messages + @@ -62,8 +91,10 @@ EOD; public function save() { + $target = $this->module->logTarget; + $messages = $target->filterMessages($target->messages, Logger::LEVEL_ERROR | Logger::LEVEL_INFO | Logger::LEVEL_WARNING | Logger::LEVEL_TRACE); return array( - 'messages' => Yii::$app->getLog()->targets['debug']->messages, + 'messages' => $messages, ); } } diff --git a/framework/yii/debug/panels/ProfilingPanel.php b/framework/yii/debug/panels/ProfilingPanel.php new file mode 100644 index 0000000..c09108e --- /dev/null +++ b/framework/yii/debug/panels/ProfilingPanel.php @@ -0,0 +1,85 @@ + + * @since 2.0 + */ +class ProfilingPanel extends Panel +{ + public function getName() + { + return 'Profiling'; + } + + public function getDetail() + { + $messages = $this->data['messages']; + $timings = array(); + $stack = array(); + foreach ($messages as $i => $log) { + list($token, $level, $category, $timestamp) = $log; + $log[4] = $i; + if ($level == Logger::LEVEL_PROFILE_BEGIN) { + $stack[] = $log; + } elseif ($level == Logger::LEVEL_PROFILE_END) { + if (($last = array_pop($stack)) !== null && $last[0] === $token) { + $timings[$last[4]] = array(count($stack), $token, $category, $timestamp - $last[3]); + } + } + } + + $now = microtime(true); + while (($last = array_pop($stack)) !== null) { + $delta = $now - $last[3]; + $timings[$last[4]] = array(count($stack), $last[0], $last[2], $delta); + } + ksort($timings); + + $rows = array(); + foreach ($timings as $timing) { + $time = sprintf('%.1f ms', $timing[3] * 1000); + $procedure = str_repeat('', $timing[0]) . Html::encode($timing[1]); + $category = Html::encode($timing[2]); + $rows[] = ""; + } + $rows = implode("\n", $rows); + + return <<Performance Profiling + +
$time$category$procedure
+ + + + + + + + +$rows + +
TimeCategoryProcedure
+EOD; + } + + public function save() + { + $target = $this->module->logTarget; + $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE); + return array( + 'messages' => $messages, + ); + } +} diff --git a/framework/yii/debug/panels/RequestPanel.php b/framework/yii/debug/panels/RequestPanel.php index a587c59..2727a3a 100644 --- a/framework/yii/debug/panels/RequestPanel.php +++ b/framework/yii/debug/panels/RequestPanel.php @@ -7,6 +7,8 @@ namespace yii\debug\panels; +use Yii; +use yii\base\InlineAction; use yii\debug\Panel; use yii\helpers\Html; @@ -23,8 +25,8 @@ class RequestPanel extends Panel public function getSummary() { - $memory = sprintf('%.2fMB', $this->data['memory'] / 1048576); - $time = sprintf('%.3fs', $this->data['time']); + $memory = sprintf('%.1f MB', $this->data['memory'] / 1048576); + $time = number_format($this->data['time'] * 1000) . ' ms'; return << @@ -39,37 +41,92 @@ EOD; public function getDetail() { - return "

\$_GET

\n" . $this->renderTable($this->data['GET']) . "\n" - . "

\$_POST

\n" . $this->renderTable($this->data['POST']) . "\n" - . "

\$_COOKIE

\n" . $this->renderTable($this->data['COOKIE']) . "\n" - . "

\$_FILES

\n" . $this->renderTable($this->data['FILES']) . "\n" - . "

\$_SESSION

\n" . $this->renderTable($this->data['SESSION']) . "\n" - . "

\$_SERVER

\n" . $this->renderTable($this->data['SERVER']); + $data = array( + 'Route' => $this->data['route'], + 'Action' => $this->data['action'], + 'Parameters' => $this->data['actionParams'], + ); + return "

Request Information

\n" + . $this->renderData('Routing', $data) . "\n" + . $this->renderData('Flashes', $this->data['flashes']) . "\n" + . $this->renderData('$_GET', $this->data['GET']) . "\n" + . $this->renderData('$_POST', $this->data['POST']) . "\n" + . $this->renderData('$_COOKIE', $this->data['COOKIE']) . "\n" + . $this->renderData('$_FILES', $this->data['FILES']) . "\n" + . $this->renderData('$_SESSION', $this->data['SESSION']) . "\n" + . $this->renderData('$_SERVER', $this->data['SERVER']) . "\n" + . $this->renderData('Request Headers', $this->data['requestHeaders']) . "\n" + . $this->renderData('Response Headers', $this->data['responseHeaders']); } public function save() { + if (function_exists('apache_request_headers')) { + $requestHeaders = apache_request_headers(); + } elseif (function_exists('http_get_request_headers')) { + $requestHeaders = http_get_request_headers(); + } else { + $requestHeaders = array(); + } + $responseHeaders = array(); + foreach (headers_list() as $header) { + if (($pos = strpos($header, ':')) !== false) { + $name = substr($header, 0, $pos); + $value = trim(substr($header, $pos + 1)); + if (isset($responseHeaders[$name])) { + if (!is_array($responseHeaders[$name])) { + $responseHeaders[$name] = array($responseHeaders[$name], $value); + } else { + $responseHeaders[$name][] = $value; + } + } else { + $responseHeaders[$name] = $value; + } + } else { + $responseHeaders[] = $header; + } + } + if (Yii::$app->requestedAction) { + if (Yii::$app->requestedAction instanceof InlineAction) { + $action = get_class(Yii::$app->requestedAction->controller) . '::' . Yii::$app->requestedAction->actionMethod . '()'; + } else { + $action = get_class(Yii::$app->requestedAction) . '::run()'; + } + } else { + $action = null; + } + /** @var \yii\web\Session $session */ + $session = Yii::$app->getComponent('session', false); return array( 'memory' => memory_get_peak_usage(), 'time' => microtime(true) - YII_BEGIN_TIME, - 'SERVER' => $_SERVER, - 'GET' => $_GET, - 'POST' => $_POST, - 'COOKIE' => $_COOKIE, + 'flashes' => $session ? $session->getAllFlashes() : array(), + 'requestHeaders' => $requestHeaders, + 'responseHeaders' => $responseHeaders, + 'route' => Yii::$app->requestedAction->getUniqueId(), + 'action' => $action, + 'actionParams' => Yii::$app->requestedParams, + 'SERVER' => empty($_SERVER) ? array() : $_SERVER, + 'GET' => empty($_GET) ? array() : $_GET, + 'POST' => empty($_POST) ? array() : $_POST, + 'COOKIE' => empty($_COOKIE) ? array() : $_COOKIE, 'FILES' => empty($_FILES) ? array() : $_FILES, 'SESSION' => empty($_SESSION) ? array() : $_SESSION, ); } - protected function renderTable($values) + protected function renderData($caption, $values) { + if (empty($values)) { + return "

$caption

\n

Empty.

"; + } $rows = array(); foreach ($values as $name => $value) { $rows[] = '' . Html::encode($name) . '
' . Html::encode(var_export($value, true)) . '
'; } - if (!empty($rows)) { - $rows = implode("\n", $rows); - return <<$caption @@ -77,8 +134,5 @@ $rows
NameValue
EOD; - } else { - return 'Empty.'; - } } } diff --git a/framework/yii/debug/views/default/index.php b/framework/yii/debug/views/default/index.php index 79caf02..ead7fb3 100644 --- a/framework/yii/debug/views/default/index.php +++ b/framework/yii/debug/views/default/index.php @@ -4,16 +4,23 @@ use yii\helpers\Html; /** * @var \yii\base\View $this + * @var array $meta * @var string $tag + * @var array $manifest * @var \yii\debug\Panel[] $panels * @var \yii\debug\Panel $activePanel */ + +$this->registerAssetBundle('yii/bootstrap/dropdown'); +$this->title = 'Yii Debugger'; ?>
@@ -21,18 +28,39 @@ use yii\helpers\Html;
-
+
+
+ + +
+ Debugging: + + + + at + by +
getDetail(); ?>
diff --git a/framework/yii/debug/views/default/toolbar.php b/framework/yii/debug/views/default/toolbar.php index 10f66a5..05b03f6 100644 --- a/framework/yii/debug/views/default/toolbar.php +++ b/framework/yii/debug/views/default/toolbar.php @@ -12,17 +12,42 @@ use yii\helpers\Html; left: 0; right: 0; bottom: 0; - background-color: #eee; - border-top: 1px solid #ccc; margin: 0; - padding: 5px 10px; + padding: 0; z-index: 1000000; font: 11px Verdana, Arial, sans-serif; text-align: left; + height: 38px; + border-top: 1px solid #ccc; + background: rgb(237,237,237); + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); + background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); } + .yii-debug-toolbar-block { float: left; - margin: 0 10px; + margin: 0; + border-right: 1px solid #e4e4e4; + padding: 4px 8px; + line-height: 32px; +} + +.yii-debug-toolbar-block a { + text-decoration: none; + color: black !important; +} + +.yii-debug-toolbar-block span { +} + +.yii-debug-toolbar-block img { + vertical-align: middle; } @@ -30,7 +55,4 @@ use yii\helpers\Html; getSummary(); ?> -
- $tag)); ?> -
diff --git a/framework/yii/debug/views/layouts/main.php b/framework/yii/debug/views/layouts/main.php index 11eeb2d..5c8a735 100644 --- a/framework/yii/debug/views/layouts/main.php +++ b/framework/yii/debug/views/layouts/main.php @@ -5,7 +5,7 @@ */ use yii\helpers\Html; -Yii::$app->getView()->registerAssetBundle('yii/bootstrap/responsive'); +Yii::$app->getView()->registerAssetBundle('yii/debug'); ?> diff --git a/framework/yii/helpers/base/Html.php b/framework/yii/helpers/base/Html.php index f5a4076..ad83eed 100644 --- a/framework/yii/helpers/base/Html.php +++ b/framework/yii/helpers/base/Html.php @@ -855,7 +855,7 @@ class Html * The signature of this callback must be: * * ~~~ - * function ($index, $item) + * function ($item, $index) * ~~~ * * where $index is the array key corresponding to `$item` in `$items`. The callback should return @@ -876,7 +876,7 @@ class Html $results = array(); foreach ($items as $index => $item) { if ($formatter !== null) { - $results[] = call_user_func($formatter, $index, $item); + $results[] = call_user_func($formatter, $item, $index); } else { $results[] = static::tag('li', $encode ? static::encode($item) : $item, $itemOptions); } @@ -897,7 +897,7 @@ class Html * The signature of this callback must be: * * ~~~ - * function ($index, $item) + * function ($item, $index) * ~~~ * * where $index is the array key corresponding to `$item` in `$items`. The callback should return diff --git a/framework/yii/log/Logger.php b/framework/yii/log/Logger.php index 6a36a5c..d1d2c2c 100644 --- a/framework/yii/log/Logger.php +++ b/framework/yii/log/Logger.php @@ -161,7 +161,7 @@ class Logger extends Component public function log($message, $level, $category = 'application') { $time = microtime(true); - if (YII_DEBUG && YII_TRACE_LEVEL > 0) { + if (YII_DEBUG && YII_TRACE_LEVEL > 0 && !($level & self::LEVEL_PROFILE)) { $traces = debug_backtrace(); $count = 0; foreach ($traces as $trace) { diff --git a/framework/yii/log/Target.php b/framework/yii/log/Target.php index 21e2779..48c340f 100644 --- a/framework/yii/log/Target.php +++ b/framework/yii/log/Target.php @@ -90,7 +90,7 @@ abstract class Target extends Component */ public function collect($messages, $final) { - $this->messages = array_merge($this->messages, $this->filterMessages($messages)); + $this->messages = array_merge($this->messages, $this->filterMessages($messages, $this->getLevels(), $this->categories, $this->except)); $count = count($this->messages); if ($count > 0 && ($final || $this->exportInterval > 0 && $count >= $this->exportInterval)) { if (($context = $this->getContextMessage()) !== '') { @@ -178,22 +178,22 @@ abstract class Target extends Component /** * Filters the given messages according to their categories and levels. * @param array $messages messages to be filtered + * @param integer $levels the message levels to filter by. This is a bitmap of + * level values. Value 0 means allowing all levels. + * @param array $categories the message categories to filter by. If empty, it means all categories are allowed. + * @param array $except the message categories to exclude. If empty, it means all categories are allowed. * @return array the filtered messages. - * @see filterByCategory - * @see filterByLevel */ - protected function filterMessages($messages) + public static function filterMessages($messages, $levels = 0, $categories = array(), $except = array()) { - $levels = $this->getLevels(); - foreach ($messages as $i => $message) { if ($levels && !($levels & $message[1])) { unset($messages[$i]); continue; } - $matched = empty($this->categories); - foreach ($this->categories as $category) { + $matched = empty($categories); + foreach ($categories as $category) { if ($message[2] === $category || substr($category, -1) === '*' && strpos($message[2], rtrim($category, '*')) === 0) { $matched = true; break; @@ -201,7 +201,7 @@ abstract class Target extends Component } if ($matched) { - foreach ($this->except as $category) { + foreach ($except as $category) { $prefix = rtrim($category, '*'); if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) { $matched = false; diff --git a/framework/yii/web/Application.php b/framework/yii/web/Application.php index 242a0db..8753ebe 100644 --- a/framework/yii/web/Application.php +++ b/framework/yii/web/Application.php @@ -65,6 +65,8 @@ class Application extends \yii\base\Application $params = array_splice($this->catchAll, 1); } try { + Yii::trace("Route requested: '$route'", __METHOD__); + $this->requestedRoute = $route; $result = $this->runAction($route, $params); if ($result instanceof Response) { return $result; diff --git a/framework/yii/web/CaptchaAction.php b/framework/yii/web/CaptchaAction.php index b149ffd..687ac49 100644 --- a/framework/yii/web/CaptchaAction.php +++ b/framework/yii/web/CaptchaAction.php @@ -177,7 +177,7 @@ class CaptchaAction extends Action $session->open(); $name = $this->getSessionKey() . 'count'; $session[$name] = $session[$name] + 1; - if ($session[$name] > $this->testLimit && $this->testLimit > 0) { + if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) { $this->getVerifyCode(true); } return $valid; diff --git a/framework/yii/web/UrlManager.php b/framework/yii/web/UrlManager.php index 9a616c5..e3ac986 100644 --- a/framework/yii/web/UrlManager.php +++ b/framework/yii/web/UrlManager.php @@ -171,6 +171,7 @@ class UrlManager extends Component /** @var $rule UrlRule */ foreach ($this->rules as $rule) { if (($result = $rule->parseRequest($this, $request)) !== false) { + Yii::info("Request parsed with URL rule: {$rule->name}", __METHOD__); return $result; } } @@ -194,12 +195,14 @@ class UrlManager extends Component } } + Yii::info('No matching URL rules. Using default URL parsing logic.', __METHOD__); return array($pathInfo, array()); } else { $route = $request->get($this->routeVar); if (is_array($route)) { $route = ''; } + Yii::info('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__); return array((string)$route, array()); } } diff --git a/tests/unit/framework/helpers/HtmlTest.php b/tests/unit/framework/helpers/HtmlTest.php index aef2855..61331e0 100644 --- a/tests/unit/framework/helpers/HtmlTest.php +++ b/tests/unit/framework/helpers/HtmlTest.php @@ -388,7 +388,7 @@ EOD; EOD; $this->assertEqualsWithoutLE($expected, Html::ul($data, array( 'class' => 'test', - 'item' => function($index, $item) { + 'item' => function($item, $index) { return "
  • $item
  • "; } ))); @@ -418,7 +418,7 @@ EOD; EOD; $this->assertEqualsWithoutLE($expected, Html::ol($data, array( 'class' => 'test', - 'item' => function($index, $item) { + 'item' => function($item, $index) { return "
  • $item
  • "; } ))); diff --git a/tests/unit/framework/web/UrlManagerTest.php b/tests/unit/framework/web/UrlManagerTest.php index 7da8f34..54e88ab 100644 --- a/tests/unit/framework/web/UrlManagerTest.php +++ b/tests/unit/framework/web/UrlManagerTest.php @@ -7,6 +7,12 @@ use yiiunit\TestCase; class UrlManagerTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testCreateUrl() { // default setting with '/' as base url