[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 * This file is part of the DebugBar package. 4 * 5 * (c) 2013 Maxime Bouroumeau-Fuseau 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11 namespace DebugBar; 12 13 use ArrayAccess; 14 use DebugBar\DataCollector\DataCollectorInterface; 15 use DebugBar\Storage\StorageInterface; 16 17 /** 18 * Main DebugBar object 19 * 20 * Manages data collectors. DebugBar provides an array-like access 21 * to collectors by name. 22 * 23 * <code> 24 * $debugbar = new DebugBar(); 25 * $debugbar->addCollector(new DataCollector\MessagesCollector()); 26 * $debugbar['messages']->addMessage("foobar"); 27 * </code> 28 */ 29 class DebugBar implements ArrayAccess 30 { 31 public static $useOpenHandlerWhenSendingDataHeaders = false; 32 33 protected $collectors = array(); 34 35 protected $data; 36 37 protected $jsRenderer; 38 39 protected $requestIdGenerator; 40 41 protected $requestId; 42 43 protected $storage; 44 45 protected $httpDriver; 46 47 protected $stackSessionNamespace = 'PHPDEBUGBAR_STACK_DATA'; 48 49 protected $stackAlwaysUseSessionStorage = false; 50 51 /** 52 * Adds a data collector 53 * 54 * @param DataCollectorInterface $collector 55 * 56 * @throws DebugBarException 57 * @return $this 58 */ 59 public function addCollector(DataCollectorInterface $collector) 60 { 61 if ($collector->getName() === '__meta') { 62 throw new DebugBarException("'__meta' is a reserved name and cannot be used as a collector name"); 63 } 64 if (isset($this->collectors[$collector->getName()])) { 65 throw new DebugBarException("'{$collector->getName()}' is already a registered collector"); 66 } 67 $this->collectors[$collector->getName()] = $collector; 68 return $this; 69 } 70 71 /** 72 * Checks if a data collector has been added 73 * 74 * @param string $name 75 * @return boolean 76 */ 77 public function hasCollector($name) 78 { 79 return isset($this->collectors[$name]); 80 } 81 82 /** 83 * Returns a data collector 84 * 85 * @param string $name 86 * @return DataCollectorInterface 87 * @throws DebugBarException 88 */ 89 public function getCollector($name) 90 { 91 if (!isset($this->collectors[$name])) { 92 throw new DebugBarException("'$name' is not a registered collector"); 93 } 94 return $this->collectors[$name]; 95 } 96 97 /** 98 * Returns an array of all data collectors 99 * 100 * @return array[DataCollectorInterface] 101 */ 102 public function getCollectors() 103 { 104 return $this->collectors; 105 } 106 107 /** 108 * Sets the request id generator 109 * 110 * @param RequestIdGeneratorInterface $generator 111 * @return $this 112 */ 113 public function setRequestIdGenerator(RequestIdGeneratorInterface $generator) 114 { 115 $this->requestIdGenerator = $generator; 116 return $this; 117 } 118 119 /** 120 * @return RequestIdGeneratorInterface 121 */ 122 public function getRequestIdGenerator() 123 { 124 if ($this->requestIdGenerator === null) { 125 $this->requestIdGenerator = new RequestIdGenerator(); 126 } 127 return $this->requestIdGenerator; 128 } 129 130 /** 131 * Returns the id of the current request 132 * 133 * @return string 134 */ 135 public function getCurrentRequestId() 136 { 137 if ($this->requestId === null) { 138 $this->requestId = $this->getRequestIdGenerator()->generate(); 139 } 140 return $this->requestId; 141 } 142 143 /** 144 * Sets the storage backend to use to store the collected data 145 * 146 * @param StorageInterface $storage 147 * @return $this 148 */ 149 public function setStorage(StorageInterface $storage = null) 150 { 151 $this->storage = $storage; 152 return $this; 153 } 154 155 /** 156 * @return StorageInterface 157 */ 158 public function getStorage() 159 { 160 return $this->storage; 161 } 162 163 /** 164 * Checks if the data will be persisted 165 * 166 * @return boolean 167 */ 168 public function isDataPersisted() 169 { 170 return $this->storage !== null; 171 } 172 173 /** 174 * Sets the HTTP driver 175 * 176 * @param HttpDriverInterface $driver 177 * @return $this 178 */ 179 public function setHttpDriver(HttpDriverInterface $driver) 180 { 181 $this->httpDriver = $driver; 182 return $this; 183 } 184 185 /** 186 * Returns the HTTP driver 187 * 188 * If no http driver where defined, a PhpHttpDriver is automatically created 189 * 190 * @return HttpDriverInterface 191 */ 192 public function getHttpDriver() 193 { 194 if ($this->httpDriver === null) { 195 $this->httpDriver = new PhpHttpDriver(); 196 } 197 return $this->httpDriver; 198 } 199 200 /** 201 * Collects the data from the collectors 202 * 203 * @return array 204 */ 205 public function collect() 206 { 207 if (php_sapi_name() === 'cli') { 208 $ip = gethostname(); 209 if ($ip) { 210 $ip = gethostbyname($ip); 211 } else { 212 $ip = '127.0.0.1'; 213 } 214 $request_variables = array( 215 'method' => 'CLI', 216 'uri' => isset($_SERVER['SCRIPT_FILENAME']) ? realpath($_SERVER['SCRIPT_FILENAME']) : null, 217 'ip' => $ip 218 ); 219 } else { 220 $request_variables = array( 221 'method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null, 222 'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null, 223 'ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null 224 ); 225 } 226 $this->data = array( 227 '__meta' => array_merge( 228 array( 229 'id' => $this->getCurrentRequestId(), 230 'datetime' => date('Y-m-d H:i:s'), 231 'utime' => microtime(true) 232 ), 233 $request_variables 234 ) 235 ); 236 237 foreach ($this->collectors as $name => $collector) { 238 $this->data[$name] = $collector->collect(); 239 } 240 241 // Remove all invalid (non UTF-8) characters 242 array_walk_recursive($this->data, function (&$item) { 243 if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) { 244 $item = mb_convert_encoding($item, 'UTF-8', 'UTF-8'); 245 } 246 }); 247 248 if ($this->storage !== null) { 249 $this->storage->save($this->getCurrentRequestId(), $this->data); 250 } 251 252 return $this->data; 253 } 254 255 /** 256 * Returns collected data 257 * 258 * Will collect the data if none have been collected yet 259 * 260 * @return array 261 */ 262 public function getData() 263 { 264 if ($this->data === null) { 265 $this->collect(); 266 } 267 return $this->data; 268 } 269 270 /** 271 * Returns an array of HTTP headers containing the data 272 * 273 * @param string $headerName 274 * @param integer $maxHeaderLength 275 * @return array 276 */ 277 public function getDataAsHeaders($headerName = 'phpdebugbar', $maxHeaderLength = 4096, $maxTotalHeaderLength = 250000) 278 { 279 $data = rawurlencode(json_encode(array( 280 'id' => $this->getCurrentRequestId(), 281 'data' => $this->getData() 282 ))); 283 284 if (strlen($data) > $maxTotalHeaderLength) { 285 $data = rawurlencode(json_encode(array( 286 'error' => 'Maximum header size exceeded' 287 ))); 288 } 289 290 $chunks = array(); 291 292 while (strlen($data) > $maxHeaderLength) { 293 $chunks[] = substr($data, 0, $maxHeaderLength); 294 $data = substr($data, $maxHeaderLength); 295 } 296 $chunks[] = $data; 297 298 $headers = array(); 299 for ($i = 0, $c = count($chunks); $i < $c; $i++) { 300 $name = $headerName . ($i > 0 ? "-$i" : ''); 301 $headers[$name] = $chunks[$i]; 302 } 303 304 return $headers; 305 } 306 307 /** 308 * Sends the data through the HTTP headers 309 * 310 * @param bool $useOpenHandler 311 * @param string $headerName 312 * @param integer $maxHeaderLength 313 * @return $this 314 */ 315 public function sendDataInHeaders($useOpenHandler = null, $headerName = 'phpdebugbar', $maxHeaderLength = 4096) 316 { 317 if ($useOpenHandler === null) { 318 $useOpenHandler = self::$useOpenHandlerWhenSendingDataHeaders; 319 } 320 if ($useOpenHandler && $this->storage !== null) { 321 $this->getData(); 322 $headerName .= '-id'; 323 $headers = array($headerName => $this->getCurrentRequestId()); 324 } else { 325 $headers = $this->getDataAsHeaders($headerName, $maxHeaderLength); 326 } 327 $this->getHttpDriver()->setHeaders($headers); 328 return $this; 329 } 330 331 /** 332 * Stacks the data in the session for later rendering 333 */ 334 public function stackData() 335 { 336 $http = $this->initStackSession(); 337 338 $data = null; 339 if (!$this->isDataPersisted() || $this->stackAlwaysUseSessionStorage) { 340 $data = $this->getData(); 341 } elseif ($this->data === null) { 342 $this->collect(); 343 } 344 345 $stack = $http->getSessionValue($this->stackSessionNamespace); 346 $stack[$this->getCurrentRequestId()] = $data; 347 $http->setSessionValue($this->stackSessionNamespace, $stack); 348 return $this; 349 } 350 351 /** 352 * Checks if there is stacked data in the session 353 * 354 * @return boolean 355 */ 356 public function hasStackedData() 357 { 358 try { 359 $http = $this->initStackSession(); 360 } catch (DebugBarException $e) { 361 return false; 362 } 363 return count($http->getSessionValue($this->stackSessionNamespace)) > 0; 364 } 365 366 /** 367 * Returns the data stacked in the session 368 * 369 * @param boolean $delete Whether to delete the data in the session 370 * @return array 371 */ 372 public function getStackedData($delete = true) 373 { 374 $http = $this->initStackSession(); 375 $stackedData = $http->getSessionValue($this->stackSessionNamespace); 376 if ($delete) { 377 $http->deleteSessionValue($this->stackSessionNamespace); 378 } 379 380 $datasets = array(); 381 if ($this->isDataPersisted() && !$this->stackAlwaysUseSessionStorage) { 382 foreach ($stackedData as $id => $data) { 383 $datasets[$id] = $this->getStorage()->get($id); 384 } 385 } else { 386 $datasets = $stackedData; 387 } 388 389 return $datasets; 390 } 391 392 /** 393 * Sets the key to use in the $_SESSION array 394 * 395 * @param string $ns 396 * @return $this 397 */ 398 public function setStackDataSessionNamespace($ns) 399 { 400 $this->stackSessionNamespace = $ns; 401 return $this; 402 } 403 404 /** 405 * Returns the key used in the $_SESSION array 406 * 407 * @return string 408 */ 409 public function getStackDataSessionNamespace() 410 { 411 return $this->stackSessionNamespace; 412 } 413 414 /** 415 * Sets whether to only use the session to store stacked data even 416 * if a storage is enabled 417 * 418 * @param boolean $enabled 419 * @return $this 420 */ 421 public function setStackAlwaysUseSessionStorage($enabled = true) 422 { 423 $this->stackAlwaysUseSessionStorage = $enabled; 424 return $this; 425 } 426 427 /** 428 * Checks if the session is always used to store stacked data 429 * even if a storage is enabled 430 * 431 * @return boolean 432 */ 433 public function isStackAlwaysUseSessionStorage() 434 { 435 return $this->stackAlwaysUseSessionStorage; 436 } 437 438 /** 439 * Initializes the session for stacked data 440 * @return HttpDriverInterface 441 * @throws DebugBarException 442 */ 443 protected function initStackSession() 444 { 445 $http = $this->getHttpDriver(); 446 if (!$http->isSessionStarted()) { 447 throw new DebugBarException("Session must be started before using stack data in the debug bar"); 448 } 449 450 if (!$http->hasSessionValue($this->stackSessionNamespace)) { 451 $http->setSessionValue($this->stackSessionNamespace, array()); 452 } 453 454 return $http; 455 } 456 457 /** 458 * Returns a JavascriptRenderer for this instance 459 * @param string $baseUrl 460 * @param string $basePath 461 * @return JavascriptRenderer 462 */ 463 public function getJavascriptRenderer($baseUrl = null, $basePath = null) 464 { 465 if ($this->jsRenderer === null) { 466 $this->jsRenderer = new JavascriptRenderer($this, $baseUrl, $basePath); 467 } 468 return $this->jsRenderer; 469 } 470 471 // -------------------------------------------- 472 // ArrayAccess implementation 473 474 #[\ReturnTypeWillChange] 475 public function offsetSet($key, $value) 476 { 477 throw new DebugBarException("DebugBar[] is read-only"); 478 } 479 480 #[\ReturnTypeWillChange] 481 public function offsetGet($key) 482 { 483 return $this->getCollector($key); 484 } 485 486 #[\ReturnTypeWillChange] 487 public function offsetExists($key) 488 { 489 return $this->hasCollector($key); 490 } 491 492 #[\ReturnTypeWillChange] 493 public function offsetUnset($key) 494 { 495 throw new DebugBarException("DebugBar[] is read-only"); 496 } 497 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |