/analysis/src/lib/php/ChromePhp.php
PHP | 437 lines | 184 code | 63 blank | 190 comment | 25 complexity | 6cfd158a43f93c23d622ff101d85d84f MD5 | raw file
- <?php
- /**
- * Copyright 2012 Craig Campbell
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * Server Side Chrome PHP debugger class
- *
- * @package ChromePhp
- * @author Craig Campbell <iamcraigcampbell@gmail.com>
- */
- class ChromePhp
- {
- /**
- * @var string
- */
- const VERSION = '3.0';
- /**
- * @var string
- */
- const HEADER_NAME = 'X-ChromePhp-Data';
- /**
- * @var string
- */
- const BACKTRACE_LEVEL = 'backtrace_level';
- /**
- * @var string
- */
- const LOG = 'log';
- /**
- * @var string
- */
- const WARN = 'warn';
- /**
- * @var string
- */
- const ERROR = 'error';
- /**
- * @var string
- */
- const GROUP = 'group';
- /**
- * @var string
- */
- const INFO = 'info';
- /**
- * @var string
- */
- const GROUP_END = 'groupEnd';
- /**
- * @var string
- */
- const GROUP_COLLAPSED = 'groupCollapsed';
- /**
- * @var string
- */
- protected $_php_version;
- /**
- * @var int
- */
- protected $_timestamp;
- /**
- * @var array
- */
- protected $_json = array(
- 'version' => self::VERSION,
- 'columns' => array('label', 'log', 'backtrace', 'type'),
- 'rows' => array()
- );
- /**
- * @var array
- */
- protected $_backtraces = array();
- /**
- * @var bool
- */
- protected $_error_triggered = false;
- /**
- * @var array
- */
- protected $_settings = array(
- self::BACKTRACE_LEVEL => 1
- );
- /**
- * @var ChromePhp
- */
- protected static $_instance;
- /**
- * Prevent recursion when working with objects referring to each other
- *
- * @var array
- */
- protected $_processed = array();
- /**
- * constructor
- */
- private function __construct()
- {
- $this->_php_version = phpversion();
- $this->_timestamp = $this->_php_version >= 5.1 ? $_SERVER['REQUEST_TIME'] : time();
- $this->_json['request_uri'] = $_SERVER['REQUEST_URI'];
- }
- /**
- * gets instance of this class
- *
- * @return ChromePhp
- */
- public static function getInstance()
- {
- if (self::$_instance === null) {
- self::$_instance = new ChromePhp();
- }
- return self::$_instance;
- }
- /**
- * logs a variable to the console
- *
- * @param string label
- * @param mixed value
- * @param string severity ChromePhp::LOG || ChromePhp::WARN || ChromePhp::ERROR
- * @return void
- */
- public static function log()
- {
- $args = func_get_args();
- $severity = count($args) == 3 ? array_pop($args) : '';
- // save precious bytes
- if ($severity == self::LOG) {
- $severity = '';
- }
- return self::_log($args + array('type' => $severity));
- }
- /**
- * logs a warning to the console
- *
- * @param string label
- * @param mixed value
- * @return void
- */
- public static function warn()
- {
- return self::_log(func_get_args() + array('type' => self::WARN));
- }
- /**
- * logs an error to the console
- *
- * @param string label
- * @param mixed value
- * @return void
- */
- public static function error()
- {
- return self::_log(func_get_args() + array('type' => self::ERROR));
- }
- /**
- * sends a group log
- *
- * @param string value
- */
- public static function group()
- {
- return self::_log(func_get_args() + array('type' => self::GROUP));
- }
- /**
- * sends an info log
- *
- * @param string value
- */
- public static function info()
- {
- return self::_log(func_get_args() + array('type' => self::INFO));
- }
- /**
- * sends a collapsed group log
- *
- * @param string value
- */
- public static function groupCollapsed()
- {
- return self::_log(func_get_args() + array('type' => self::GROUP_COLLAPSED));
- }
- /**
- * ends a group log
- *
- * @param string value
- */
- public static function groupEnd()
- {
- return self::_log(func_get_args() + array('type' => self::GROUP_END));
- }
- /**
- * internal logging call
- *
- * @param string $type
- * @return void
- */
- protected static function _log(array $args)
- {
- $type = $args['type'];
- unset($args['type']);
- // nothing passed in, don't do anything
- if (count($args) == 0 && $type != self::GROUP_END) {
- return;
- }
- // default to single
- $label = null;
- $value = isset($args[0]) ? $args[0] : '';
- $logger = self::getInstance();
- // if there are two values passed in then the first one is the label
- if (count($args) == 2) {
- $label = $args[0];
- $value = $args[1];
- }
- $logger->_processed = array();
- $value = $logger->_convert($value);
- $backtrace = debug_backtrace(false);
- $level = $logger->getSetting(self::BACKTRACE_LEVEL);
- $backtrace_message = 'unknown';
- if (isset($backtrace[$level]['file']) && isset($backtrace[$level]['line'])) {
- $backtrace_message = $backtrace[$level]['file'] . ' : ' . $backtrace[$level]['line'];
- }
- $logger->_addRow($label, $value, $backtrace_message, $type);
- }
- /**
- * converts an object to a better format for logging
- *
- * @param Object
- * @return array
- */
- protected function _convert($object)
- {
- // if this isn't an object then just return it
- if (!is_object($object)) {
- return $object;
- }
- //Mark this object as processed so we don't convert it twice and it
- //Also avoid recursion when objects refer to each other
- $this->_processed[] = $object;
- $object_as_array = array();
- // first add the class name
- $object_as_array['___class_name'] = get_class($object);
- // loop through object vars
- $object_vars = get_object_vars($object);
- foreach ($object_vars as $key => $value) {
- // same instance as parent object
- if ($value === $object || in_array($value, $this->_processed, true)) {
- $value = 'recursion - parent object [' . get_class($value) . ']';
- }
- $object_as_array[$key] = $this->_convert($value);
- }
- $reflection = new ReflectionClass($object);
- // loop through the properties and add those
- foreach ($reflection->getProperties() as $property) {
- // if one of these properties was already added above then ignore it
- if (array_key_exists($property->getName(), $object_vars)) {
- continue;
- }
- $type = $this->_getPropertyKey($property);
- if ($this->_php_version >= 5.3) {
- $property->setAccessible(true);
- }
- try {
- $value = $property->getValue($object);
- } catch (ReflectionException $e) {
- $value = 'only PHP 5.3 can access private/protected properties';
- }
- // same instance as parent object
- if ($value === $object || in_array($value, $this->_processed, true)) {
- $value = 'recursion - parent object [' . get_class($value) . ']';
- }
- $object_as_array[$type] = $this->_convert($value);
- }
- return $object_as_array;
- }
- /**
- * takes a reflection property and returns a nicely formatted key of the property name
- *
- * @param ReflectionProperty
- * @return string
- */
- protected function _getPropertyKey(ReflectionProperty $property)
- {
- $static = $property->isStatic() ? ' static' : '';
- if ($property->isPublic()) {
- return 'public' . $static . ' ' . $property->getName();
- }
- if ($property->isProtected()) {
- return 'protected' . $static . ' ' . $property->getName();
- }
- if ($property->isPrivate()) {
- return 'private' . $static . ' ' . $property->getName();
- }
- }
- /**
- * adds a value to the data array
- *
- * @var mixed
- * @return void
- */
- protected function _addRow($label, $log, $backtrace, $type)
- {
- // if this is logged on the same line for example in a loop, set it to null to save space
- if (in_array($backtrace, $this->_backtraces)) {
- $backtrace = null;
- }
- if ($backtrace !== null) {
- $this->_backtraces[] = $backtrace;
- }
- $row = array($label, $log, $backtrace, $type);
- $this->_json['rows'][] = $row;
- $this->_writeHeader($this->_json);
- }
- protected function _writeHeader($data)
- {
- header(self::HEADER_NAME . ': ' . $this->_encode($data));
- }
- /**
- * encodes the data to be sent along with the request
- *
- * @param array $data
- * @return string
- */
- protected function _encode($data)
- {
- return base64_encode(utf8_encode(json_encode($data)));
- }
- /**
- * adds a setting
- *
- * @param string key
- * @param mixed value
- * @return void
- */
- public function addSetting($key, $value)
- {
- $this->_settings[$key] = $value;
- }
- /**
- * add ability to set multiple settings in one call
- *
- * @param array $settings
- * @return void
- */
- public function addSettings(array $settings)
- {
- foreach ($settings as $key => $value) {
- $this->addSetting($key, $value);
- }
- }
- /**
- * gets a setting
- *
- * @param string key
- * @return mixed
- */
- public function getSetting($key)
- {
- if (!isset($this->_settings[$key])) {
- return null;
- }
- return $this->_settings[$key];
- }
- }