/** * Sets a timer point before rendering a file. * * @param string $viewFile The view being rendered */ public function beforeRenderFile($viewFile) { if ($this->_renderComplete) { return; } DebugTimer::start('render_' . basename($viewFile), __d('debug_kit', 'Rendering %s', Debugger::trimPath($viewFile))); }
/** * Overload _render to capture filenames and time actual rendering of each view file * * @param string $___viewFn Filename of the view * @param array $___dataForView Data to include in rendered view * @return string Rendered output * @access protected */ function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) { if (!isset($___dataForView['disableTimer'])) { DebugKitDebugger::startTimer('render_' . basename($___viewFn), sprintf(__d('debug_kit', 'Rendering %s', true), Debugger::trimPath($___viewFn))); } $out = parent::_render($___viewFn, $___dataForView, $loadHelpers, $cached); if (!isset($___dataForView['disableTimer'])) { DebugKitDebugger::stopTimer('render_' . basename($___viewFn)); } return $out; }
public function testGetCallbacks() { $listeners = array(array('callable' => array('SomeClass', 'someStaticMethod')), array('callable' => array($this, 'someInstanceMethod')), array('callable' => function () { return 'Some Closure'; })); $line = __LINE__; $path = Debugger::trimPath(__FILE__); $expected = array('SomeClass::someStaticMethod', 'CrudPanelTest::someInstanceMethod', $path . ':' . ($line - 5)); $return = $this->callProtectedMethod('_getCallbacks', array($listeners), $this->Panel); $this->assertSame($expected, $return); }
/** * Overload _render to capture filenames and time actual rendering of each view file * * @param string $___viewFn Filename of the view * @param array $___dataForView Data to include in rendered view * @return string Rendered output */ protected function _render($___viewFn, $___dataForView = array()) { if (!isset($___dataForView['disableTimer'])) { DebugTimer::start('render_' . basename($___viewFn), __d('debug_kit', 'Rendering %s', Debugger::trimPath($___viewFn))); } $out = parent::_render($___viewFn, $___dataForView); if (!isset($___dataForView['disableTimer'])) { DebugTimer::stop('render_' . basename($___viewFn)); } return $out; }
/** * Overload _render to capture filenames and time actual rendering of each view file * * @param string $___viewFn Filename of the view * @param array $___dataForView Data to include in rendered view * @return string Rendered output * @access protected */ function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) { if (isset($this->_oldExtension) && strstr($___viewFn, '.debug_view')) { $___viewFn = substr($___viewFn, 0, -10) . $this->_oldExtension; } if (!isset($___dataForView['disableTimer'])) { DebugKitDebugger::startTimer('render_' . basename($___viewFn), sprintf(__('Rendering %s', true), Debugger::trimPath($___viewFn))); } $out = parent::_render($___viewFn, $___dataForView, $loadHelpers, $cached); if (!isset($___dataForView['disableTimer'])) { DebugKitDebugger::stopTimer('render_' . basename($___viewFn)); } return $out; }
/** * Read a config file and return its contents. * * Keys with `.` will be treated as values in plugins. Instead of reading from * the initialized path, plugin keys will be located using App::pluginPath(). * * * @param string $key The identifier to read from. If the key has a . it will be treated * as a plugin prefix. path extension is not needed by default, but possible to specify * your own extension, e.g. Configure::load('Hoge.yaml', new YamlReader); * @return array Parsed configuration values. * @throws ConfigureException when files doesn't exist or when files contain '..' as this could lead to abusive reads. */ public function read($key) { App::uses('Spyc', 'vendors'); if (!class_exists('Spyc')) { App::uses('Spyc', 'YamlReader.vendors'); } $filePath = $this->_getFilePath($key); if (!file_exists($filePath)) { $filePath .= ".{$this->ext}"; if (!file_exists($filePath)) { throw new ConfigureException(__('Could not load configuration file: ') . Debugger::trimPath($filePath)); } } $config = Spyc::YAMLLoad($filePath); if ($this->baseKey) { $config = array($key => $config); } return $config; }
/** * override core one with the following enhancements/fixes: * - 404s log to a different domain * - IP, Referer and Browser-Infos are added for better error debugging/tracing * 2011-12-21 ms */ public static function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } $errorConfig = Configure::read('Error'); list($error, $log) = self::mapErrorCode($code); $debug = Configure::read('debug'); if ($debug) { $data = array('level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line, 'context' => $context, 'start' => 2, 'path' => Debugger::trimPath($file)); return Debugger::getInstance()->outputError($data); } else { $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; if (!empty($errorConfig['trace'])) { $trace = Debugger::trace(array('start' => 1, 'format' => 'log')); $message .= "\nTrace:\n" . $trace . "\n"; $message .= self::traceDetails(); } return CakeLog::write($log, $message); } }
/** * testTrimPath method * * @return void */ public function testTrimPath() { $this->assertEquals('APP' . DS, Debugger::trimPath(APP)); $this->assertEquals('CORE', Debugger::trimPath(CAKE_CORE_INCLUDE_PATH)); $this->assertEquals('ROOT', Debugger::trimPath(ROOT)); $this->assertEquals('CORE' . DS . 'Cake' . DS, Debugger::trimPath(CAKE)); $this->assertEquals('Some/Other/Path', Debugger::trimPath('Some/Other/Path')); }
/** * own shutdown function - also logs fatal errors (necessary until cake2.2) * 2010-10-17 ms */ function shutDownFunction() { $error = error_get_last(); if (empty($error)) { return; } $matching = array(E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_', E_NOTICE => 'E_', E_CORE_ERROR => 'E_', E_COMPILE_ERROR => 'E_', E_COMPILE_WARNING => 'E_', E_STRICT => 'E_STRICT', E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', E_DEPRECATED => 'E_DEPRECATED'); App::uses('CakeLog', 'Log'); if (in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR))) { $error['type_name'] = 'Fatal Error'; $type = 'error'; } elseif (Configure::read('Debug.log') && isset($matching[$error['type']])) { $error['type_name'] = 'Error'; $type = 'notice'; } if (!isset($type)) { return; } App::uses('Debugger', 'Utility'); $trace = Debugger::trace(array('start' => 1, 'format' => 'log', 'args' => true)); $path = Debugger::trimPath($error['file']); $message = $error['type_name'] . ' ' . $matching[$error['type']] . ' in ' . $path . ' (line ' . $error['line'] . '): ' . $error['message']; $message .= PHP_EOL . $trace; App::uses('MyErrorHandler', 'Tools.Error'); $message .= MyErrorHandler::traceDetails(); CakeLog::write($type, $message); }
/** * testTrimPath method * * @return void */ public function testTrimPath() { $this->assertEquals(Debugger::trimPath(APP), 'APP' . DS); $this->assertEquals(Debugger::trimPath(CAKE_CORE_INCLUDE_PATH), 'CORE'); }
/** * Fix a trace for use in output * * @param mixed $trace Trace to fix * @return string */ protected static function _escapeTrace($trace) { for ($i = 0, $len = count($trace); $i < $len; $i++) { if (isset($trace[$i]['file'])) { $trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']); } if (isset($trace[$i]['args'])) { $trace[$i]['args'] = FireCake::stringEncode($trace[$i]['args']); } } return $trace; }
/** * Set as the default error handler by CakePHP. Use Configure::write('Error.handler', $callback), to use your own * error handling methods. This function will use Debugger to display errors when debug > 0. And * will log errors to CakeLog, when debug == 0. * * You can use Configure::write('Error.level', $value); to set what type of errors will be handled here. * Stack traces for errors can be enabled with Configure::write('Error.trace', true); * * @param int $code Code of error * @param string $description Error description * @param string $file File on which error occurred * @param int $line Line that triggered the error * @param array $context Context * @return bool true if error was handled */ public static function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } $errorConfig = Configure::read('Error'); list($error, $log) = self::mapErrorCode($code); if ($log === LOG_ERR) { return self::handleFatalError($code, $description, $file, $line); } $debug = Configure::read('debug'); if ($debug) { $data = array('level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line, 'context' => $context, 'start' => 2, 'path' => Debugger::trimPath($file)); return Debugger::getInstance()->outputError($data); } $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; #mod blamoo@live.com $message .= "\nForwarded-For: " . (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : '(None)'); #MOD $message .= "\nReferer: " . (isset($_SERVER['HTTP_REFERER']) ? "<a href=\"{$_SERVER['HTTP_REFERER']}\">{$_SERVER['HTTP_REFERER']}</a>" : '(None)'); #MOD $message .= "\nUA: " . (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '(None)'); #MOD $message .= "\nMethod: " . (isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '(None)'); #MOD if (count($_POST) !== 0) { $message .= "\nPost: <pre>" . var_export($_POST, true) . '</pre>'; #MOD } #endmod if (!empty($errorConfig['trace'])) { $trace = Debugger::trace(array('start' => 1, 'format' => 'log')); $message .= "\nTrace:\n" . $trace . "\n"; } return CakeLog::write($log, $message); }
/** * Return where a closure has been defined * * If for some reason this doesn't work - it'll return the closure instance in the full knowledge * that it'll probably get dumped as the string "function" * * @param Closure $closure * @return mixed string or Closure */ protected function _getClosureDefinition(Closure $closure) { $exported = ReflectionFunction::export($closure, true); preg_match('#@@ (.*) (\\d+) - (\\d+)#', $exported, $match); if (!$match) { return $closure; } list($m, $path, $start) = $match; $path = Debugger::trimPath($path); return "{$path}:{$start}"; }
/** * update method * * @return void * @access public */ public function update() { if (!file_exists(CAKE . 'config' . DS . 'sources.txt')) { $File = new File(CAKE . 'config' . DS . 'sources.txt', true); $File->write('file://' . dirname(__FILE__) . DS . 'packages.txt'); } $sources = file(CAKE . 'config' . DS . 'sources.txt'); $packages = array(); App::import('Core', 'HttpSocket'); $Socket = new HttpSocket(); foreach ($sources as &$source) { $source = trim($source); if (!$source || $source[0] === '#') { $source = false; continue; } if (strpos($source, 'file://') !== false) { $data = file($source); } else { $data = $Socket->get($source); if (!$data) { $source .= ' (no response)'; continue; } $data = explode("\n", $data); } $packages = array_merge($packages, MiInstall::_parsePackages($data)); } $File = new File(CAKE . 'config' . DS . 'packages.php', true); $File->write("<?php\n\$config = " . var_export($packages, true) . ';'); $return[] = Debugger::trimPath($File->pwd()) . ' updated'; $return['sources checked:'] = array_filter($sources); return $return; }
/** * Set as the default error handler by CakePHP. Use Configure::write('Error.handler', $callback), to use your own * error handling methods. This function will use Debugger to display errors when debug > 0. And * will log errors to CakeLog, when debug == 0. * * You can use Configure::write('Error.level', $value); to set what type of errors will be handled here. * Stack traces for errors can be enabled with Configure::write('Error.trace', true); * * @param int $code Code of error * @param string $description Error description * @param string $file File on which error occurred * @param int $line Line that triggered the error * @param array $context Context * @return bool true if error was handled */ public static function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } list($error, $log) = static::mapErrorCode($code); if ($log === LOG_ERR) { return static::handleFatalError($code, $description, $file, $line); } $debug = Configure::read('debug'); if ($debug) { $data = array('level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line, 'context' => $context, 'start' => 2, 'path' => Debugger::trimPath($file)); return Debugger::getInstance()->outputError($data); } $message = static::_getErrorMessage($error, $code, $description, $file, $line); return CakeLog::write($log, $message); }
/** * Outputs a stack trace based on the supplied options. * * ### Options * * - `depth` - The number of stack frames to return. Defaults to 999 * - `format` - The format you want the return. Defaults to the currently selected format. If * format is 'array' or 'points' the return will be an array. * - `args` - Should arguments for functions be shown? If true, the arguments for each method call * will be displayed. * - `start` - The stack frame to start generating a trace from. Defaults to 0 * * @param array $options Format for outputting stack trace * @return mixed Formatted stack trace * @access public * @static * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class */ function trace($options = array()) { $_this =& Debugger::getInstance(); $defaults = array('depth' => 999, 'format' => $_this->_outputFormat, 'args' => false, 'start' => 0, 'scope' => null, 'exclude' => null); $options += $defaults; $backtrace = debug_backtrace(); $count = count($backtrace); $back = array(); $_trace = array('line' => '??', 'file' => '[internal]', 'class' => null, 'function' => '[main]'); for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) { $trace = array_merge(array('file' => '[internal]', 'line' => '??'), $backtrace[$i]); if (isset($backtrace[$i + 1])) { $next = array_merge($_trace, $backtrace[$i + 1]); $reference = $next['function']; if (!empty($next['class'])) { $reference = $next['class'] . '::' . $reference . '('; if ($options['args'] && isset($next['args'])) { $args = array(); foreach ($next['args'] as $arg) { $args[] = Debugger::exportVar($arg); } $reference .= join(', ', $args); } $reference .= ')'; } } else { $reference = '[main]'; } if (in_array($reference, array('call_user_func_array', 'trigger_error'))) { continue; } if ($options['format'] == 'points' && $trace['file'] != '[internal]') { $back[] = array('file' => $trace['file'], 'line' => $trace['line']); } elseif ($options['format'] == 'array') { $back[] = $trace; } else { if (isset($_this->_templates[$options['format']]['traceLine'])) { $tpl = $_this->_templates[$options['format']]['traceLine']; } else { $tpl = $_this->_templates['base']['traceLine']; } $trace['path'] = Debugger::trimPath($trace['file']); $trace['reference'] = $reference; unset($trace['object'], $trace['args']); $back[] = String::insert($tpl, $trace, array('before' => '{:', 'after' => '}')); } } if ($options['format'] == 'array' || $options['format'] == 'points') { return $back; } return implode("\n", $back); }
/** * Assert that nested anonymous timers don't get mixed up. * * @return void **/ function testNestedAnonymousTimers() { $this->assertTrue(DebugKitDebugger::startTimer()); usleep(100); $this->assertTrue(DebugKitDebugger::startTimer()); usleep(100); $this->assertTrue(DebugKitDebugger::stopTimer()); $this->assertTrue(DebugKitDebugger::stopTimer()); $timers = DebugKitDebugger::getTimers(); $this->assertEqual(count($timers), 3, 'incorrect number of timers %s'); $firstTimerLine = __LINE__ - 9; $secondTimerLine = __LINE__ - 8; $file = Debugger::trimPath(__FILE__); $this->assertTrue(isset($timers[$file . ' line ' . $firstTimerLine]), 'first timer is not set %s'); $this->assertTrue(isset($timers[$file . ' line ' . $secondTimerLine]), 'second timer is not set %s'); $firstTimer = $timers[$file . ' line ' . $firstTimerLine]; $secondTimer = $timers[$file . ' line ' . $secondTimerLine]; $this->assertTrue($firstTimer['time'] > $secondTimer['time']); }
/** * Fix a trace for use in output * * @param mixed $trace Trace to fix * @access protected * @static * @return string **/ function _escapeTrace($trace) { for ($i = 0, $len = count($trace); $i < $len; $i++) { if (isset($trace[$i]['file'])) { $trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']); } if (isset($trace[$i]['args'])) { $trace[$i]['args'] = $this->stringEncode($trace[$i]['args']); } } return $trace; }
/** * Outputs a stack trace based on the supplied options. * * @param array $options Format for outputting stack trace * @return string Formatted stack trace * @access public * @static * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class */ function trace($options = array()) { $options = array_merge(array('depth' => 999, 'format' => '', 'args' => false, 'start' => 0, 'scope' => null, 'exclude' => null), $options); $backtrace = debug_backtrace(); $back = array(); $count = count($backtrace); for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) { $trace = array_merge(array('file' => '[internal]', 'line' => '??'), $backtrace[$i]); if (isset($backtrace[$i + 1])) { $next = array_merge(array('line' => '??', 'file' => '[internal]', 'class' => null, 'function' => '[main]'), $backtrace[$i + 1]); $function = $next['function']; if (!empty($next['class'])) { $function = $next['class'] . '::' . $function . '('; if ($options['args'] && isset($next['args'])) { $args = array(); foreach ($next['args'] as $arg) { $args[] = Debugger::exportVar($arg); } $function .= join(', ', $args); } $function .= ')'; } } else { $function = '[main]'; } if (in_array($function, array('call_user_func_array', 'trigger_error'))) { continue; } if ($options['format'] == 'points' && $trace['file'] != '[internal]') { $back[] = array('file' => $trace['file'], 'line' => $trace['line']); } elseif (empty($options['format'])) { $back[] = $function . ' - ' . Debugger::trimPath($trace['file']) . ', line ' . $trace['line']; } else { $back[] = $trace; } } if ($options['format'] == 'array' || $options['format'] == 'points') { return $back; } return join("\n", $back); }
/** * log method * * If the message level is greater than the set logLevel - ignore it * If it's an error - don't echo it inline to prevent duplicate messages (once when found, and * once in the summary when all files are processed) * * @param string $string '' * @param mixed $ruleKey null * @param mixed $level 'info' * @param bool $isError false * @return void * @access protected */ function _log($string = '', $ruleKey = null, $level = 'info', $isError = false) { if ($isError) { $this->returnValue = 1; } if ($this->_logLevel[$level] > $this->_logLevel[$this->settings['logLevel']]) { return; } if ($isError) { $this->returnValue = 1; $file = Debugger::trimPath($this->current['file']); if (!strpos($string, $file)) { $string .= ' in ' . $file; if ($this->current['lineNo'] !== '*') { $string .= ' on line ' . $this->current['lineNo']; } } $this->errors[$this->current['file']][$this->current['rule']][$this->current['lineNo']] = $string; return; } if ($this->_logLevel[$level] === $this->_logLevel['err']) { $string = 'Error: ' . $string; } elseif ($this->_logLevel[$level] === $this->_logLevel['warning']) { $string = 'Warning: ' . $string; } if (!empty($this->settings['_supressMessages'])) { $this->messages[] = $string; return; } $this->out($string); }
/** * Set as the default error handler by CakePHP. Use Configure::write('Error.handler', $callback), to use your own * error handling methods. This function will use Debugger to display errors when debug > 0. And * will log errors to CakeLog, when debug == 0. * * You can use Configure::write('Error.level', $value); to set what type of errors will be handled here. * Stack traces for errors can be enabled with Configure::write('Error.trace', true); * * @param int $code Code of error * @param string $description Error description * @param string $file File on which error occurred * @param int $line Line that triggered the error * @param array $context Context * @return bool true if error was handled */ public static function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } $errorConfig = Configure::read('Error'); list($error, $log) = static::mapErrorCode($code); if ($log === LOG_ERR) { return static::handleFatalError($code, $description, $file, $line); } $debug = Configure::read('debug'); if ($debug) { $data = array('level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line, 'context' => $context, 'start' => 2, 'path' => Debugger::trimPath($file)); return Debugger::getInstance()->outputError($data); } $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; if (!empty($errorConfig['trace'])) { // https://bugs.php.net/bug.php?id=65322 if (version_compare(PHP_VERSION, '5.4.21', '<')) { if (!class_exists('Debugger')) { App::load('Debugger'); } if (!class_exists('CakeText')) { App::uses('CakeText', 'Utility'); App::load('CakeText'); } } $trace = Debugger::trace(array('start' => 1, 'format' => 'log')); $message .= "\nTrace:\n" . $trace . "\n"; } return CakeLog::write($log, $message); }
/** * jsPo method * * Parse js files for use of the (javascript) function __d('mi', ) and generate a javascript 'po' file. * will create app/vendors/i18n.<locale>.js files for each locale that exists in the app/locale dir * * @return void * @access protected */ function _jsPo() { $Folder = new Folder(APP . 'locale'); list($locales, $potFiles) = $Folder->read(); if (!in_array('javascript.pot', $potFiles)) { $this->out(__d('mi', 'The javascript.pot file wasn\'t found - run cake mi_i18n to generate it', true)); return; } if (defined('DEFAULT_LANGUAGE')) { $locales = array_unique(am(array(DEFAULT_LANGUAGE), $locales)); } if (!class_exists('I18n')) { App::import('Core', 'i18n'); } $messages = array(); foreach ($locales as $locale) { if ($locale[0] === '.') { continue; } $data = Cache::read('javascript_' . $locale, '_cake_core_'); if (!$data) { Configure::write('Config.language', $locale); __d('javascript', 'foo', true); $inst =& I18n::getInstance(); Cache::write('javascript_' . $locale, array_filter($inst->__domains), '_cake_core_'); $data = Cache::read('javascript_' . $locale, '_cake_core_'); if (!$data) { continue; } } foreach ($data as $type => $i) { foreach ($i[$locale]['javascript'] as $lookup => $string) { if (!is_string($string)) { continue; } if (!$string) { $string = $lookup; } $messages[$lookup] = $string; } } ob_start(); include dirname(__FILE__) . DS . 'templates' . DS . 'js' . DS . 'po.js'; $contents = ob_get_clean(); $targetFile = APP . 'vendors' . DS . 'js' . DS . 'i18n.' . $locale . '.js'; $File = new File($targetFile); $File->write($contents); $this->out(Debugger::trimPath($targetFile) . ' written'); } }