media-cloud-sync
/
includes
/
sdk
/
google
/
monolog
/
monolog
/
src
/
Monolog
/
Handler
/
PHPConsoleHandler.php
PHPConsoleHandler.php in Media Cloud Sync 1.2.5, at includes/sdk/google/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
| 1 | <?php |
| 2 | |
| 3 | declare (strict_types=1); |
| 4 | /* |
| 5 | * This file is part of the Monolog package. |
| 6 | * |
| 7 | * (c) Jordi Boggiano <[email protected]> |
| 8 | * |
| 9 | * For the full copyright and license information, please view the LICENSE |
| 10 | * file that was distributed with this source code. |
| 11 | */ |
| 12 | namespace Dudlewebs\WPMCS\Monolog\Handler; |
| 13 | |
| 14 | use Dudlewebs\WPMCS\Monolog\Formatter\LineFormatter; |
| 15 | use Dudlewebs\WPMCS\Monolog\Formatter\FormatterInterface; |
| 16 | use Dudlewebs\WPMCS\Monolog\Logger; |
| 17 | use Dudlewebs\WPMCS\Monolog\Utils; |
| 18 | use Dudlewebs\WPMCS\PhpConsole\Connector; |
| 19 | use Dudlewebs\WPMCS\PhpConsole\Handler as VendorPhpConsoleHandler; |
| 20 | use Dudlewebs\WPMCS\PhpConsole\Helper; |
| 21 | /** |
| 22 | * Monolog handler for Google Chrome extension "PHP Console" |
| 23 | * |
| 24 | * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely |
| 25 | * |
| 26 | * Usage: |
| 27 | * 1. Install Google Chrome extension [now dead and removed from the chrome store] |
| 28 | * 2. See overview https://github.com/barbushin/php-console#overview |
| 29 | * 3. Install PHP Console library https://github.com/barbushin/php-console#installation |
| 30 | * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png) |
| 31 | * |
| 32 | * $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler())); |
| 33 | * \Monolog\ErrorHandler::register($logger); |
| 34 | * echo $undefinedVar; |
| 35 | * $logger->debug('SELECT * FROM users', array('db', 'time' => 0.012)); |
| 36 | * PC::debug($_SERVER); // PHP Console debugger for any type of vars |
| 37 | * |
| 38 | * @author Sergey Barbushin https://www.linkedin.com/in/barbushin |
| 39 | * |
| 40 | * @phpstan-import-type Record from \Monolog\Logger |
| 41 | * @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4 |
| 42 | */ |
| 43 | class PHPConsoleHandler extends AbstractProcessingHandler |
| 44 | { |
| 45 | /** @var array<string, mixed> */ |
| 46 | private $options = [ |
| 47 | 'enabled' => \true, |
| 48 | // bool Is PHP Console server enabled |
| 49 | 'classesPartialsTraceIgnore' => ['Monolog\\'], |
| 50 | // array Hide calls of classes started with... |
| 51 | 'debugTagsKeysInContext' => [0, 'tag'], |
| 52 | // bool Is PHP Console server enabled |
| 53 | 'useOwnErrorsHandler' => \false, |
| 54 | // bool Enable errors handling |
| 55 | 'useOwnExceptionsHandler' => \false, |
| 56 | // bool Enable exceptions handling |
| 57 | 'sourcesBasePath' => null, |
| 58 | // string Base path of all project sources to strip in errors source paths |
| 59 | 'registerHelper' => \true, |
| 60 | // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s') |
| 61 | 'serverEncoding' => null, |
| 62 | // string|null Server internal encoding |
| 63 | 'headersLimit' => null, |
| 64 | // int|null Set headers size limit for your web-server |
| 65 | 'password' => null, |
| 66 | // string|null Protect PHP Console connection by password |
| 67 | 'enableSslOnlyMode' => \false, |
| 68 | // bool Force connection by SSL for clients with PHP Console installed |
| 69 | 'ipMasks' => [], |
| 70 | // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') |
| 71 | 'enableEvalListener' => \false, |
| 72 | // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required) |
| 73 | 'dumperDetectCallbacks' => \false, |
| 74 | // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings |
| 75 | 'dumperLevelLimit' => 5, |
| 76 | // int Maximum dumped vars array or object nested dump level |
| 77 | 'dumperItemsCountLimit' => 100, |
| 78 | // int Maximum dumped var same level array items or object properties number |
| 79 | 'dumperItemSizeLimit' => 5000, |
| 80 | // int Maximum length of any string or dumped array item |
| 81 | 'dumperDumpSizeLimit' => 500000, |
| 82 | // int Maximum approximate size of dumped vars result formatted in JSON |
| 83 | 'detectDumpTraceAndSource' => \false, |
| 84 | // bool Autodetect and append trace data to debug |
| 85 | 'dataStorage' => null, |
| 86 | ]; |
| 87 | /** @var Connector */ |
| 88 | private $connector; |
| 89 | /** |
| 90 | * @param array<string, mixed> $options See \Monolog\Handler\PHPConsoleHandler::$options for more details |
| 91 | * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) |
| 92 | * @throws \RuntimeException |
| 93 | */ |
| 94 | public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = \true) |
| 95 | { |
| 96 | if (!class_exists('Dudlewebs\WPMCS\PhpConsole\Connector')) { |
| 97 | throw new \RuntimeException('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); |
| 98 | } |
| 99 | parent::__construct($level, $bubble); |
| 100 | $this->options = $this->initOptions($options); |
| 101 | $this->connector = $this->initConnector($connector); |
| 102 | } |
| 103 | /** |
| 104 | * @param array<string, mixed> $options |
| 105 | * |
| 106 | * @return array<string, mixed> |
| 107 | */ |
| 108 | private function initOptions(array $options): array |
| 109 | { |
| 110 | $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); |
| 111 | if ($wrongOptions) { |
| 112 | throw new \RuntimeException('Unknown options: ' . implode(', ', $wrongOptions)); |
| 113 | } |
| 114 | return array_replace($this->options, $options); |
| 115 | } |
| 116 | private function initConnector(?Connector $connector = null): Connector |
| 117 | { |
| 118 | if (!$connector) { |
| 119 | if ($this->options['dataStorage']) { |
| 120 | Connector::setPostponeStorage($this->options['dataStorage']); |
| 121 | } |
| 122 | $connector = Connector::getInstance(); |
| 123 | } |
| 124 | if ($this->options['registerHelper'] && !Helper::isRegistered()) { |
| 125 | Helper::register(); |
| 126 | } |
| 127 | if ($this->options['enabled'] && $connector->isActiveClient()) { |
| 128 | if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) { |
| 129 | $handler = VendorPhpConsoleHandler::getInstance(); |
| 130 | $handler->setHandleErrors($this->options['useOwnErrorsHandler']); |
| 131 | $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']); |
| 132 | $handler->start(); |
| 133 | } |
| 134 | if ($this->options['sourcesBasePath']) { |
| 135 | $connector->setSourcesBasePath($this->options['sourcesBasePath']); |
| 136 | } |
| 137 | if ($this->options['serverEncoding']) { |
| 138 | $connector->setServerEncoding($this->options['serverEncoding']); |
| 139 | } |
| 140 | if ($this->options['password']) { |
| 141 | $connector->setPassword($this->options['password']); |
| 142 | } |
| 143 | if ($this->options['enableSslOnlyMode']) { |
| 144 | $connector->enableSslOnlyMode(); |
| 145 | } |
| 146 | if ($this->options['ipMasks']) { |
| 147 | $connector->setAllowedIpMasks($this->options['ipMasks']); |
| 148 | } |
| 149 | if ($this->options['headersLimit']) { |
| 150 | $connector->setHeadersLimit($this->options['headersLimit']); |
| 151 | } |
| 152 | if ($this->options['detectDumpTraceAndSource']) { |
| 153 | $connector->getDebugDispatcher()->detectTraceAndSource = \true; |
| 154 | } |
| 155 | $dumper = $connector->getDumper(); |
| 156 | $dumper->levelLimit = $this->options['dumperLevelLimit']; |
| 157 | $dumper->itemsCountLimit = $this->options['dumperItemsCountLimit']; |
| 158 | $dumper->itemSizeLimit = $this->options['dumperItemSizeLimit']; |
| 159 | $dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit']; |
| 160 | $dumper->detectCallbacks = $this->options['dumperDetectCallbacks']; |
| 161 | if ($this->options['enableEvalListener']) { |
| 162 | $connector->startEvalRequestsListener(); |
| 163 | } |
| 164 | } |
| 165 | return $connector; |
| 166 | } |
| 167 | public function getConnector(): Connector |
| 168 | { |
| 169 | return $this->connector; |
| 170 | } |
| 171 | /** |
| 172 | * @return array<string, mixed> |
| 173 | */ |
| 174 | public function getOptions(): array |
| 175 | { |
| 176 | return $this->options; |
| 177 | } |
| 178 | public function handle(array $record): bool |
| 179 | { |
| 180 | if ($this->options['enabled'] && $this->connector->isActiveClient()) { |
| 181 | return parent::handle($record); |
| 182 | } |
| 183 | return !$this->bubble; |
| 184 | } |
| 185 | /** |
| 186 | * Writes the record down to the log of the implementing handler |
| 187 | */ |
| 188 | protected function write(array $record): void |
| 189 | { |
| 190 | if ($record['level'] < Logger::NOTICE) { |
| 191 | $this->handleDebugRecord($record); |
| 192 | } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { |
| 193 | $this->handleExceptionRecord($record); |
| 194 | } else { |
| 195 | $this->handleErrorRecord($record); |
| 196 | } |
| 197 | } |
| 198 | /** |
| 199 | * @phpstan-param Record $record |
| 200 | */ |
| 201 | private function handleDebugRecord(array $record): void |
| 202 | { |
| 203 | $tags = $this->getRecordTags($record); |
| 204 | $message = $record['message']; |
| 205 | if ($record['context']) { |
| 206 | $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, \true); |
| 207 | } |
| 208 | $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); |
| 209 | } |
| 210 | /** |
| 211 | * @phpstan-param Record $record |
| 212 | */ |
| 213 | private function handleExceptionRecord(array $record): void |
| 214 | { |
| 215 | $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); |
| 216 | } |
| 217 | /** |
| 218 | * @phpstan-param Record $record |
| 219 | */ |
| 220 | private function handleErrorRecord(array $record): void |
| 221 | { |
| 222 | $context = $record['context']; |
| 223 | $this->connector->getErrorsDispatcher()->dispatchError($context['code'] ?? null, $context['message'] ?? $record['message'], $context['file'] ?? null, $context['line'] ?? null, $this->options['classesPartialsTraceIgnore']); |
| 224 | } |
| 225 | /** |
| 226 | * @phpstan-param Record $record |
| 227 | * @return string |
| 228 | */ |
| 229 | private function getRecordTags(array &$record) |
| 230 | { |
| 231 | $tags = null; |
| 232 | if (!empty($record['context'])) { |
| 233 | $context =& $record['context']; |
| 234 | foreach ($this->options['debugTagsKeysInContext'] as $key) { |
| 235 | if (!empty($context[$key])) { |
| 236 | $tags = $context[$key]; |
| 237 | if ($key === 0) { |
| 238 | array_shift($context); |
| 239 | } else { |
| 240 | unset($context[$key]); |
| 241 | } |
| 242 | break; |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | return $tags ?: strtolower($record['level_name']); |
| 247 | } |
| 248 | /** |
| 249 | * {@inheritDoc} |
| 250 | */ |
| 251 | protected function getDefaultFormatter(): FormatterInterface |
| 252 | { |
| 253 | return new LineFormatter('%message%'); |
| 254 | } |
| 255 | } |
| 256 |