File: /var/www/html/wp-content/plugins/wp-stateless/lib/classes/class-logger.php
<?php
/**
* Copyright 2010-2013 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.
*/
namespace wpCloud\StatelessMedia {
if( !class_exists( 'wpCloud\StatelessMedia\Logger' ) ) {
/**
* Server Side Chrome PHP debugger class
*
* @package ChromePhp
* @author Craig Campbell <iamcraigcampbell@gmail.com>
*/
class Logger {
/**
* @var string
*/
const VERSION = '4.1.0';
/**
* @var string
*/
const HEADER_NAME = 'X-ChromeLogger-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
*/
const TABLE = 'table';
/**
* @var string
*/
protected $_php_version;
/**
* @var int
*/
protected $_timestamp;
/**
* @var array
*/
protected $_json = array(
'version' => self::VERSION,
'columns' => array( '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 ? sanitize_text_field($_SERVER[ 'REQUEST_TIME' ]) : time();
$this->_json[ 'request_uri' ] = sanitize_text_field($_SERVER[ 'REQUEST_URI' ]);
}
/**
* gets instance of this class
*
* @return ChromePhp
*/
public static function getInstance() {
if( self::$_instance === null ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* logs a variable to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function log() {
$args = func_get_args();
return self::_log( '', $args );
}
/**
* logs a warning to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function warn() {
$args = func_get_args();
return self::_log( self::WARN, $args );
}
/**
* logs an error to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function error() {
$args = func_get_args();
return self::_log( self::ERROR, $args );
}
/**
* sends a group log
*
* @param string value
*/
public static function group() {
$args = func_get_args();
return self::_log( self::GROUP, $args );
}
/**
* sends an info log
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function info() {
$args = func_get_args();
return self::_log( self::INFO, $args );
}
/**
* sends a collapsed group log
*
* @param string value
*/
public static function groupCollapsed() {
$args = func_get_args();
return self::_log( self::GROUP_COLLAPSED, $args );
}
/**
* ends a group log
*
* @param string value
*/
public static function groupEnd() {
$args = func_get_args();
return self::_log( self::GROUP_END, $args );
}
/**
* sends a table log
*
* @param string value
*/
public static function table() {
$args = func_get_args();
return self::_log( self::TABLE, $args );
}
/**
* internal logging call
*
* @param string $type
* @return void
*/
protected static function _log( $type, array $args ) {
// nothing passed in, don't do anything
if( count( $args ) == 0 && $type != self::GROUP_END ) {
return;
}
$logger = self::getInstance();
$logger->_processed = array();
$logs = array();
foreach( $args as $arg ) {
$logs[] = $logger->_convert( $arg );
}
$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( $logs, $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( array $logs, $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;
}
// for group, groupEnd, and groupCollapsed
// take out the backtrace since it is not useful
if( $type == self::GROUP || $type == self::GROUP_END || $type == self::GROUP_COLLAPSED ) {
$backtrace = null;
}
if( $backtrace !== null ) {
$this->_backtraces[] = $backtrace;
}
$row = array( $logs, $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 ) {
if ( function_exists('mb_convert_encoding') ) {
$encoded = json_encode($data);
if ( $encoded !== false ) {
$utf8 = mb_convert_encoding($encoded, 'UTF-8', 'UTF-8');
if ($utf8 !== false) {
return base64_encode($utf8);
}
}
}
return false;
}
/**
* 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 ];
}
}
}
}