Changeset 1542350
- Timestamp:
- 11/29/2016 12:54:44 AM (9 years ago)
- Location:
- bugsnag/trunk
- Files:
-
- 12 edited
-
bugsnag-php/Autoload.php (modified) (1 diff)
-
bugsnag-php/Client.php (modified) (29 diffs)
-
bugsnag-php/Configuration.php (modified) (5 diffs)
-
bugsnag-php/Diagnostics.php (modified) (4 diffs)
-
bugsnag-php/Error.php (modified) (10 diffs)
-
bugsnag-php/ErrorTypes.php (modified) (5 diffs)
-
bugsnag-php/Notification.php (modified) (8 diffs)
-
bugsnag-php/Request.php (modified) (4 diffs)
-
bugsnag-php/Stacktrace.php (modified) (7 diffs)
-
bugsnag.php (modified) (12 diffs)
-
readme.txt (modified) (2 diffs)
-
views/settings.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
bugsnag/trunk/bugsnag-php/Autoload.php
r871602 r1542350 1 1 <?php 2 2 3 #We used to have an autoloader, but it caused problems in some4 #environments. So now we manually load the entire library upfront.5 # 6 #The file is still called Autoload so that existing integration7 #instructions continue to work.8 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Client.php";9 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Configuration.php";10 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Diagnostics.php";11 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Error.php";12 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "ErrorTypes.php";13 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Notification.php";14 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Request.php";15 require_once dirname(__FILE__).DIRECTORY_SEPARATOR. "Stacktrace.php";3 // We used to have an autoloader, but it caused problems in some 4 // environments. So now we manually load the entire library upfront. 5 // 6 // The file is still called Autoload so that existing integration 7 // instructions continue to work. 8 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Client.php'; 9 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Configuration.php'; 10 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Diagnostics.php'; 11 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Error.php'; 12 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'ErrorTypes.php'; 13 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Notification.php'; 14 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Request.php'; 15 require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'Stacktrace.php'; -
bugsnag/trunk/bugsnag-php/Client.php
r871602 r1542350 3 3 class Bugsnag_Client 4 4 { 5 /** 6 * The config instance. 7 * 8 * @var Bugsnag_Configuration 9 */ 5 10 private $config; 11 12 /** 13 * The diagnostics instance. 14 * 15 * @var Bugsnag_Diagnostics 16 */ 17 private $diagnostics; 18 19 /** 20 * The notification instance. 21 * 22 * @var Bugsnag_Notification|null 23 */ 6 24 private $notification; 7 25 8 26 /** 9 * Initialize Bugsnag 10 * 11 * @param String $apiKey your Bugsnag API key 27 * Create a new client instance. 28 * 29 * @param string $apiKey your Bugsnag API key 30 * 31 * @throws Exception 32 * 33 * @return void 12 34 */ 13 35 public function __construct($apiKey) … … 18 40 } 19 41 20 // Check cURL is enabled21 if (!function_exists('curl_version')) {22 throw new Exception('Bugsnag Error: Bugsnag requires cURL support to be enabled on your PHP installation');23 }24 25 42 // Create a configuration object 26 43 $this->config = new Bugsnag_Configuration(); … … 30 47 $this->diagnostics = new Bugsnag_Diagnostics($this->config); 31 48 32 // Attempt to determine a sensible default for projectRoot33 if (isset($_SERVER) && !empty($_SERVER['DOCUMENT_ROOT'])) {34 $this->setProjectRoot($_SERVER['DOCUMENT_ROOT']);35 }36 37 49 // Register a shutdown function to check for fatal errors 38 50 // and flush any buffered errors … … 41 53 42 54 /** 43 * Set your release stage, eg "production" or "development" 44 * 45 * @param String $releaseStage the app's current release stage 55 * Set your release stage, eg "production" or "development". 56 * 57 * @param string $releaseStage the app's current release stage 58 * 59 * @return $this 46 60 */ 47 61 public function setReleaseStage($releaseStage) … … 53 67 54 68 /** 55 * Set your app's semantic version, eg "1.2.3" 56 * 57 * @param String $appVersion the app's version 69 * Set your app's semantic version, eg "1.2.3". 70 * 71 * @param string $appVersion the app's version 72 * 73 * @return $this 58 74 */ 59 75 public function setAppVersion($appVersion) … … 65 81 66 82 /** 67 * Set which release stages should be allowed to notify Bugsnag 68 * eg array("production", "development") 69 * 70 * @param Array $notifyReleaseStages array of release stages to notify for 83 * Set the host name. 84 * 85 * @param string $hostname the host name 86 * 87 * @return $this 88 */ 89 public function setHostname($hostname) 90 { 91 $this->config->hostname = $hostname; 92 93 return $this; 94 } 95 96 /** 97 * Set which release stages should be allowed to notify Bugsnag. 98 * 99 * Eg array('production', 'development'). 100 * 101 * @param array $notifyReleaseStages array of release stages to notify for 102 * 103 * @return $this 71 104 */ 72 105 public function setNotifyReleaseStages(array $notifyReleaseStages) … … 80 113 * Set which Bugsnag endpoint to send errors to. 81 114 * 82 * @param String $endpoint endpoint URL 115 * @param string $endpoint endpoint URL 116 * 117 * @return $this 83 118 */ 84 119 public function setEndpoint($endpoint) … … 90 125 91 126 /** 92 * Set whether or not to use SSL when notifying bugsnag 93 * 94 * @param Boolean $useSSL whether to use SSL 127 * Enable debug mode to help diagnose problems. 128 * 129 * @param bool $debug whether to enable debug mode 130 * 131 * @return $this 132 */ 133 public function setDebug($debug) 134 { 135 $this->config->debug = $debug; 136 137 return $this; 138 } 139 140 /** 141 * Set whether or not to use SSL when notifying bugsnag. 142 * 143 * @param bool $useSSL whether to use SSL 144 * 145 * @return $this 146 * 147 * @deprecated since version 2.5. Pass full URLs to setEndpoint. 95 148 */ 96 149 public function setUseSSL($useSSL) … … 102 155 103 156 /** 104 * Set the desired timeout for cURL connection when notifying bugsnag 105 * 106 * @param Integer $timeout the desired timeout in seconds 157 * Set the desired timeout for cURL connection when notifying bugsnag. 158 * 159 * @param int $timeout the desired timeout in seconds 160 * 161 * @return $this 107 162 */ 108 163 public function setTimeout($timeout) … … 115 170 /** 116 171 * Set the absolute path to the root of your application. 172 * 117 173 * We use this to help with error grouping and to highlight "in project" 118 174 * stacktrace lines. 119 175 * 120 * @param String $projectRoot the root path for your application 176 * @param string $projectRoot the root path for your application 177 * 178 * @return $this 121 179 */ 122 180 public function setProjectRoot($projectRoot) … … 128 186 129 187 /** 130 * Set the a regular expression for matching filenames in stacktrace lines 131 * that are part of your application. 132 * 133 * @param String $projectRootRegex regex matching paths belong to your project 188 * Set the absolute split path. 189 * 190 * This is the path that should be stripped from the beginning of any 191 * stacktrace file line. This helps to normalise filenames for grouping 192 * and reduces the noise in stack traces. 193 * 194 * @param string $stripPath the path to strip from filenames 195 * 196 * @return $this 197 */ 198 public function setStripPath($stripPath) 199 { 200 $this->config->setStripPath($stripPath); 201 202 return $this; 203 } 204 205 /** 206 * Set the a regular expression for matching filenames in stacktrace lines. 207 * 208 * @param string $projectRootRegex regex matching paths belong to your project 209 * 210 * @return $this 134 211 */ 135 212 public function setProjectRootRegex($projectRootRegex) … … 141 218 142 219 /** 143 * Set the strings to filter out from metaData arrays before sending then 144 * to Bugsnag. Eg. array("password", "credit_card") 145 * 146 * @param Array $filters an array of metaData filters 220 * Set the strings to filter out from metaData arrays before sending then. 221 * 222 * Eg. array('password', 'credit_card'). 223 * 224 * @param array $filters an array of metaData filters 225 * 226 * @return $this 147 227 */ 148 228 public function setFilters(array $filters) … … 154 234 155 235 /** 156 * Set information about the current user of your app, including 157 * id, name and email. 158 * 159 * @param Array $user an array of user information. Eg: 236 * Set information about the current user of your app, including id, name and email. 237 * 238 * @param array $user an array of user information. Eg: 160 239 * array( 161 240 * 'name' => 'Bob Hoskins', 162 241 * 'email' => '[email protected]' 163 242 * ) 243 * 244 * @return $this 164 245 */ 165 246 public function setUser(array $user) … … 171 252 172 253 /** 173 * @deprecated deprecated since version 2.1 254 * @param $userId 255 * 256 * @return $this 257 * 258 * @deprecated since version 2.1. Use setUser instead. 174 259 */ 175 260 public function setUserId($userId) … … 187 272 * Set a context representing the current type of request, or location in code. 188 273 * 189 * @param String $context the current context 274 * @param string $context the current context 275 * 276 * @return $this 190 277 */ 191 278 public function setContext($context) … … 197 284 198 285 /** 199 * Set the type of application executing the code. This is usually used to 200 * represent if you are running plain PHP code "php", via a framework, 201 * eg "laravel", or executing through delayed worker code, eg "resque". 202 * 203 * @param String $type the current type 286 * Set the type of application executing the code. 287 * 288 * This is usually used to represent if you are running plain PHP code 289 * "php", via a framework, eg "laravel", or executing through delayed 290 * worker code, eg "resque". 291 * 292 * @param string $type the current type 293 * 294 * @return $this 204 295 */ 205 296 public function setType($type) … … 211 302 212 303 /** 213 * Set custom metadata to send to Bugsnag with every error. You can use 214 * this to add custom tabs of data to each error on your Bugsnag dashboard 215 * 216 * @param Array $metaData an array of arrays of custom data. Eg: 304 * Set custom metadata to send to Bugsnag with every error. 305 * 306 * You can use this to add custom tabs of data to each error on your 307 * Bugsnag dashboard. 308 * 309 * @param array $metaData an array of arrays of custom data. Eg: 217 310 * array( 218 * "user"=> array(219 * "name" => "James",220 * "email" => "[email protected]"311 * 'user' => array( 312 * 'name' => 'James', 313 * 'email' => '[email protected]' 221 314 * ) 222 315 * ) 223 */ 224 public function setMetaData(array $metaData) 225 { 226 $this->config->metaData = $metaData; 227 228 return $this; 229 } 230 231 /** 232 * Set proxy configuration 233 * 234 * @param Array $proxySettings an array with proxy settings. Eg: 316 * @param bool $merge optionally merge the meta data 317 * 318 * @return $this 319 */ 320 public function setMetaData(array $metaData, $merge = false) 321 { 322 if ($merge) { 323 $this->config->metaData = array_merge_recursive((array) $this->config->metaData, $metaData); 324 } else { 325 $this->config->metaData = $metaData; 326 } 327 328 return $this; 329 } 330 331 /** 332 * Set proxy configuration. 333 * 334 * @param array $proxySettings an array with proxy settings. Eg: 235 335 * array( 236 * 'host' => "bugsnag.com",336 * 'host' => 'bugsnag.com', 237 337 * 'port' => 42, 238 * 'user' => "username" 239 * 'password' => "password123" 240 * ) 338 * 'user' => 'username' 339 * 'password' => 'password123' 340 * ) 341 * 342 * @return $this 241 343 */ 242 344 public function setProxySettings(array $proxySettings) … … 248 350 249 351 /** 352 * Set custom curl options. 353 * 354 * @param array $curlOptions an array with curl options. Eg: 355 * array( 356 * CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4 357 * ) 358 * 359 * @return $this 360 */ 361 public function setCurlOptions(array $curlOptions) 362 { 363 $this->config->curlOptions = $curlOptions; 364 365 return $this; 366 } 367 368 /** 250 369 * Set a custom function to call before notifying Bugsnag of an error. 370 * 251 371 * You can use this to call your own error handling functions, or to add 252 372 * custom tabs of data to each error on your Bugsnag dashboard. … … 255 375 * function before_bugsnag_notify($error) { 256 376 * $error->addMetaData(array( 257 * "user"=> array(258 * "name" => "James"377 * 'user' => array( 378 * 'name' => 'James' 259 379 * ) 260 380 * )); 261 381 * } 262 * $bugsnag->setBeforeNotifyFunction("before_bugsnag_notify"); 263 * 264 */ 382 * $bugsnag->setBeforeNotifyFunction('before_bugsnag_notify'); 383 * 384 * @param callable $beforeNotifyFunction 385 * 386 * @return $this 387 */ 265 388 public function setBeforeNotifyFunction($beforeNotifyFunction) 266 389 { … … 272 395 /** 273 396 * Set Bugsnag's error reporting level. 397 * 274 398 * If this is not set, we'll use your current PHP error_reporting value 275 399 * from your ini file or error_reporting(...) calls. 276 400 * 277 * @param Integer$errorReportingLevel the error reporting level integer401 * @param int $errorReportingLevel the error reporting level integer 278 402 * exactly as you would pass to PHP's error_reporting 403 * 404 * @return $this 279 405 */ 280 406 public function setErrorReportingLevel($errorReportingLevel) … … 286 412 287 413 /** 288 * Sets whether Bugsnag should be automatically notified of unhandled 289 * exceptions and errors. 290 * 291 * @param Boolean $autoNotify whether to auto notify or not 414 * Sets whether Bugsnag should be automatically notified of unhandled exceptions and errors. 415 * 416 * @param bool $autoNotify whether to auto notify or not 417 * 418 * @return $this 292 419 */ 293 420 public function setAutoNotify($autoNotify) … … 299 426 300 427 /** 301 * Sets whether errors should be batched together and send at the end of 302 * each request. 303 * 304 * @param Boolean $batchSending whether to batch together errors 428 * Sets whether errors should be batched together and send at the end of each request. 429 * 430 * @param bool $batchSending whether to batch together errors 431 * 432 * @return $this 305 433 */ 306 434 public function setBatchSending($batchSending) … … 312 440 313 441 /** 314 * Sets the notifier to report as to Bugsnag. This should only be 315 * set by other notifier libraries. 316 * 317 * @param Array $notifier an array of name, version, url. 442 * Sets the notifier to report as to Bugsnag. 443 * 444 * This should only be set by other notifier libraries. 445 * 446 * @param array $notifier an array of name, version, url. 447 * 448 * @return $this 318 449 */ 319 450 public function setNotifier($notifier) … … 325 456 326 457 /** 327 * Notify Bugsnag of a non-fatal/handled exception 328 * 329 * @param Exception $exception the exception to notify Bugsnag about 330 * @param Array $metaData optional metaData to send with this error 331 * @param String $severity optional severity of this error (fatal/error/warning/info) 332 */ 333 public function notifyException(Exception $exception, array $metaData=null, $severity=null) 334 { 335 $error = Bugsnag_Error::fromPHPException($this->config, $this->diagnostics, $exception); 336 $error->setSeverity($severity); 337 338 $this->notify($error, $metaData); 339 } 340 341 /** 342 * Notify Bugsnag of a non-fatal/handled error 343 * 344 * @param String $errorName the name of the error, a short (1 word) string 345 * @param String $errorMessage the error message 346 * @param Array $metaData optional metaData to send with this error 347 * @param String $severity optional severity of this error (fatal/error/warning/info) 348 */ 349 public function notifyError($name, $message, array $metaData=null, $severity=null) 458 * Sets whether Bugsnag should send $_ENV with each error. 459 * 460 * @param bool $sendEnvironment whether to send the environment 461 * 462 * @return $this 463 */ 464 public function setSendEnvironment($sendEnvironment) 465 { 466 $this->config->sendEnvironment = $sendEnvironment; 467 468 return $this; 469 } 470 471 /** 472 * Sets whether Bugsnag should send $_COOKIE with each error. 473 * 474 * @param bool $sendCookies whether to send the environment 475 * 476 * @return $this 477 */ 478 public function setSendCookies($sendCookies) 479 { 480 $this->config->sendCookies = $sendCookies; 481 482 return $this; 483 } 484 485 /** 486 * Sets whether Bugsnag should send $_SESSION with each error. 487 * 488 * @param bool $sendSession whether to send the environment 489 * 490 * @return $this 491 */ 492 public function setSendSession($sendSession) 493 { 494 $this->config->sendSession = $sendSession; 495 496 return $this; 497 } 498 499 /** 500 * Should we send a small snippet of the code that crashed. 501 * 502 * This can help you diagnose even faster from within your dashboard. 503 * 504 * @param bool $sendCode whether to send code to Bugsnag 505 * 506 * @return $this 507 */ 508 public function setSendCode($sendCode) 509 { 510 $this->config->sendCode = $sendCode; 511 512 return $this; 513 } 514 515 /** 516 * Notify Bugsnag of a non-fatal/handled throwable. 517 * 518 * @param Throwable $throwable the throwable to notify Bugsnag about 519 * @param array $metaData optional metaData to send with this error 520 * @param string $severity optional severity of this error (fatal/error/warning/info) 521 * 522 * @return void 523 */ 524 public function notifyException($throwable, array $metaData = null, $severity = null) 525 { 526 if (is_subclass_of($throwable, 'Throwable') || is_subclass_of($throwable, 'Exception') || get_class($throwable) == 'Exception') { 527 $error = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $throwable); 528 $error->setSeverity($severity); 529 530 $this->notify($error, $metaData); 531 } 532 } 533 534 /** 535 * Notify Bugsnag of a non-fatal/handled error. 536 * 537 * @param string $name the name of the error, a short (1 word) string 538 * @param string $message the error message 539 * @param array $metaData optional metaData to send with this error 540 * @param string $severity optional severity of this error (fatal/error/warning/info) 541 * 542 * @return void 543 */ 544 public function notifyError($name, $message, array $metaData = null, $severity = null) 350 545 { 351 546 $error = Bugsnag_Error::fromNamedError($this->config, $this->diagnostics, $name, $message); … … 355 550 } 356 551 357 // Exception handler callback, should only be called internally by PHP's set_exception_handler 358 public function exceptionHandler($exception) 359 { 360 $error = Bugsnag_Error::fromPHPException($this->config, $this->diagnostics, $exception); 361 $error->setSeverity("fatal"); 362 363 if (!$error->shouldIgnore() && $this->config->autoNotify) { 364 $this->notify($error); 365 } 366 } 367 368 // Exception handler callback, should only be called internally by PHP's set_error_handler 369 public function errorHandler($errno, $errstr, $errfile='', $errline=0) 370 { 552 /** 553 * Exception handler callback. 554 * 555 * Should only be called internally by PHP's set_exception_handler. 556 * 557 * @param Throwable $throwable the exception was was thrown 558 * 559 * @return void 560 */ 561 public function exceptionHandler($throwable) 562 { 563 if (!$this->config->autoNotify) { 564 return; 565 } 566 567 $error = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $throwable); 568 $error->setSeverity('error'); 569 $this->notify($error); 570 } 571 572 /** 573 * Error handler callback. 574 * 575 * Should only be called internally by PHP's set_error_handler. 576 * 577 * @param int $errno the level of the error raised 578 * @param string $errstr the error message 579 * @param string $errfile the filename that the error was raised in 580 * @param int $errline the line number the error was raised at 581 * 582 * @return void 583 */ 584 public function errorHandler($errno, $errstr, $errfile = '', $errline = 0) 585 { 586 if (!$this->config->autoNotify || $this->config->shouldIgnoreErrorCode($errno)) { 587 return; 588 } 589 371 590 $error = Bugsnag_Error::fromPHPError($this->config, $this->diagnostics, $errno, $errstr, $errfile, $errline); 372 373 if (!$error->shouldIgnore() && $this->config->autoNotify) { 374 $this->notify($error); 375 } 376 } 377 378 // Shutdown handler callback, called when the PHP process has finished running 379 // Should only be called internally by PHP's register_shutdown_function 591 $this->notify($error); 592 } 593 594 /** 595 * Shutdown handler callback. 596 * 597 * Called when the PHP process has finished running. Should only be called 598 * internally by PHP's register_shutdown_function. 599 * 600 * @return void 601 */ 380 602 public function shutdownHandler() 381 603 { … … 384 606 385 607 // Check if a fatal error caused this shutdown 386 if (!is_null($lastError) && Bugsnag_ErrorTypes::isFatal($lastError['type']) ) {608 if (!is_null($lastError) && Bugsnag_ErrorTypes::isFatal($lastError['type']) && $this->config->autoNotify && !$this->config->shouldIgnoreErrorCode($lastError['type'])) { 387 609 $error = Bugsnag_Error::fromPHPError($this->config, $this->diagnostics, $lastError['type'], $lastError['message'], $lastError['file'], $lastError['line'], true); 388 $error->setSeverity("fatal"); 389 390 if (!$error->shouldIgnore() && $this->config->autoNotify) { 391 $this->notify($error); 392 } 610 $error->setSeverity('error'); 611 $this->notify($error); 393 612 } 394 613 … … 400 619 } 401 620 402 // Batches up errors into notifications for later sending 403 public function notify($error, $metaData=array()) 621 /** 622 * Batches up errors into notifications for later sending. 623 * 624 * @param Bugsnag_Error $error the error to batch up 625 * @param array $metaData optional meta data to send with the error 626 * 627 * @return void 628 */ 629 public function notify(Bugsnag_Error $error, $metaData = array()) 404 630 { 405 631 // Queue or send the error … … 413 639 $this->notification->addError($error, $metaData); 414 640 } else { 415 // Create and deliver notification immediatel t641 // Create and deliver notification immediately 416 642 $notif = new Bugsnag_Notification($this->config); 417 643 $notif->addError($error, $metaData); … … 420 646 } 421 647 422 // Should we send errors immediately or on shutdown 648 /** 649 * Should we send errors immediately, or on shutdown? 650 * 651 * @return bool 652 */ 423 653 private function sendErrorsOnShutdown() 424 654 { -
bugsnag/trunk/bugsnag-php/Configuration.php
r871602 r1542350 3 3 class Bugsnag_Configuration 4 4 { 5 public static $DEFAULT_TIMEOUT = 10; 6 public static $DEFAULT_ENDPOINT = 'https://notify.bugsnag.com'; 7 public static $DEFAULT_NON_SSL_ENDPOINT = 'http://notify.bugsnag.com'; 8 5 9 public $apiKey; 6 10 public $autoNotify = true; 7 11 public $batchSending = true; 8 12 public $useSSL = true; 9 public $endpoint = 'notify.bugsnag.com'; 10 public $timeout = 2; 13 public $endpoint; 11 14 public $notifyReleaseStages; 12 15 public $filters = array('password'); … … 15 18 public $proxySettings = array(); 16 19 public $notifier = array( 17 'name' => 'Bugsnag PHP (Official)',18 'version' => '2. 2.0',19 'url' => 'https://bugsnag.com'20 'name' => 'Bugsnag PHP (Official)', 21 'version' => '2.9.2', 22 'url' => 'https://bugsnag.com', 20 23 ); 24 public $sendEnvironment = false; 25 public $sendCookies = true; 26 public $sendSession = true; 27 public $sendCode = true; 28 public $stripPath; 29 public $stripPathRegex; 21 30 22 31 public $context; … … 31 40 public $errorReportingLevel; 32 41 42 public $curlOptions = array(); 43 44 public $debug = false; 45 46 /** 47 * Create a new config instance. 48 * 49 * @return void 50 */ 51 public function __construct() 52 { 53 $this->timeout = self::$DEFAULT_TIMEOUT; 54 } 55 56 /** 57 * Get the notify endpoint. 58 * 59 * @return string 60 */ 33 61 public function getNotifyEndpoint() 34 62 { 35 return $this->getProtocol()."://".$this->endpoint; 63 if (is_null($this->endpoint)) { 64 return $this->useSSL ? self::$DEFAULT_ENDPOINT : self::$DEFAULT_NON_SSL_ENDPOINT; 65 } elseif (preg_match('/^(http:\/\/|https:\/\/)/', $this->endpoint)) { 66 return $this->endpoint; 67 } else { 68 return ($this->useSSL ? 'https' : 'http').'://'.$this->endpoint; 69 } 36 70 } 37 71 72 /** 73 * Should we notify? 74 * 75 * @return bool 76 */ 38 77 public function shouldNotify() 39 78 { … … 41 80 } 42 81 82 /** 83 * Should we ignore the given error code? 84 * 85 * @param int $code the error code 86 * 87 * @return bool 88 */ 89 public function shouldIgnoreErrorCode($code) 90 { 91 if (isset($this->errorReportingLevel)) { 92 return !($this->errorReportingLevel & $code); 93 } else { 94 return !(error_reporting() & $code); 95 } 96 } 97 98 /** 99 * Set the project root. 100 * 101 * @param string $projectRoot the project root path 102 * 103 * @return void 104 */ 43 105 public function setProjectRoot($projectRoot) 44 106 { 45 107 $this->projectRoot = $projectRoot; 46 $this->projectRootRegex = '/'.preg_quote($projectRoot, '/')."[\\/]?/i"; 108 $this->projectRootRegex = '/'.preg_quote($projectRoot, '/').'[\\/]?/i'; 109 if (is_null($this->stripPath)) { 110 $this->setStripPath($projectRoot); 111 } 47 112 } 48 113 49 public function get($prop, $default=NULL) 114 /** 115 * Set the strip path. 116 * 117 * @param string $stripPath the absolute strip path 118 * 119 * @return void 120 */ 121 public function setStripPath($stripPath) 122 { 123 $this->stripPath = $stripPath; 124 $this->stripPathRegex = '/'.preg_quote($stripPath, '/').'[\\/]?/i'; 125 } 126 127 /** 128 * Get the given configuration. 129 * 130 * @param string $prop the property to get 131 * @param mixed $default the value to fallback to 132 * 133 * @return mixed 134 */ 135 public function get($prop, $default = null) 50 136 { 51 137 $configured = $this->$prop; … … 57 143 } 58 144 } 59 60 private function getProtocol()61 {62 return $this->useSSL ? "https" : "http";63 }64 145 } -
bugsnag/trunk/bugsnag-php/Diagnostics.php
r871602 r1542350 3 3 class Bugsnag_Diagnostics 4 4 { 5 /** 6 * The config instance. 7 * 8 * @var Bugsnag_Configuration 9 */ 5 10 private $config; 6 11 12 /** 13 * Create a new diagnostics instance. 14 * 15 * @param Bugsnag_Configuration $config the configuration instance 16 * 17 * @return void 18 */ 7 19 public function __construct(Bugsnag_Configuration $config) 8 20 { … … 10 22 } 11 23 24 /** 25 * Get the application information. 26 * 27 * @return array 28 */ 12 29 public function getAppData() 13 30 { … … 29 46 } 30 47 48 /** 49 * Get the device information. 50 * 51 * @return array 52 */ 31 53 public function getDeviceData() 32 54 { 33 55 return array( 34 'hostname' => $this->config->get('hostname', php_uname('n')) 56 'hostname' => $this->config->get('hostname', php_uname('n')), 35 57 ); 36 58 } 37 59 60 /** 61 * Get the error context. 62 * 63 * @return array 64 */ 38 65 public function getContext() 39 66 { … … 41 68 } 42 69 70 /** 71 * Get the current user. 72 * 73 * @return array 74 */ 43 75 public function getUser() 44 76 { -
bugsnag/trunk/bugsnag-php/Error.php
r871602 r1542350 4 4 { 5 5 private static $VALID_SEVERITIES = array( 6 'fatal',7 6 'error', 8 7 'warning', 9 'info' 8 'info', 10 9 ); 11 10 12 11 public $name; 12 public $payloadVersion = '2'; 13 13 public $message; 14 public $severity = "error"; 14 public $severity = 'warning'; 15 /** @var Bugsnag_Stacktrace */ 15 16 public $stacktrace; 16 17 public $metaData = array(); 18 public $user; 17 19 public $config; 18 20 public $diagnostics; 19 public $code;21 /** @var Bugsnag_Error|null */ 20 22 public $previous; 21 22 // Static error creation methods, to ensure that Error object is always complete 23 public static function fromPHPError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $code, $message, $file, $line, $fatal=false) 24 { 25 $error = new Bugsnag_Error($config, $diagnostics); 23 public $groupingHash; 24 25 /** 26 * Create a new error from a PHP error. 27 * 28 * @param Bugsnag_Configuration $config the config instance 29 * @param Bugsnag_Diagnostics $diagnostics the diagnostics instance 30 * @param int $code the error code 31 * @param string $message the error message 32 * @param string $file the error file 33 * @param int $line the error line 34 * @param bool $fatal if the error was fatal 35 * 36 * @return self 37 */ 38 public static function fromPHPError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $code, $message, $file, $line, $fatal = false) 39 { 40 $error = new self($config, $diagnostics); 26 41 $error->setPHPError($code, $message, $file, $line, $fatal); 27 42 … … 29 44 } 30 45 31 public static function fromPHPException(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, Exception $exception) 32 { 33 $error = new Bugsnag_Error($config, $diagnostics); 34 $error->setPHPException($exception); 46 /** 47 * Create a new error from a PHP throwable. 48 * 49 * @param Bugsnag_Configuration $config the config instance 50 * @param Bugsnag_Diagnostics $diagnostics the diagnostics instance 51 * @param Throwable $throwable te he throwable instance 52 * 53 * @return self 54 */ 55 public static function fromPHPThrowable(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $throwable) 56 { 57 $error = new self($config, $diagnostics); 58 $error->setPHPThrowable($throwable); 35 59 36 60 return $error; 37 61 } 38 62 39 public static function fromNamedError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $name, $message=NULL) 40 { 41 $error = new Bugsnag_Error($config, $diagnostics); 63 /** 64 * Create a new error from a named error. 65 * 66 * @param Bugsnag_Configuration $config the config instance 67 * @param Bugsnag_Diagnostics $diagnostics the diagnostics instance 68 * @param string $name the error name 69 * @param string|null $message the error message 70 * 71 * @return self 72 */ 73 public static function fromNamedError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $name, $message = null) 74 { 75 $error = new self($config, $diagnostics); 42 76 $error->setName($name) 43 77 ->setMessage($message) … … 47 81 } 48 82 49 // Private constructor (for use only by the static methods above) 83 /** 84 * Create a new error instance. 85 * 86 * This is only for for use only by the static methods above. 87 * 88 * @param Bugsnag_Configuration $config the config instance 89 * @param Bugsnag_Diagnostics $diagnostics the diagnostics instance 90 * 91 * @return void 92 */ 50 93 private function __construct(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics) 51 94 { … … 54 97 } 55 98 99 /** 100 * Set the error name. 101 * 102 * @param string $name the error name 103 * 104 * @throws InvalidArgumentException 105 * 106 * @return $this 107 */ 56 108 public function setName($name) 57 109 { 58 $this->name = $name; 59 60 return $this; 61 } 62 110 if (is_scalar($name) || method_exists($name, '__toString')) { 111 $this->name = (string) $name; 112 } else { 113 throw new InvalidArgumentException('Name must be a string.'); 114 } 115 116 return $this; 117 } 118 119 /** 120 * Set the error message. 121 * 122 * @param string|null $message the error message 123 * 124 * @throws InvalidArgumentException 125 * 126 * @return $this 127 */ 63 128 public function setMessage($message) 64 129 { 65 $this->message = $message; 66 67 return $this; 68 } 69 70 public function setStacktrace($stacktrace) 130 if ($message === null) { 131 $this->message = null; 132 } elseif (is_scalar($message) || method_exists($message, '__toString')) { 133 $this->message = (string) $message; 134 } else { 135 throw new InvalidArgumentException('Message must be a string.'); 136 } 137 138 return $this; 139 } 140 141 /** 142 * Set the grouping hash. 143 * 144 * @param string $groupingHash the grouping hash 145 * 146 * @return $this 147 */ 148 public function setGroupingHash($groupingHash) 149 { 150 $this->groupingHash = $groupingHash; 151 152 return $this; 153 } 154 155 /** 156 * Set the bugsnag stacktrace. 157 * 158 * @param Bugsnag_Stacktrace $stacktrace the stacktrace instance 159 * 160 * @return $this 161 */ 162 public function setStacktrace(Bugsnag_Stacktrace $stacktrace) 71 163 { 72 164 $this->stacktrace = $stacktrace; … … 75 167 } 76 168 77 public function setCode($code)78 {79 $this->code = $code;80 81 return $this;82 }83 169 /** 170 * Set the error severity. 171 * 172 * @param int|null $severity the error severity 173 * 174 * @return $this 175 */ 84 176 public function setSeverity($severity) 85 177 { 86 178 if (!is_null($severity)) { 87 if (in_array($severity, Bugsnag_Error::$VALID_SEVERITIES)) {179 if (in_array($severity, self::$VALID_SEVERITIES)) { 88 180 $this->severity = $severity; 89 181 } else { 90 error_log('Bugsnag Warning: Tried to set error severity to '. $severity.' which is not allowed.');182 error_log('Bugsnag Warning: Tried to set error severity to '.$severity.' which is not allowed.'); 91 183 } 92 184 } … … 95 187 } 96 188 97 public function setPHPException(Exception $exception) 98 { 189 /** 190 * Set the PHP exception. 191 * 192 * @param Throwable $exception the throwable instance 193 * 194 * @return $this 195 * 196 * @deprecated since version 2.9. Use setPHPThrowable instead. 197 */ 198 public function setPHPException($exception) 199 { 200 return $this->setPHPThrowable($exception); 201 } 202 203 /** 204 * Set the PHP throwable. 205 * 206 * @param Throwable $exception the throwable instance 207 * 208 * @return $this 209 */ 210 public function setPHPThrowable($exception) 211 { 212 if (version_compare(PHP_VERSION, '7.0.0', '>=')) { 213 if (!$exception instanceof Throwable) { 214 error_log('Bugsnag Warning: The exception must implement Throwable.'); 215 216 return $this; 217 } 218 } else { 219 if (!$exception instanceof Exception) { 220 error_log('Bugsnag Warning: The exception must be an Exception.'); 221 222 return $this; 223 } 224 } 225 99 226 $this->setName(get_class($exception)) 100 227 ->setMessage($exception->getMessage()) … … 108 235 } 109 236 110 public function setPHPError($code, $message, $file, $line, $fatal=false) 237 /** 238 * Set the PHP error. 239 * 240 * @param int $code the error code 241 * @param string $message the error message 242 * @param string $file the error file 243 * @param int $line the error line 244 * @param bool $fatal if the error was fatal 245 * 246 * @return $this 247 */ 248 public function setPHPError($code, $message, $file, $line, $fatal = false) 111 249 { 112 250 if ($fatal) { … … 125 263 ->setMessage($message) 126 264 ->setSeverity(Bugsnag_ErrorTypes::getSeverity($code)) 127 ->setStacktrace($stacktrace) 128 ->setCode($code); 129 130 return $this; 131 } 132 265 ->setStacktrace($stacktrace); 266 267 return $this; 268 } 269 270 /** 271 * Set the error meta data. 272 * 273 * @param array $metaData the error meta data 274 * 275 * @return $this 276 */ 133 277 public function setMetaData($metaData) 134 278 { … … 140 284 } 141 285 286 /** 287 * Set the current user. 288 * 289 * @param array|null $user the current user 290 * 291 * @return $this 292 */ 293 public function setUser($user) 294 { 295 $this->user = $user; 296 297 return $this; 298 } 299 300 /** 301 * Set the previous throwable. 302 * 303 * @param Throwable $exception the previous throwable 304 * 305 * @return $this 306 */ 142 307 public function setPrevious($exception) 143 308 { 144 309 if ($exception) { 145 $this->previous = Bugsnag_Error::fromPHPException($this->config, $this->diagnostics, $exception); 146 } 147 148 return $this; 149 } 150 151 public function shouldIgnore() 152 { 153 // Check if we should ignore errors of this type 154 if (isset($this->code)) { 155 if (isset($this->config->errorReportingLevel)) { 156 return !($this->config->errorReportingLevel & $this->code); 157 } else { 158 return !(error_reporting() & $this->code); 159 } 160 } 161 162 return false; 163 } 164 310 $this->previous = self::fromPHPThrowable($this->config, $this->diagnostics, $exception); 311 } 312 313 return $this; 314 } 315 316 /** 317 * Get the array representation. 318 * 319 * @return array 320 */ 165 321 public function toArray() 166 322 { 167 returnarray(323 $errorArray = array( 168 324 'app' => $this->diagnostics->getAppData(), 169 325 'device' => $this->diagnostics->getDeviceData(), 170 'user' => $this->diagnostics->getUser(),326 'user' => is_null($this->user) ? $this->diagnostics->getUser() : $this->user, 171 327 'context' => $this->diagnostics->getContext(), 328 'payloadVersion' => $this->payloadVersion, 172 329 'severity' => $this->severity, 173 330 'exceptions' => $this->exceptionArray(), 174 'metaData' => $this-> applyFilters($this->metaData)331 'metaData' => $this->cleanupObj($this->metaData, true), 175 332 ); 176 } 177 333 334 if (isset($this->groupingHash)) { 335 $errorArray['groupingHash'] = $this->groupingHash; 336 } 337 338 return $errorArray; 339 } 340 341 /** 342 * Get the exception array. 343 * 344 * @return array 345 */ 178 346 public function exceptionArray() 179 347 { … … 187 355 'errorClass' => $this->name, 188 356 'message' => $this->message, 189 'stacktrace' => $this->stacktrace->toArray() 357 'stacktrace' => $this->stacktrace->toArray(), 190 358 ); 191 359 192 return $exceptionArray; 193 } 194 195 private function applyFilters($metaData) 196 { 197 if (!empty($this->config->filters)) { 198 $cleanMetaData = array(); 199 200 foreach ($metaData as $key => $value) { 360 return $this->cleanupObj($exceptionArray, false); 361 } 362 363 /** 364 * Cleanup the given object. 365 * 366 * @param mixed $obj the data to cleanup 367 * @param bool $isMetaData if it is meta data 368 * 369 * @return array|null 370 */ 371 private function cleanupObj($obj, $isMetaData) 372 { 373 if (is_null($obj)) { 374 return; 375 } 376 377 if (is_array($obj)) { 378 $cleanArray = array(); 379 foreach ($obj as $key => $value) { 380 // Check if this key should be filtered 201 381 $shouldFilter = false; 202 foreach ($this->config->filters as $filter) { 203 if (strpos($key, $filter) !== false) { 204 $shouldFilter = true; 205 break; 382 383 // Apply filters to metadata if required 384 if ($isMetaData && is_array($this->config->filters)) { 385 foreach ($this->config->filters as $filter) { 386 if (strpos($key, $filter) !== false) { 387 $shouldFilter = true; 388 break; 389 } 206 390 } 207 391 } 208 392 // Apply filter 209 393 if ($shouldFilter) { 210 $clean MetaData[$key] = '[FILTERED]';394 $cleanArray[$key] = '[FILTERED]'; 211 395 } else { 212 if (is_array($value)) { 213 $cleanMetaData[$key] = $this->applyFilters($value); 214 } else { 215 $cleanMetaData[$key] = $value; 216 } 396 $cleanArray[$key] = $this->cleanupObj($value, $isMetaData); 217 397 } 218 398 } 219 399 220 return $cleanMetaData; 221 } else { 222 return $metaData; 400 return $cleanArray; 401 } elseif (is_string($obj)) { 402 // UTF8-encode if not already encoded 403 if (function_exists('mb_detect_encoding') && !mb_detect_encoding($obj, 'UTF-8', true)) { 404 return utf8_encode($obj); 405 } else { 406 return $obj; 407 } 408 } elseif (is_object($obj)) { 409 // json_encode -> json_decode trick turns an object into an array 410 return $this->cleanupObj(json_decode(json_encode($obj), true), $isMetaData); 411 } else { 412 return $obj; 223 413 } 224 414 } -
bugsnag/trunk/bugsnag-php/ErrorTypes.php
r871602 r1542350 6 6 E_ERROR => array( 7 7 'name' => 'PHP Fatal Error', 8 'severity' => ' fatal'8 'severity' => 'error', 9 9 ), 10 10 11 11 E_WARNING => array( 12 12 'name' => 'PHP Warning', 13 'severity' => 'warning' 13 'severity' => 'warning', 14 14 ), 15 15 16 16 E_PARSE => array( 17 17 'name' => 'PHP Parse Error', 18 'severity' => ' fatal'18 'severity' => 'error', 19 19 ), 20 20 21 21 E_NOTICE => array( 22 22 'name' => 'PHP Notice', 23 'severity' => 'info' 23 'severity' => 'info', 24 24 ), 25 25 26 26 E_CORE_ERROR => array( 27 27 'name' => 'PHP Core Error', 28 'severity' => ' fatal'28 'severity' => 'error', 29 29 ), 30 30 31 31 E_CORE_WARNING => array( 32 32 'name' => 'PHP Core Warning', 33 'severity' => 'warning' 33 'severity' => 'warning', 34 34 ), 35 35 36 36 E_COMPILE_ERROR => array( 37 37 'name' => 'PHP Compile Error', 38 'severity' => ' fatal'38 'severity' => 'error', 39 39 ), 40 40 41 41 E_COMPILE_WARNING => array( 42 42 'name' => 'PHP Compile Warning', 43 'severity' => 'warning' 43 'severity' => 'warning', 44 44 ), 45 45 46 46 E_USER_ERROR => array( 47 47 'name' => 'User Error', 48 'severity' => 'error' 48 'severity' => 'error', 49 49 ), 50 50 51 51 E_USER_WARNING => array( 52 52 'name' => 'User Warning', 53 'severity' => 'warning' 53 'severity' => 'warning', 54 54 ), 55 55 56 56 E_USER_NOTICE => array( 57 57 'name' => 'User Notice', 58 'severity' => 'info' 58 'severity' => 'info', 59 59 ), 60 60 61 61 E_STRICT => array( 62 62 'name' => 'PHP Strict', 63 'severity' => 'info' 63 'severity' => 'info', 64 64 ), 65 65 66 66 E_RECOVERABLE_ERROR => array( 67 67 'name' => 'PHP Recoverable Error', 68 'severity' => 'error' 68 'severity' => 'error', 69 69 ), 70 70 … … 72 72 8192 => array( 73 73 'name' => 'PHP Deprecated', 74 'severity' => 'info' 74 'severity' => 'info', 75 75 ), 76 76 … … 78 78 16384 => array( 79 79 'name' => 'User Deprecated', 80 'severity' => 'info' 81 ) 80 'severity' => 'info', 81 ), 82 82 ); 83 83 84 /** 85 * Is the given error code fatal? 86 * 87 * @param int $code the error code 88 * 89 * @return bool 90 */ 84 91 public static function isFatal($code) 85 92 { 86 return self::getSeverity($code) == ' fatal';93 return self::getSeverity($code) == 'error'; 87 94 } 88 95 96 /** 97 * Get the name of the given error code. 98 * 99 * @param int $code the error code 100 * 101 * @return string 102 */ 89 103 public static function getName($code) 90 104 { … … 92 106 return self::$ERROR_TYPES[$code]['name']; 93 107 } else { 94 return "Unknown";108 return 'Unknown'; 95 109 } 96 110 } 97 111 112 /** 113 * Get the severity of the given error code. 114 * 115 * @param int $code the error code 116 * 117 * @return string 118 */ 98 119 public static function getSeverity($code) 99 120 { … … 101 122 return self::$ERROR_TYPES[$code]['severity']; 102 123 } else { 103 return "error";124 return 'error'; 104 125 } 105 126 } 106 127 128 /** 129 * Get the the levels for the given severity. 130 * 131 * @param string $severity the given severity 132 * 133 * @return int 134 */ 107 135 public static function getLevelsForSeverity($severity) 108 136 { 109 137 $levels = 0; 110 foreach ( Bugsnag_ErrorTypes::$ERROR_TYPES as $level => $info) {138 foreach (self::$ERROR_TYPES as $level => $info) { 111 139 if ($info['severity'] == $severity) { 112 140 $levels |= $level; -
bugsnag/trunk/bugsnag-php/Notification.php
r871602 r1542350 3 3 class Bugsnag_Notification 4 4 { 5 private static $CONTENT_TYPE_HEADER = 'Content-type: application/json'; 6 7 /** 8 * The config instance. 9 * 10 * @var Bugsnag_Configuration 11 */ 5 12 private $config; 13 14 /** 15 * The queue of errors to send to Bugsnag. 16 * 17 * @var Bugsnag_Error[] 18 */ 6 19 private $errorQueue = array(); 7 20 21 /** 22 * Create a new notification instance. 23 * 24 * @param Bugsnag_Configuration $config the configuration instance 25 * 26 * @return void 27 */ 8 28 public function __construct(Bugsnag_Configuration $config) 9 29 { … … 11 31 } 12 32 13 public function addError($error, $passedMetaData=array()) 33 /** 34 * Add an error to the queue. 35 * 36 * @param Bugsnag_Error $config the bugsnag error instance 37 * @param array $passedMetaData the associated meta data 38 * 39 * @return bool 40 */ 41 public function addError(Bugsnag_Error $error, $passedMetaData = array()) 14 42 { 15 43 // Check if this error should be sent to Bugsnag 16 44 if (!$this->config->shouldNotify()) { 17 return FALSE;45 return false; 18 46 } 19 47 … … 26 54 } 27 55 56 // Session Tab 57 if ($this->config->sendSession && !empty($_SESSION)) { 58 $error->setMetaData(array('session' => $_SESSION)); 59 } 60 61 // Cookies Tab 62 if ($this->config->sendCookies && !empty($_COOKIE)) { 63 $error->setMetaData(array('cookies' => $_COOKIE)); 64 } 65 28 66 // Add environment meta-data to error 29 if ( !empty($_ENV)) {30 $error->setMetaData(array( "Environment"=> $_ENV));67 if ($this->config->sendEnvironment && !empty($_ENV)) { 68 $error->setMetaData(array('Environment' => $_ENV)); 31 69 } 32 70 … … 40 78 41 79 // Skip this error if the beforeNotify function returned FALSE 42 if (!isset($beforeNotifyReturn) || $beforeNotifyReturn !== FALSE) {80 if (!isset($beforeNotifyReturn) || $beforeNotifyReturn !== false) { 43 81 $this->errorQueue[] = $error; 44 82 45 return TRUE;83 return true; 46 84 } else { 47 return FALSE; 48 } 49 } 50 85 return false; 86 } 87 } 88 89 /** 90 * Get the array representation. 91 * 92 * @return array 93 */ 51 94 public function toArray() 52 95 { … … 63 106 'apiKey' => $this->config->apiKey, 64 107 'notifier' => $this->config->notifier, 65 'events' => $events 108 'events' => $events, 66 109 ); 67 110 } 68 111 112 /** 113 * Deliver everything on the queue to Bugsnag. 114 * 115 * @return void 116 */ 69 117 public function deliver() 70 118 { 71 if (!empty($this->errorQueue)) { 72 // Post the request to bugsnag 73 $this->postJSON($this->config->getNotifyEndpoint(), $this->toArray()); 74 75 // Clear the error queue 76 $this->errorQueue = array(); 77 } 78 } 79 119 if (empty($this->errorQueue)) { 120 return; 121 } 122 123 // Post the request to bugsnag 124 $this->postJSON($this->config->getNotifyEndpoint(), $this->toArray()); 125 126 // Clear the error queue 127 $this->errorQueue = array(); 128 } 129 130 /** 131 * Post the given data to Bugsnag in json form. 132 * 133 * @param string $url the url to hit 134 * @param array $data the data send 135 * 136 * @return void 137 */ 80 138 public function postJSON($url, $data) 139 { 140 // Try to send the whole lot, or without the meta data for the first 141 // event. If failed, try to send the first event, and then the rest of 142 // them, revursively. Decrease by a constant and concquer if you like. 143 // Note that the base case is satisfied as soon as the payload is small 144 // enought to send, or when it's simply discarded. 145 try { 146 $body = $this->encode($data); 147 } catch (RuntimeException $e) { 148 if (count($data['events']) > 1) { 149 $event = array_shift($data['events']); 150 $this->postJSON($url, array_merge($data, array('events' => array($event)))); 151 $this->postJSON($url, $data); 152 } else { 153 error_log('Bugsnag Warning: '.$e->getMessage()); 154 } 155 156 return; 157 } 158 159 // Prefer cURL if it is installed, otherwise fall back to fopen() 160 // cURL supports both timeouts and proxies 161 162 try { 163 if (function_exists('curl_version')) { 164 $this->postWithCurl($url, $body); 165 } elseif (ini_get('allow_url_fopen')) { 166 $this->postWithFopen($url, $body); 167 } else { 168 error_log('Bugsnag Warning: Couldn\'t notify (neither cURL or allow_url_fopen are available on your PHP installation)'); 169 } 170 } catch (Exception $e) { 171 error_log('Bugsnag Warning: Couldn\'t notify. '.$e->getMessage()); 172 } 173 } 174 175 /** 176 * Json encode the given data. 177 * 178 * We will also strip out the meta data if it's too large. 179 * 180 * @param array $data the data to encode 181 * 182 * @throws RuntimeException 183 * 184 * @return string 185 */ 186 private function encode(array $data) 187 { 188 $body = json_encode($data); 189 190 if ($this->length($body) > 500000) { 191 unset($data['events'][0]['metaData']); 192 } 193 194 $body = json_encode($data); 195 196 if ($this->length($body) > 500000) { 197 throw new RuntimeException('Payload too large'); 198 } 199 200 return $body; 201 } 202 203 /** 204 * Get the length of the given string in bytes. 205 * 206 * @param string $str the string to get the length of 207 * 208 * @return int 209 */ 210 private function length($str) 211 { 212 return function_exists('mb_strlen') ? mb_strlen($str, '8bit') : strlen($str); 213 } 214 215 /** 216 * Post the given info to Bugsnag using cURL. 217 * 218 * @param string $url the url to hit 219 * @param string $body the request body 220 * 221 * @return void 222 */ 223 private function postWithCurl($url, $body) 81 224 { 82 225 $http = curl_init($url); … … 86 229 curl_setopt($http, CURLOPT_RETURNTRANSFER, true); 87 230 curl_setopt($http, CURLOPT_POST, true); 88 curl_setopt($http, CURLOPT_HTTPHEADER, array( 'Content-type: application/json'));89 curl_setopt($http, CURLOPT_POSTFIELDS, json_encode($data));231 curl_setopt($http, CURLOPT_HTTPHEADER, array(self::$CONTENT_TYPE_HEADER, 'Expect:')); 232 curl_setopt($http, CURLOPT_POSTFIELDS, $body); 90 233 curl_setopt($http, CURLOPT_CONNECTTIMEOUT, $this->config->timeout); 91 234 curl_setopt($http, CURLOPT_SSL_VERIFYPEER, false); 92 235 curl_setopt($http, CURLOPT_VERBOSE, false); 93 236 if (defined('HHVM_VERSION')) { 237 curl_setopt($http, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 238 } else { 239 curl_setopt($http, CURL_IPRESOLVE_V4, true); 240 } 241 242 if (!empty($this->config->curlOptions)) { 243 foreach ($this->config->curlOptions as $option => $value) { 244 curl_setopt($http, $option, $value); 245 } 246 } 94 247 // Apply proxy settings (if present) 95 248 if (count($this->config->proxySettings)) { … … 101 254 } 102 255 if (isset($this->config->proxySettings['user'])) { 103 $userPassword = $this->config->proxySettings['user'] .':';104 $userPassword .= isset($this->config->proxySettings['password']) ? $this->config->proxySettings['password'] : '';256 $userPassword = $this->config->proxySettings['user'].':'; 257 $userPassword .= isset($this->config->proxySettings['password']) ? $this->config->proxySettings['password'] : ''; 105 258 curl_setopt($http, CURLOPT_PROXYUSERPWD, $userPassword); 106 259 } … … 113 266 if ($statusCode > 200) { 114 267 error_log('Bugsnag Warning: Couldn\'t notify ('.$responseBody.')'); 268 269 if ($this->config->debug) { 270 error_log('Bugsnag Debug: Attempted to post to URL - "'.$url.'"'); 271 error_log('Bugsnag Debug: Attempted to post payload - "'.$body.'"'); 272 } 273 } 274 275 if (curl_errno($http)) { 276 error_log('Bugsnag Warning: Couldn\'t notify ('.curl_error($http).')'); 115 277 } 116 278 117 279 curl_close($http); 118 119 return $statusCode; 280 } 281 282 /** 283 * Post the given info to Bugsnag using fopen. 284 * 285 * @param string $url the url to hit 286 * @param string $body the request body 287 * 288 * @return void 289 */ 290 private function postWithFopen($url, $body) 291 { 292 // Warn about lack of proxy support if we are using fopen() 293 if (count($this->config->proxySettings)) { 294 error_log('Bugsnag Warning: Can\'t use proxy settings unless cURL is installed'); 295 } 296 297 // Create the request context 298 $context = stream_context_create(array( 299 'http' => array( 300 'method' => 'POST', 301 'header' => self::$CONTENT_TYPE_HEADER.'\r\n', 302 'content' => $body, 303 'timeout' => $this->config->timeout, 304 ), 305 'ssl' => array( 306 'verify_peer' => false, 307 ), 308 )); 309 310 // Execute the request and fetch the response 311 if ($stream = fopen($url, 'rb', false, $context)) { 312 $response = stream_get_contents($stream); 313 314 if (!$response) { 315 error_log('Bugsnag Warning: Couldn\'t notify (no response)'); 316 } 317 } else { 318 error_log('Bugsnag Warning: Couldn\'t notify (fopen failed)'); 319 } 120 320 } 121 321 } -
bugsnag/trunk/bugsnag-php/Request.php
r825757 r1542350 3 3 class Bugsnag_Request 4 4 { 5 /** 6 * Are we currently processing a request? 7 * 8 * @return bool 9 */ 5 10 public static function isRequest() 6 11 { … … 8 13 } 9 14 15 /** 16 * Get the request formatted as meta data. 17 * 18 * @return array 19 */ 10 20 public static function getRequestMetaData() 11 21 { 22 static $requestData; 23 24 if ($requestData !== null) { 25 return $requestData; 26 } 27 12 28 $requestData = array(); 29 30 $methodsWithPayload = array('PUT'); 13 31 14 32 // Request Tab … … 22 40 $requestData['request']['params'] = $_POST; 23 41 } else { 42 $input = file_get_contents('php://input'); 43 24 44 if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'], 'application/json') === 0) { 25 $requestData['request']['params'] = json_decode(file_get_contents('php://input')); 45 $requestData['request']['params'] = json_decode($input, true); 46 } 47 48 if (isset($_SERVER['REQUEST_METHOD']) && in_array(strtoupper($_SERVER['REQUEST_METHOD']), $methodsWithPayload)) { 49 parse_str($input, $params); 50 if (isset($requestData['request']['params']) && is_array($requestData['request']['params'])) { 51 $requestData['request']['params'] = array_merge($requestData['request']['params'], $params); 52 } else { 53 $requestData['request']['params'] = $params; 54 } 26 55 } 27 56 } 28 57 29 $requestData['request'][' ip'] = self::getRequestIp();58 $requestData['request']['clientIp'] = self::getRequestIp(); 30 59 if (isset($_SERVER['HTTP_USER_AGENT'])) { 31 60 $requestData['request']['userAgent'] = $_SERVER['HTTP_USER_AGENT']; 32 61 } 33 62 34 if (function_exists("getallheaders")) { 35 $headers = getallheaders(); 36 if (!empty($headers)) { 37 $requestData['request']['headers'] = $headers; 38 } 39 } 40 41 // Session Tab 42 if (!empty($_SESSION)) { 43 $requestData['session'] = $_SESSION; 44 } 45 46 // Cookies Tab 47 if (!empty($_COOKIE)) { 48 $requestData['cookies'] = $_COOKIE; 63 $headers = self::getRequestHeaders(); 64 if (!empty($headers)) { 65 $requestData['request']['headers'] = $headers; 49 66 } 50 67 … … 52 69 } 53 70 71 /** 72 * Get the request context. 73 * 74 * @return string|null 75 */ 54 76 public static function getContext() 55 77 { 56 if (self::isRequest() && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER["REQUEST_URI"])) { 57 return $_SERVER['REQUEST_METHOD'] . ' ' . strtok($_SERVER["REQUEST_URI"], '?'); 58 } else { 59 return null; 78 if (self::isRequest() && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['REQUEST_URI'])) { 79 return $_SERVER['REQUEST_METHOD'].' '.strtok($_SERVER['REQUEST_URI'], '?'); 60 80 } 61 81 } 62 82 83 /** 84 * Get the request id. 85 * 86 * @return string|null 87 */ 63 88 public static function getUserId() 64 89 { 65 90 if (self::isRequest()) { 66 91 return self::getRequestIp(); 67 } else {68 return null;69 92 } 70 93 } 71 94 95 /** 96 * Get the request url. 97 * 98 * @return string 99 */ 72 100 public static function getCurrentUrl() 73 101 { 74 $schema = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443) ? 'https://' : 'http://';102 $schema = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? 'https://' : 'http://'; 75 103 76 return $schema.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 104 $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'; 105 106 return $schema.$host.$_SERVER['REQUEST_URI']; 77 107 } 78 108 109 /** 110 * Get the request ip. 111 * 112 * @return string 113 */ 79 114 public static function getRequestIp() 80 115 { 81 116 return isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; 82 117 } 118 119 /** 120 * Get the request headers. 121 * 122 * @return array 123 */ 124 public static function getRequestHeaders() 125 { 126 $headers = array(); 127 128 foreach ($_SERVER as $name => $value) { 129 if (substr($name, 0, 5) == 'HTTP_') { 130 $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; 131 } 132 } 133 134 return $headers; 135 } 83 136 } -
bugsnag/trunk/bugsnag-php/Stacktrace.php
r871602 r1542350 3 3 class Bugsnag_Stacktrace 4 4 { 5 private $frames = array(); 5 private static $DEFAULT_NUM_LINES = 7; 6 private static $MAX_LINE_LENGTH = 200; 7 8 public $frames = array(); 6 9 private $config; 7 10 11 /** 12 * Generate a new stacktrace using the given config. 13 * 14 * @param Bugsnag_Configuration $config the configuration instance 15 * 16 * @return self 17 */ 8 18 public static function generate($config) 9 19 { … … 12 22 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS & ~DEBUG_BACKTRACE_PROVIDE_OBJECT); 13 23 } elseif (version_compare(PHP_VERSION, '5.2.5') >= 0) { 14 $backtrace = debug_backtrace( FALSE);24 $backtrace = debug_backtrace(false); 15 25 } else { 16 26 $backtrace = debug_backtrace(); 17 27 } 18 28 19 return self::fromBacktrace($config, $backtrace, "[generator]", 0); 20 } 21 29 return self::fromBacktrace($config, $backtrace, '[generator]', 0); 30 } 31 32 /** 33 * Create a new stacktrace instance from a frame. 34 * 35 * @param Bugsnag_Configuration $config the configuration instance 36 * @param string $file the associated file 37 * @param int $line the line number 38 * 39 * @return self 40 */ 22 41 public static function fromFrame($config, $file, $line) 23 42 { 24 $stacktrace = new Bugsnag_Stacktrace($config);25 $stacktrace->addFrame($file, $line, "[unknown]");43 $stacktrace = new self($config); 44 $stacktrace->addFrame($file, $line, '[unknown]'); 26 45 27 46 return $stacktrace; 28 47 } 29 48 49 /** 50 * Create a new stacktrace instance from a backtrace. 51 * 52 * @param Bugsnag_Configuration $config the configuration instance 53 * @param array $backtrace the associated backtrace 54 * @param int $topFile the top file to use 55 * @param int $topLine the top line to use 56 * 57 * @return self 58 */ 30 59 public static function fromBacktrace($config, $backtrace, $topFile, $topLine) 31 60 { 32 $stacktrace = new Bugsnag_Stacktrace($config);61 $stacktrace = new self($config); 33 62 34 63 // PHP backtrace's are misaligned, we need to shift the file/line down a frame 35 64 foreach ($backtrace as $frame) { 36 65 if (!self::frameInsideBugsnag($frame)) { 37 $stacktrace->addFrame($topFile, $topLine, $frame['function'], isset($frame['class']) ? $frame['class'] : NULL); 66 $stacktrace->addFrame( 67 $topFile, 68 $topLine, 69 isset($frame['function']) ? $frame['function'] : null, 70 isset($frame['class']) ? $frame['class'] : null 71 ); 38 72 } 39 73 … … 42 76 $topLine = $frame['line']; 43 77 } else { 44 $topFile = "[internal]";78 $topFile = '[internal]'; 45 79 $topLine = 0; 46 80 } … … 53 87 } 54 88 89 /** 90 * Does the given frame internally belong to bugsnag. 91 * 92 * @param array $frame the given frame to check 93 * 94 * @return bool 95 */ 55 96 public static function frameInsideBugsnag($frame) 56 97 { … … 58 99 } 59 100 60 101 /** 102 * Create a new stacktrace instance. 103 * 104 * @param Bugsnag_Configuration $config the configuration instance 105 * 106 * @return void 107 */ 61 108 public function __construct($config) 62 109 { … … 64 111 } 65 112 113 /** 114 * Get the array representation. 115 * 116 * @return array 117 */ 66 118 public function toArray() 67 119 { … … 69 121 } 70 122 71 public function addFrame($file, $line, $method, $class=NULL) 72 { 73 // Check if this frame is inProject 74 $inProject = !is_null($this->config->projectRootRegex) && preg_match($this->config->projectRootRegex, $file); 75 76 // Strip out projectRoot from start of file path 77 if ($inProject) { 78 $file = preg_replace($this->config->projectRootRegex, '', $file); 123 /** 124 * Add the given frame to the stacktrace. 125 * 126 * @param string $file the associated file 127 * @param int $line the line number 128 * @param string $method the method called 129 * @param string|null $class the associated class 130 * 131 * @return void 132 */ 133 public function addFrame($file, $line, $method, $class = null) 134 { 135 // Account for special "filenames" in eval'd code 136 $matches = array(); 137 if (preg_match("/^(.*?)\((\d+)\) : (?:eval\(\)'d code|runtime-created function)$/", $file, $matches)) { 138 $file = $matches[1]; 139 $line = $matches[2]; 79 140 } 80 141 81 142 // Construct the frame 82 143 $frame = array( 83 'file' => $file, 84 'lineNumber' => $line, 85 'method' => $method, 86 'inProject' => $inProject 144 'lineNumber' => (int) $line, 145 'method' => $class ? "$class::$method" : $method, 87 146 ); 88 147 89 if (!empty($class)) { 90 $frame['class'] = $class; 148 // Attach some lines of code for context 149 if ($this->config->sendCode) { 150 $frame['code'] = $this->getCode($file, $line, self::$DEFAULT_NUM_LINES); 151 } 152 153 // Check if this frame is inProject 154 $frame['inProject'] = !is_null($this->config->projectRootRegex) && preg_match($this->config->projectRootRegex, $file); 155 156 // Strip out projectRoot from start of file path 157 if (is_null($this->config->stripPathRegex)) { 158 $frame['file'] = $file; 159 } else { 160 $frame['file'] = preg_replace($this->config->stripPathRegex, '', $file); 91 161 } 92 162 93 163 $this->frames[] = $frame; 94 164 } 165 166 /** 167 * Extract the code for the given file and lines. 168 * 169 * @param string $path the path to the file 170 * @param int $line the line to centre about 171 * @param string $numLines the number of lines to fetch 172 * 173 * @return string[]|null 174 */ 175 private function getCode($path, $line, $numLines) 176 { 177 if (empty($path) || empty($line) || !file_exists($path)) { 178 return; 179 } 180 181 try { 182 // Get the number of lines in the file 183 $file = new SplFileObject($path); 184 $file->seek(PHP_INT_MAX); 185 $totalLines = $file->key() + 1; 186 187 // Work out which lines we should fetch 188 $start = max($line - floor($numLines / 2), 1); 189 $end = $start + ($numLines - 1); 190 if ($end > $totalLines) { 191 $end = $totalLines; 192 $start = max($end - ($numLines - 1), 1); 193 } 194 195 // Get the code for this range 196 $code = array(); 197 198 $file->seek($start - 1); 199 while ($file->key() < $end) { 200 $code[$file->key() + 1] = rtrim(substr($file->current(), 0, self::$MAX_LINE_LENGTH)); 201 $file->next(); 202 } 203 204 return $code; 205 } catch (RuntimeException $ex) { 206 return; 207 } 208 } 95 209 } -
bugsnag/trunk/bugsnag.php
r904344 r1542350 4 4 Plugin URI: https://bugsnag.com 5 5 Description: Bugsnag monitors for errors and crashes on your wordpress site, sends them to your bugsnag.com dashboard, and notifies you by email of each error. 6 Version: 1. 1.26 Version: 1.3.0 7 7 Author: Bugsnag Inc. 8 8 Author URI: https://bugsnag.com … … 18 18 private static $NOTIFIER = array( 19 19 'name' => 'Bugsnag Wordpress (Official)', 20 'version' => '1. 1.2',20 'version' => '1.3.0', 21 21 'url' => 'https://bugsnag.com/notifiers/wordpress' 22 22 ); … … 26 26 private $notifySeverities; 27 27 private $filterFields; 28 private $pluginBase; 28 29 29 30 public function __construct() … … 32 33 $this->activateBugsnag(); 33 34 35 $this->pluginBase = 'bugsnag/bugsnag.php'; 36 34 37 // Run init actions (loading wp user) 35 38 add_action('init', array($this, 'initActions')); … … 38 41 add_action('admin_menu', array($this, 'adminMenuActions')); 39 42 43 // Load network admin menu if using multisite 44 add_action('network_admin_menu', array($this, 'networkAdminMenuActions')); 45 40 46 add_action('wp_ajax_test_bugsnag', array($this, 'testBugsnag')); 41 47 } … … 43 49 private function activateBugsnag() 44 50 { 45 // Require bugsnag-php 46 if(file_exists($this->relativePath(self::$COMPOSER_AUTOLOADER))) { 47 require_once $this->relativePath(self::$COMPOSER_AUTOLOADER); 48 } elseif (file_exists($this->relativePath(self::$PACKAGED_AUTOLOADER))) { 49 require_once $this->relativePath(self::$PACKAGED_AUTOLOADER); 50 } else { 51 $is_load_success = $this->requireBugsnagPhp(); 52 if (!$is_load_success) { 51 53 error_log("Bugsnag Error: Couldn't activate Bugsnag Error Monitoring due to missing Bugsnag library!"); 52 54 return; … … 54 56 55 57 // Load bugsnag settings 56 $this->apiKey = get_option('bugsnag_api_key'); 57 $this->notifySeverities = get_option('bugsnag_notify_severities'); 58 $this->filterFields = get_option('bugsnag_filterfields'); 58 if (!get_site_option('bugsnag_network')) { 59 // Regular 60 $this->apiKey = get_option( 'bugsnag_api_key' ); 61 $this->notifySeverities = get_option( 'bugsnag_notify_severities' ); 62 $this->filterFields = get_option( 'bugsnag_filterfields' ); 63 } else { 64 // Multisite 65 $this->apiKey = get_site_option( 'bugsnag_api_key' ); 66 $this->notifySeverities = get_site_option( 'bugsnag_notify_severities' ); 67 $this->filterFields = get_site_option( 'bugsnag_filterfields' ); 68 } 59 69 60 70 $this->constructBugsnag(); … … 72 82 $this->client->setNotifier(self::$NOTIFIER); 73 83 74 // Hook up automatic error handling 75 set_error_handler(array($this->client, "errorHandler")); 76 set_exception_handler(array($this->client, "exceptionHandler")); 77 } 78 84 // If handlers are not set, errors are still going to be reported 85 // to bugsnag, difference is execution will not stop. 86 // 87 // Can be useful to see inline errors and traces with xdebug too. 88 $set_error_and_exception_handlers = apply_filters('bugsnag_set_error_and_exception_handlers', true); 89 if ($set_error_and_exception_handlers === true) { 90 // Hook up automatic error handling 91 set_error_handler(array($this->client, "errorHandler")); 92 set_exception_handler(array($this->client, "exceptionHandler")); 93 } 94 } 95 96 } 97 98 private function requireBugsnagPhp() 99 { 100 // Bugsnag-php was already loaded by some 3rd-party code, don't need to load it again. 101 if (class_exists('Bugsnag_Client')) { 102 return true; 103 } 104 105 // Try loading bugsnag-php with composer autoloader. 106 $composer_autoloader_path = $this->relativePath(self::$COMPOSER_AUTOLOADER); 107 $composer_autoloader_path_filtered = apply_filters('bugsnag_composer_autoloader_path', $composer_autoloader_path); 108 if (file_exists($composer_autoloader_path_filtered)) { 109 require_once $composer_autoloader_path_filtered; 110 return true; 111 } 112 113 // Try loading bugsnag-php from packaged autoloader. 114 $packaged_autoloader_path = $this->relativePath(self::$PACKAGED_AUTOLOADER); 115 $packaged_autoloader_path_filtered = apply_filters('bugsnag_packaged_autoloader_path', $packaged_autoloader_path); 116 if (file_exists($packaged_autoloader_path_filtered)) { 117 require_once $packaged_autoloader_path_filtered; 118 return true; 119 } 120 121 return false; 79 122 } 80 123 … … 99 142 private function filterFields() 100 143 { 101 return array_map('trim', explode("\n", $this->filterFields)); 144 $filter_fields = apply_filters('bugsnag_filter_fields', $this->filterFields); 145 146 // Array with empty string will break things. 147 if ($filter_fields === '') { 148 return array(); 149 } 150 151 return array_map('trim', explode("\n", $filter_fields)); 102 152 } 103 153 104 154 private function releaseStage() 105 155 { 106 return defined('WP_ENV') ? WP_ENV : "production"; 156 $release_stage = defined('WP_ENV') ? WP_ENV : "production"; 157 $release_stage_filtered = apply_filters('bugsnag_release_stage', $release_stage); 158 return $release_stage_filtered; 107 159 } 108 160 … … 111 163 public function initActions() 112 164 { 113 // Set the bugsnag user using the current WordPress user if available 114 $wpUser = wp_get_current_user(); 115 if(!empty($this->client) && !empty($wpUser)) { 116 $user = array(); 117 118 if(!empty($wpUser->user_login)) { 119 $user['id'] = $wpUser->user_login; 165 // This should be handled on stage of initializing, 166 // not even adding action if init failed. 167 // 168 // Leaving it here for now. 169 if(empty($this->client)) { 170 return; 171 } 172 173 174 // Set the bugsnag user using the current WordPress user if available, 175 // set as anonymous otherwise. 176 $user = array(); 177 if (is_user_logged_in()) { 178 $wp_user = wp_get_current_user(); 179 180 // Removed checks for !empty($wp_user->display_name), it should not be required. 181 $user['id'] = $wp_user->user_login; 182 $user['email'] = $wp_user->user_email; 183 $user['name'] = $wp_user->display_name; 184 } 185 else { 186 $use_unsafe_spoofable_ip_address_getter = apply_filters('bugsnag_use_unsafe_spoofable_ip_address_getter', true); 187 $user['id'] = $use_unsafe_spoofable_ip_address_getter ? 188 $this->getClientIpAddressUnsafe() : 189 $this->getClientIpAddress(); 190 $user['name'] = 'anonymous'; 191 } 192 193 $this->client->setUser($user); 194 } 195 196 // Unsafe: client can spoof address. 197 // http://stackoverflow.com/questions/1634782/what-is-the-most-accurate-way-to-retrieve-a-users-correct-ip-address-in-php 198 private function getClientIpAddressUnsafe() 199 { 200 foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){ 201 if (array_key_exists($key, $_SERVER) === true) { 202 foreach (explode(',', $_SERVER[$key]) as $ip) { 203 $ip = trim($ip); 204 if (filter_var($ip, FILTER_VALIDATE_IP) !== false) { 205 return $ip; 206 } 207 } 120 208 } 121 122 if(!empty($wpUser->user_email)) { 123 $user['email'] = $wpUser->user_email; 124 } 125 126 if(!empty($wpUser->user_display_name)) { 127 $user['name'] = $wpUser->user_display_name; 128 } 129 130 $this->client->setUser($user); 131 } 209 } 210 } 211 212 // Can not be spoofed, but can show ip of NAT or proxies. 213 private function getClientIpAddress() 214 { 215 return $_SERVER['REMOTE_ADDR']; 132 216 } 133 217 134 218 public function adminMenuActions() 135 219 { 136 // Add the "settings" link to the Bugsnag row of plugins.php 137 add_filter('plugin_action_links', array($this, 'pluginActionLinksFilter'), 10, 2); 138 139 // Create the settings page 140 add_options_page('Bugsnag Settings', 'Bugsnag', 'manage_options', 'bugsnag', array($this, 'renderSettings')); 220 if ( ! function_exists( 'is_plugin_active_for_network' ) || ! is_plugin_active_for_network($this->pluginBase)) { 221 // Add the "settings" link to the Bugsnag row of plugins.php 222 add_filter('plugin_action_links', array($this, 'pluginActionLinksFilter'), 10, 2); 223 224 // Create the settings page 225 add_options_page('Bugsnag Settings', 'Bugsnag', 'manage_options', 'bugsnag', array($this, 'renderSettings')); 226 } 227 } 228 229 public function networkAdminMenuActions() 230 { 231 if (function_exists('is_plugin_active_for_network') && is_plugin_active_for_network($this->pluginBase)) { 232 // Create the network settings page 233 add_submenu_page('settings.php', 'Bugsnag Settings', 'Bugsnag', 'manage_network_options', 'bugsnag', array($this, 'renderSettings')); 234 } 235 } 236 237 private function updateNetworkSettings( $settings ) 238 { 239 // Update options 240 update_site_option('bugsnag_api_key', isset($_POST['bugsnag_api_key']) ? $_POST['bugsnag_api_key'] : ''); 241 update_site_option('bugsnag_notify_severities', isset($_POST['bugsnag_notify_severities']) ? $_POST['bugsnag_notify_severities'] : ''); 242 update_site_option('bugsnag_filterfields', isset($_POST['bugsnag_filterfields']) ? $_POST['bugsnag_filterfields'] : ''); 243 update_site_option('bugsnag_network', true); 244 245 // Update variables 246 $this->apiKey = get_site_option( 'bugsnag_api_key' ); 247 $this->notifySeverities = get_site_option( 'bugsnag_notify_severities' ); 248 $this->filterFields = get_site_option( 'bugsnag_filterfields' ); 249 250 echo '<div class="updated"><p>Settings saved.</p></div>'; 141 251 } 142 252 … … 171 281 public function renderSettings() 172 282 { 283 if ( ! empty($_POST[ 'action' ]) && $_POST[ 'action' ] == 'update') { 284 $this->updateNetworkSettings( $_POST ); 285 } 286 173 287 include $this->relativePath('views/settings.php'); 174 288 } … … 179 293 echo "<option value=\"$value\"$selected>$name</option>"; 180 294 } 295 296 /** 297 * Fluent interface to $this->client, simply call the methods on this object and this will proxy them through. 298 * 299 * @param string $method 300 * @param array $arguments 301 * 302 * @return mixed 303 */ 304 public function __call($method, $arguments) 305 { 306 if (method_exists($this->client, $method)) { 307 return call_user_func_array(array($this->client, $method), $arguments); 308 } 309 310 throw new BadMethodCallException(sprintf('Method %s does not exist on %s or Bugsnag_Client', $method, __CLASS__ )); 311 } 181 312 } 182 313 -
bugsnag/trunk/readme.txt
r982429 r1542350 3 3 Tags: bugsnag, error, monitoring, exception, logging 4 4 Requires at least: 2.0 5 Tested up to: 3.86 Stable tag: 1. 1.25 Tested up to: 4.5 6 Stable tag: 1.3.0 7 7 License: GPLv2 or later 8 8 … … 39 39 == Changelog == 40 40 41 = 1.3.0 = 42 * Fix version constraints 43 * General fixes for WP 4.5 compatibility 44 45 = 1.2.1 = 46 * Add support for WordPress Multisite installations. 47 41 48 = 1.2.0 = 42 49 * Update bugsnag-php to allow cURL or fopen. -
bugsnag/trunk/views/settings.php
r904344 r1542350 9 9 </p> 10 10 11 <form method="post" action="options.php"> 11 <?php if (function_exists('is_plugin_active_for_network') && is_plugin_active_for_network($this->pluginBase)) { ?> 12 <form method='post'> 13 <?php } else { ?> 14 <form method="post" action="options.php"> 15 <?php } ?> 12 16 <?php if(empty($this->apiKey)) { ?> 13 17 … … 39 43 </th> 40 44 <td> 41 <input type="text" id="bugsnag_api_key" name="bugsnag_api_key" value="<?php echo get_option('bugsnag_api_key');?>" class="regular-text code" /><br>45 <input type="text" id="bugsnag_api_key" name="bugsnag_api_key" value="<?php echo $this->apiKey ?>" class="regular-text code" /><br> 42 46 43 47 <p class="description"> … … 67 71 </th> 68 72 <td> 69 <textarea id="bugsnag_filterfields" name="bugsnag_filterfields" class="regular-text filterfields" style="width: 355px; height: 150px;"><?php echo get_option('bugsnag_filterfields'); ?></textarea>73 <textarea id="bugsnag_filterfields" name="bugsnag_filterfields" class="regular-text filterfields" style="width: 355px; height: 150px;"><?php echo $this->filterFields; ?></textarea> 70 74 <p class="description" style="max-width: 400px"> 71 75 The information to remove from Bugsnag reports, one per line. Use this if you want to ensure you don't send sensitive data such as passwords, and credit card numbers to our servers.
Note: See TracChangeset
for help on using the changeset viewer.