Files
2026-04-28 15:13:50 +02:00

202 lines
5.5 KiB
PHP

<?php
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
namespace FacebookPixelPlugin\FacebookAds;
use FacebookPixelPlugin\FacebookAds\Api;
use FacebookPixelPlugin\FacebookAds\Exception\Exception;
use FacebookPixelPlugin\FacebookAds\Http\RequestInterface;
use FacebookPixelPlugin\FacebookAds\Http\Exception\RequestException;
/**
* Class CrashReasons
* @package FacebookAds
*/
class CrashReasons {
const SDK = 'SDK';
const API = 'API';
}
/**
* Class CrashReporter
* @package FacebookAds
*/
class CrashReporter {
const E_FATAL =
E_ERROR |
E_USER_ERROR |
E_PARSE |
E_CORE_ERROR |
E_COMPILE_ERROR |
E_RECOVERABLE_ERROR;
/**
* @var CrashReporter
*/
private static $instance;
/**
* @var resource
*/
private static $handle;
/**
* @var int
*/
private $app_id;
/**
* CrashReporter constructor.
* @param int $app_id
* @return void
*/
private function __construct(
$app_id
) {
$this->app_id = $app_id;
}
/**
* @return void
*/
public static function enable() {
if (!static::$handle) {
static::$handle = fopen('php://stdout', 'w');
}
if (!static::$instance) {
$api = Api::instance();
if ($api == null) {
self::log('Could not initialize API' . PHP_EOL);
}
static::$instance = new static($api->getSession()->getAppId());
static::$instance->registerExceptionHandler();
self::log('Enabled' . PHP_EOL);
}
}
/**
* @return void
*/
public static function disable() {
if (static::$instance) {
static::$instance = null;
restore_exception_handler();
restore_error_handler();
self::log('Disabled');
}
}
/**
* @param $handle
*/
public static function setLogger($handle) {
if(is_resource($handle)) {
static::$handle = $handle;
}
}
/**
* @return void
*/
private function registerExceptionHandler() {
$lastHandler = set_exception_handler(
function (\Throwable $e) use (&$lastHandler) {
self::log('Exception detected!');
$params = $this->buildParamsFromException($e);
if ($params != null) {
$this->sendReport(array(
'bizsdk_crash_report' => $params
));
}
// restore the previous exception
if (is_callable($lastHandler)) {
return call_user_func_array($lastHandler, [$e]);
} else {
throw $e;
}
}
);
$lastError = set_error_handler(
function ($errno, $errstr, $errfile, $errline) use (&$lastError) {
if (($errno & self::E_FATAL) && strpos($errfile, 'FacebookAds') != false) {
self::log('Error detected!');
$e = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
$params = $this->buildParamsFromException($e);
if ($params != null) {
$this->sendReport(array(
'bizsdk_crash_report' => $params
));
}
}
if (is_callable($lastError)) {
return call_user_func_array($lastError, [$errno, $errstr, $errfile, $errline]);
} else {
// fall through to the standard PHP error handler
return false;
}
}
);
}
/**
* @param \Throwable $e
* @return array|null
*/
private function buildParamsFromException(\Throwable $e) {
if (!($e instanceof Exception || $e instanceof \ErrorException)) {
return NULL;
}
$reason = CrashReasons::SDK;
if ($e instanceof RequestException) {
$reason = CrashReasons::API;
}
$reason .= ' : ' . $e->getMessage();
$callstack = explode(PHP_EOL, $e->getTraceAsString());
return array(
'reason' => $reason,
'callstack' => $callstack,
'platform' => phpversion()
);
}
/**
* @param $params
*/
private function sendReport($params) {
try {
$session = new AnonymousSession();
$api = new Api(Api::instance()->getHttpClient(), $session);
$request = $api->prepareRequest(
'/' . $this->app_id . '/instruments',
RequestInterface::METHOD_POST,
$params
);
$response = $api->executeRequest($request);
$data = $response->getContent();
if ($data && $data['success']) {
self::log('Successfully sent report' . PHP_EOL);
} else {
self::log('Failed to send report' . PHP_EOL);
}
} catch (\Exception $e) {
self::log('Exception on sending report' . PHP_EOL);
}
}
/**
* @param $message
*/
private static function log($message) {
$content = sprintf("%s : %s%s",static::class, $message, PHP_EOL);
fwrite(static::$handle, $content);
}
}