ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
BrowserConsoleHandler.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Monolog package.
5  *
6  * (c) Jordi Boggiano <j.boggiano@seld.be>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Monolog\Handler;
13 
15 
22 {
23  protected static $initialized = false;
24  protected static $records = array();
25 
35  protected function getDefaultFormatter()
36  {
37  return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%');
38  }
39 
43  protected function write(array $record)
44  {
45  // Accumulate records
46  self::$records[] = $record;
47 
48  // Register shutdown handler if not already done
49  if (!self::$initialized) {
50  self::$initialized = true;
51  $this->registerShutdownFunction();
52  }
53  }
54 
59  public static function send()
60  {
61  $format = self::getResponseFormat();
62  if ($format === 'unknown') {
63  return;
64  }
65 
66  if (count(self::$records)) {
67  if ($format === 'html') {
68  self::writeOutput('<script>' . self::generateScript() . '</script>');
69  } elseif ($format === 'js') {
70  self::writeOutput(self::generateScript());
71  }
72  self::reset();
73  }
74  }
75 
79  public static function reset()
80  {
82  }
83 
87  protected function registerShutdownFunction()
88  {
89  if (PHP_SAPI !== 'cli') {
90  register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
91  }
92  }
93 
99  protected static function writeOutput($str)
100  {
101  echo $str;
102  }
103 
113  protected static function getResponseFormat()
114  {
115  // Check content type
116  foreach (headers_list() as $header) {
117  if (stripos($header, 'content-type:') === 0) {
118  // This handler only works with HTML and javascript outputs
119  // text/javascript is obsolete in favour of application/javascript, but still used
120  if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
121  return 'js';
122  }
123  if (stripos($header, 'text/html') === false) {
124  return 'unknown';
125  }
126  break;
127  }
128  }
129 
130  return 'html';
131  }
132 
133  private static function generateScript()
134  {
135  $script = array();
136  foreach (self::$records as $record) {
137  $context = self::dump('Context', $record['context']);
138  $extra = self::dump('Extra', $record['extra']);
139 
140  if (empty($context) && empty($extra)) {
141  $script[] = self::call_array('log', self::handleStyles($record['formatted']));
142  } else {
143  $script = array_merge($script,
144  array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))),
145  $context,
146  $extra,
147  array(self::call('groupEnd'))
148  );
149  }
150  }
151 
152  return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
153  }
154 
155  private static function handleStyles($formatted)
156  {
157  $args = array(self::quote('font-weight: normal'));
158  $format = '%c' . $formatted;
159  preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
160 
161  foreach (array_reverse($matches) as $match) {
162  $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0]));
163  $args[] = '"font-weight: normal"';
164 
165  $pos = $match[0][1];
166  $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
167  }
168 
169  array_unshift($args, self::quote($format));
170 
171  return $args;
172  }
173 
174  private static function handleCustomStyles($style, $string)
175  {
176  static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey');
177  static $labels = array();
178 
179  return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) {
180  if (trim($m[1]) === 'autolabel') {
181  // Format the string as a label with consistent auto assigned background color
182  if (!isset($labels[$string])) {
183  $labels[$string] = $colors[count($labels) % count($colors)];
184  }
185  $color = $labels[$string];
186 
187  return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px";
188  }
189 
190  return $m[1];
191  }, $style);
192  }
193 
194  private static function dump($title, array $dict)
195  {
196  $script = array();
197  $dict = array_filter($dict);
198  if (empty($dict)) {
199  return $script;
200  }
201  $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title));
202  foreach ($dict as $key => $value) {
203  $value = json_encode($value);
204  if (empty($value)) {
205  $value = self::quote('');
206  }
207  $script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value);
208  }
209 
210  return $script;
211  }
212 
213  private static function quote($arg)
214  {
215  return '"' . addcslashes($arg, "\"\n\\") . '"';
216  }
217 
218  private static function call()
219  {
220  $args = func_get_args();
221  $method = array_shift($args);
222 
223  return self::call_array($method, $args);
224  }
225 
226  private static function call_array($method, array $args)
227  {
228  return 'c.' . $method . '(' . implode(', ', $args) . ');';
229  }
230 }
static getResponseFormat()
Checks the format of the response.
$style
Definition: example_012.php:70
static writeOutput($str)
Wrapper for echo to allow overriding.
Base Handler class providing the Handler structure.
static send()
Convert records to javascript console commands and send it to the browser.
$records
Definition: simple_test.php:22
Handler sending logs to browser&#39;s javascript console with no browser extension required.
$header
registerShutdownFunction()
Wrapper for register_shutdown_function to allow overriding.
static reset()
Forget all logged records.
Create styles array
The data for the language used.
Formats incoming records into a one-line string.