Plugin Directory

Changeset 3380353


Ignore:
Timestamp:
10/17/2025 10:48:31 PM (3 months ago)
Author:
danielmorell
Message:

Sync with GitHub repo v3.0.0

Location:
rollbar/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • rollbar/trunk/README.md

    r2965452 r3380353  
    11# Rollbar for WordPress
     2
    23[![Plugin Version](https://img.shields.io/wordpress/plugin/v/rollbar.svg)](https://wordpress.org/plugins/rollbar/) [![WordPress Version Compatibility](https://img.shields.io/wordpress/v/rollbar.svg)](https://wordpress.org/plugins/rollbar/) [![Downloads](https://img.shields.io/wordpress/plugin/dt/rollbar.svg)](https://wordpress.org/plugins/rollbar/) [![Rating](https://img.shields.io/wordpress/plugin/r/rollbar.svg)](https://wordpress.org/plugins/rollbar/)
    34
    4 Rollbar full-stack error tracking for WordPress
    5 
    6 The full documentation is available [here](https://docs.rollbar.com/v1.0.0/docs/wordpress).
    7 
    8 ## Description
     5Rollbar full-stack error tracking for WordPress.
     6
    97Rollbar collects errors that happen in your application, notifies you, and analyzes them so you can debug and fix them.
    10 
    118This plugin integrates Rollbar into your WordPress installation.
    129
    13 Find out [how Rollbar can help you decrease development and maintenance costs](https://rollbar.com/features/).
    14 
    15 See [real companies improving their development workflow thanks to Rollbar](https://rollbar.com/customers/).
     10#### Helpful Links
     11
     12* [Documentation](https://docs.rollbar.com/docs/wordpress)
     13* [Official WordPress.org Plugin](https://wordpress.org/plugins/rollbar/)
     14* [How Rollbar Works](https://rollbar.com/discover/)
     15* [Rollbar Pricing](https://rollbar.com/pricing/)
    1616
    1717[Official WordPress.org Plugin](https://wordpress.org/plugins/rollbar/)
     18#### Table of Contents
     19
     201. [Installation](#installation)
     21    1. [Through WordPress Plugin directory](#through-wordpress-plugin-directory)
     22    2. [Through Packagist](#through-packagist-recommended-new)
     23    3. [Through WPackagist](#through-wpackagist)
     242. [Configuration](#configuration)
     25    1. [WordPress Admin](#wordpress-admin)
     26    2. [Programmatic Configuration](#programmatic-configuration)
     273. [Advanced Use](#advanced-use)
     28    1. [Constants](#constants)
     29    2. [Environment Variables](#environment-variables)
     30    3. [Filters](#filters)
     31    4. [Telemetry](#telemetry)
     324. [Help / Support](#help--support)
     335. [Special thanks](#special-thanks)
     346. [Contributing](#contributing)
     357. [Testing](#testing)
    1836
    1937## Installation
     
    2139### Through [WordPress Plugin directory](https://wordpress.org/plugins/rollbar/)
    2240
    23 The easiest way to install the plugin is from the WordPress Plugin directory. If you have an existing WordPress installation and you want to add Rollbar:
     41The easiest way to install the plugin is from the WordPress Plugin directory. If you have an existing WordPress
     42installation, and you want to add Rollbar:
    2443
    25441. In your WordPress administration panel go to `Plugins` → `Add New`.
     
    27463. Click `Install Now` next to the `Rollbar` plugin.
    28474. In `Plugins` → `Installed plugins` find `Rollbar` and click `Activate` underneath.
    29 5. Log into your [Rollbar account dashboard](https://rollbar.com/login/):
    30    1. Go to `Settings` → `Project Access Tokens`.
    31    2. Copy the token value under `post_client_item` and `post_server_item`.
    32 6. In WordPress, navigate to `Settings` → `Rollbar`:
    33    1. Enable `PHP error logging` and/or `Javascript error logging` depending on your needs.
    34    2. Paste the tokens you copied in step 7 in `Access Token` section.
    35    3. Provide the name of your environment in `Environment`. By default, the environment will be taken from `WP_ENV` environment variable if it's set otherwise it's blank. We recommend to fill this out either with `development` or `production`.
    36    4. Pick a minimum logging level. Only errors at that or higher level will be reported. For reference: [PHP Manual: Predefined Error Constants](http://php.net/manual/en/errorfunc.constants.php).
    37    5. Click `Save Changes`.
    38 
    39 **Warning**: This installation method might not be suitable for complex WordPress projects. The plugin installed this way will be self-contained and include all of the required dependencies for itself and `rollbar/rollbar-php` library. In complex projects, this might lead to version conflicts between dependencies and other plugins/packages. If this is an issue in your project, we recommend the "Advanced" installation method. For more information why this might be important for you, read [Using Composer with WordPress](https://roots.io/using-composer-with-wordpress/).
    40 
    41 ### Through [wpackagist](https://wpackagist.org/) (if you manage your project with Composer) *recommended*
    42 
    43 This is a recommended way to install Rollbar plugin for advanced projects. This way ensures the plugin and all of its' dependencies are managed by Composer.
    44 
    45 1. If your WordPress project is not managed with Composer yet, we suggest looking into upgrading your WordPress: [Using Composer with WordPress](https://roots.io/using-composer-with-wordpress/).
    46 2. In your `composer.json` add `wpackagist-plugin/rollbar` to your `require` section, i.e.:
    47 ```json
    48   "require": {
    49     "php": ">=5.5",
    50     ...,
    51     "wpackagist-plugin/rollbar": "*"
    52   }
     48
     49**Warning**: This installation method might not be suitable for complex WordPress projects. The plugin installed this
     50way will be self-contained and include all of the required dependencies for itself and the `rollbar/rollbar-php`
     51library. In complex projects, this might lead to version conflicts between dependencies and other plugins/packages. If
     52this is an issue in your project, we recommend the "Packagist" installation method.
     53
     54### Through [Packagist](https://packagist.org/packages/rollbar/rollbar-php-wordpress) *recommended new*
     55
     56*Note: this only works if your WordPress project is managed with Composer.
     57Read [Using Composer with WordPress](https://roots.io/using-composer-with-wordpress/) for more details.*
     58
     59This is a recommended way to install the Rollbar plugin for advanced projects. This way ensures the plugin and all of
     60its dependencies are managed by Composer.
     61
     62You can install the plugin by running the following command in the root directory of your WordPress project:
     63
     64```txt
     65composer require rollbar/rollbar-php-wordpress:^3.0
    5366```
    54 3. Issue command `composer install` in the root directory of your WordPress project.
    55 4. Go to step #4 above.
     67
     68### Through [WPackagist](https://wpackagist.org/)
     69
     70*Note: if your WordPress project is managed with Composer, we strongly recommend installing the plugin through
     71Packagist instead.*
     72
     73*Installing the plugin from wpackagist.org instead of packagist.org will result in the plugin being managed by
     74Composer. However, the downside is that it's dependencies will not be managed by composer. Instead they will be packaged
     75in the plugin's `vendor` directory not in your project's `vendor` directory. This has the potential to cause name
     76collisions if other plugins or your project use different versions of the same dependencies.*
     77
     78To install the plugin from wpackagist.org run the following steps command in the root directory of your WordPress
     79project:
     80
     81```txt
     82composer require wpackagist-plugin/rollbar
     83```
     84
     85## Configuration
     86
     87The plugin can be configured in the WordPress Admin or programmatically.
     88
     89### WordPress Admin
     90
     91The plugin provides a settings page in the WordPress Admin that allows you to configure the plugin. This settings page
     92can be disabled by setting the `ROLLBAR_DISABLE_ADMIN` constant to `true` in your `wp-config.php` file.
     93
     941. In `Plugins` → `Installed plugins` find `Rollbar` and click `Activate` underneath.
     952. Log into your [Rollbar account dashboard](https://rollbar.com/login/):
     96    1. Go to `Settings` → `Project Access Tokens`.
     97    2. Copy the token value under `post_client_item` and `post_server_item`.
     983. In WordPress, navigate to `Settings` → `Rollbar`:
     99    1. Enable `PHP error logging` and/or `Javascript error logging` depending on your needs.
     100    2. Paste the tokens you copied in step 7 in `Access Token` section.
     101    3. Provide the name of your environment in `Environment`. By default, the environment will be taken from `WP_ENV`
     102       environment variable if it's set otherwise it's blank. We recommend to fill this out either with `development` or
     103       `production`.
     104    4. Pick a minimum logging level. Only errors at that or higher level will be reported. For
     105       reference: [PHP Manual: Predefined Error Constants](http://php.net/manual/en/errorfunc.constants.php).
     106    5. Click `Save Changes`.
     107
     108### Programmatic Configuration
     109
     110The plugin can also be configured programmatically. This is useful if you want to configure the plugin in a more
     111advanced way or if you want to disable the admin settings page.
     112
     113```php
     114// wp-config.php
     115
     116// Configure the plugin.
     117define( 'ROLLBAR_SETTINGS', [
     118    'php_logging_enabled' => true,
     119    'server_side_access_token' => '<your token>',
     120    'js_logging_enabled' => true,
     121    'client_side_access_token' => '<your client token>',
     122    'environment' => 'development',
     123    'included_errno' => E_ERROR,
     124    'enable_person_reporting' => true,
     125] );
     126
     127// Optional: disable the admin settings page so the plugin is configured only programmatically.
     128define( 'ROLLBAR_DISABLE_ADMIN', true );
     129```
     130
     131## Advanced Use
     132
     133### Constants
     134
     135The plugin provides a number of constants that can be used to configure the plugin. These should typically be defined in
     136the `wp-config.php` file.
     137
     138Note: If you define these constants, they will override the settings defined in the WordPress Admin.
     139
     140* `ROLLBAR_DISABLE_ADMIN` - (optional) Removes the Rollbar Admin menu from the WordPress Admin if set to `true`. This
     141  allows for the plugin to be used without the admin settings page, for example, if the plugin is managed via the
     142  `wp-config.php` file.
     143* `ROLLBAR_SETTINGS` - (optional) An associative array of settings to override the settings values from the WordPress
     144  Admin. Note: if you disable the admin settings page with `ROLLBAR_DISABLE_ADMIN` constant, this constant must be used
     145  to configure the plugin.
     146* `ROLLBAR_ACCESS_TOKEN` - The Rollbar PHP server access token.
     147* `ROLLBAR_CLIENT_ACCESS_TOKEN` - The Rollbar JS client access token.
     148
     149#### WordPress Constants
     150
     151The Rollbar plugin respects the following WordPress constants:
     152
     153* `WP_ENV` - (optional) The environment name. This is used to determine the environment name for the Rollbar project.
     154* `WP_PROXY_HOST` - (optional) The proxy host. If both `WP_PROXY_HOST` and `WP_PROXY_PORT` are set, the plugin will use
     155  the respect the HTTP proxy when making requests to Rollbar.
     156* `WP_PROXY_PORT` - (optional) The proxy port.
     157* `WP_PROXY_USERNAME` - (optional) The proxy username.
     158* `WP_PROXY_PASSWORD` - (optional) The proxy password.
     159* `WP_PROXY_BYPASS_HOSTS` - (optional) The proxy bypass hosts. This is a comma-separated list of hosts that should not
     160  be
     161  proxied. If proxying is enabled, but you don't want to proxy requests to Rollbar, you can add `api.rollbar.com` to
     162  this list.
     163
     164### Environment Variables
     165
     166The plugin looks for the following environment variables to configure itself. Note: these are overridden by the
     167constants defined above.
     168
     169* `ROLLBAR_ACCESS_TOKEN` - The Rollbar PHP server access token.
     170* `ROLLBAR_CLIENT_ACCESS_TOKEN` - The Rollbar JS client access token.
     171* `WP_ENV` - (optional) The environment name. This is used to determine the environment name for the Rollbar project.
     172
     173### Filters
     174
     175The plugin provides a number of filters that allow you to customize the behavior of the plugin.
     176
     177#### `apply_filters('rollbar_api_admin_permission', bool $value, string $route, WP_REST_Request $request)`
     178
     179Filter to allow or deny access to a Rollbar route in the WordPress REST API used in the WordPress Admin. Generally,
     180this should be the same as the `rollbar_user_can_view_admin` filter.
     181
     182**Parameters**
     183
     184* `bool $value` - The initial value. Defaults is `true` for admin users, `false` for non-admin users.
     185* `string $route` - The route being accessed.
     186* `WP_REST_Request $request` - The REST request object.
     187
     188#### `apply_filters('rollbar_js_config', array $config)`
     189
     190Filters the Rollbar JavaScript configuration.
     191
     192**Parameters**
     193
     194* `array $config` - The Rollbar JavaScript configuration array.
     195
     196#### `apply_filters('rollbar_plugin_settings', array $settings)`
     197
     198Filters the Rollbar plugin settings.
     199
     200**Parameters**
     201
     202* `array $settings` - The Rollbar plugin settings array.
     203
     204#### `apply_filters('rollbar_php_config', array $config)`
     205
     206Filters the Rollbar Core SDK PHP configuration.
     207
     208**Parameters**
     209
     210* `array $config` - The Rollbar PHP configuration array.
     211
     212#### `apply_filters('rollbar_telemetry_actions', array<string, int> $actions)`
     213
     214Filter the list of actions to instrument with Telemetry.
     215
     216**Parameters**
     217
     218* `array<string, int> $actions` - An associative array where the keys are action names and the values are the number of
     219  arguments accepted by the action.
     220
     221#### `apply_filters('rollbar_telemetry_custom_handlers', array<string, callable(string, mixed...):string> $handlers)`
     222
     223Filter the list of custom action event handlers for Telemetry.
     224
     225Note: The custom action handler will only be called if the action is instrumented with Telemetry. This means you must
     226select the action on the settings page, or add it to the list of actions using the `rollbar_telemetry_actions` filter.
     227
     228**Parameters**
     229
     230* `array<string, callable(string, mixed...):string> $handlers` - An associative array where the keys are action names
     231  and the values are the custom event handler.
     232
     233#### `apply_filters('rollbar_user_can_view_admin', bool $disable)`
     234
     235Filter to enable / disable the admin settings page of the plugin for the current user.
     236
     237This filter cannot override the `ROLLBAR_DISABLE_ADMIN` constant.
     238
     239**Parameters**
     240
     241* `bool $allow` - `true` to enable the admin settings page, `false` to disable it.
     242
     243### Telemetry
     244
     245Starting in version 3.0.0 of the Rollbar plugin, Telemetry is enabled by default. Telemetry is a feature that allows
     246the plugin to track events that occur in your WordPress installation prior to an exception or message being sent to
     247Rollbar. The Telemetry data is sent to Rollbar along with the exception or message, and can be used to provide
     248additional context and help debug the issue.
     249
     250You can modify the list of actions you want to instrument with Telemetry by selecting them on the settings page, or
     251using the `rollbar_telemetry_actions` filter. To use a custom handler for a specific action, use the
     252`rollbar_telemetry_custom_handlers` filter. This can also be used to change the handler on any of the default actions.
     253
     254#### Registering custom actions
     255
     256You can also instrument custom actions like this:
     257
     258```php
     259use Rollbar\WordPress\Telemetry\Listener;
     260
     261// Register a custom action with a custom handler function.
     262Listener::getInstance()->instrumentAction(
     263    action: 'my_custom_action',
     264    priority: 10,
     265    acceptedArgs: 2,
     266    argsHandler: function ($action, ...$args) {
     267        $foo = $action;
     268        return 'custom_listener_test_action: ' . implode(', ', $args);
     269    },
     270);
     271
     272// Use the default handler for the action.
     273Listener::getInstance()->instrumentAction(
     274    action: 'my_other_custom_action',
     275    priority: 10,
     276    acceptedArgs: 1,
     277    argsHandler: Listener::concatExtraArgs(...),
     278);
     279```
     280
     281Of course, you can also call `Rollbar::captureTelemetryEvent()` directly to send custom events. See the
     282[Telemetry documentation](https://docs.rollbar.com/docs/php-telemetry) for more information.
    56283
    57284## Help / Support
     
    60287
    61288For bug reports, please [open an issue on GitHub](https://github.com/rollbar/rollbar-php-wordpress/issues/new).
    62 
    63 ## Special thanks
    64 
    65 The original author of this package is [@flowdee](https://twitter.com/flowdee/). This is a fork and continuation of his efforts.
    66289
    67290## Contributing
     
    702932. Create your feature branch (`git checkout -b my-new-feature`)
    712943. Commit your changes (`git commit -am 'Added some feature'`)
    72 4. Push to the branch (`git push origin my-new-feature`)
    73 5. Verify your commit passes the code standards enforced by [Codacy](https://www.codacy.com).
    74 5. Create new Pull Request
     2954. Make sure tests pass (see below).
     2965. Push to the branch (`git push origin my-new-feature`)
     2976. Create a new Pull Request
    75298
    76299## Testing
    77300
    78 In order to run the tests, you will need to install the dependencies for [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) including Node.js, git, and docker.
    79 
    80 1. npm install
    81 2. npm run test
    82 You can set the `WP_ENV_PHP_VERSION` enviormental variable to test with different versions of PHP.  If you are changing the version, you can do so by running `WP_ENV_PHP_VERSION="8.2" npm run wp-env start -- --update` and setting the enviornmental variable based on
     301To run the tests, you will need to install the dependencies for
     302[@wordpress/env](https://www.npmjs.com/package/@wordpress/env) including Node.js, git, and Docker.
     303
     3041. `npm install` - This will install the dependencies to set up the local environment.
     3052. `npm run start` - This will start a local WordPress installation with the Rollbar plugin installed.
     3063. `npm run test` - This will run the tests.
     307
     308You can set the `WP_ENV_PHP_VERSION` environment variable to test with different versions of PHP. If you are changing
     309the version, you can do so by running `WP_ENV_PHP_VERSION="8.2" npm run wp-env start -- --update` and setting the
     310environment variable based on the version you want to test with.
     311
     312## Special thanks
     313
     314The original author of this package is [@flowdee](https://twitter.com/flowdee/). This is a fork and continuation of his
     315efforts.
    83316
    84317## Tagging
     
    91324    3. Add record in the `Upgrade Notice` section of the `readme.txt`.
    92325    4. Bump the plugin version in `rollbar-php-wordpress.php` in the `Version:` comment.
    93     5. Bump the plugin version in `src/Plugin.php` in the `\Rollbar\Wordpress\Plugin::VERSION` constant.
    94     5. Add and commit the changes you made to bump the plugin version: `git add readme.txt rollbar-php-wordpress.php src/Plugin.php && git commit -m"Bump version to v[version number]"`
    95     6. Bump versions of the JS and CSS files versions in Settings.php class to force refresh of those assets on users' installations.
    96     7. `git push origin master`
     326    5. Bump the plugin version in `src/Plugin.php` in the `\Rollbar\WordPress\Plugin::VERSION` constant.
     327    6. Add and commit the changes you made to bump the plugin version:
     328       `git add readme.txt rollbar-php-wordpress.php src/Plugin.php && git commit -m"Bump version to v[version number]"`
     329    7. Bump versions of the JS and CSS files versions in Settings.php class to force refresh of those assets on users'
     330       installations.
     331    8. `git push origin master`
    973322. Tag the new version from the `master` branch and push upstream with `git tag v[version number] && git push --tags`.
    983333. Publish a new release on [GitHub](https://github.com/rollbar/rollbar-php-wordpress/releases).
     
    101336    2. Remove the contents of `trunk/` with `rm -Rf trunk`.
    102337    3. Update the contents of `trunk/` with a clone of the tag you created in step 2.
    103         2. `git clone https://github.com/rollbar/rollbar-php-wordpress.git trunk`
    104         3. `cd trunk && git checkout tags/v[version number] && cd ..`
    105         4. `rm -Rf trunk/.git`
    106         5. `svn add trunk --force`
    107         6. `svn commit -m"Sync with GitHub repo"`
    108     4. Create the Subversion tag: `svn copy https://plugins.svn.wordpress.org/rollbar/trunk https://plugins.svn.wordpress.org/rollbar/tags/[version number] -m"Tag [version number]"`. Notice the version number in Subversion doesn't include the "v" prefix.
     338        1. `git clone https://github.com/rollbar/rollbar-php-wordpress.git trunk`
     339        2. `cd trunk && git checkout tags/v[version number] && cd ..`
     340        3. `rm -Rf trunk/.git`
     341        4. `svn add trunk --force`
     342        5. `svn commit -m"Sync with GitHub repo"`
     343    4. Create the Subversion tag:
     344       `svn copy https://plugins.svn.wordpress.org/rollbar/trunk https://plugins.svn.wordpress.org/rollbar/tags/[version number] -m"Tag [version number]"`.
     345       Notice the version number in Subversion doesn't include the "v" prefix.
    109346
    110347## Disclaimer
    111348
    112349This plugin is a community-driven contribution. All rights reserved to Rollbar.
    113 
    114 [![Rollbar](https://d26gfdfi90p7cf.cloudfront.net/rollbar-badge.144534.o.png)](https://rollbar.com/)
  • rollbar/trunk/composer.json

    r2965452 r3380353  
    33    "description": "WordPress plugin for Rollbar",
    44    "type": "wordpress-plugin",
    5     "require-dev": {
    6         "yoast/phpunit-polyfills": "^2.0",
     5    "require": {
     6        "php": "^8.1",
     7        "rollbar/rollbar": "^4.1.3"
     8    },
     9    "require-dev": {
     10        "yoast/phpunit-polyfills": "^4.0",
    711        "dealerdirect/phpcodesniffer-composer-installer": "^0.7",
    8         "squizlabs/php_codesniffer": "^3.5",
    9         "phpcompatibility/php-compatibility": "^9.3",
    10         "wp-coding-standards/wpcs": "^2.2",
     12        "squizlabs/php_codesniffer": "^3.5",
     13        "phpcompatibility/php-compatibility": "^9.3",
     14        "wp-coding-standards/wpcs": "^2.2",
    1115        "sirbrillig/phpcs-variable-analysis": "^2.8"
    1216    },
    13     "license": "GNU GPL",
     17    "license": "GPL-2.0-or-later",
    1418    "authors": [
    1519        {
    16             "name": "flowdee",
    17             "email": "hello@flowdee.de"
    18         },
    19         {
    20             "name": "Artur Moczulski",
    21             "email": "artur.moczulski@gmail.com"
    22         },
    23         {
    24           "name": "Rollbar, Inc.",
    25           "email": "support@rollbar.com",
    26           "role": "Developer"
     20            "name": "Rollbar, Inc.",
     21            "email": "support@rollbar.com",
     22            "role": "Developer"
    2723        }
    2824    ],
    29 
    3025    "support": {
    3126        "email": "support@rollbar.com"
    3227    },
    33 
    3428    "autoload": {
    35       "psr-4": {
    36         "Rollbar\\Wordpress\\": "src/",
    37         "Rollbar\\Wordpress\\Tests\\": "tests/"
    38       }
     29        "files": [
     30            "src/bootstrap.php"
     31        ],
     32        "psr-4": {
     33            "Rollbar\\WordPress\\": "src/"
     34        }
     35    },
     36    "autoload-dev": {
     37        "psr-4": {
     38            "Rollbar\\WordPress\\Tests\\": "tests/"
     39        }
    3940    },
    4041    "extra": {
    4142        "scripts-description": {
    4243            "test": "Run all tests. Wrapper around npm run test"
    43         }
    44      },
     44        },
     45        "installer-name": "rollbar"
     46    },
    4547    "scripts": {
    4648        "test": [
  • rollbar/trunk/composer.lock

    r2965452 r3380353  
    55        "This file is @generated automatically"
    66    ],
    7     "content-hash": "f9e2f4270199951bedd2eca45c9e600b",
    8     "packages": [],
     7    "content-hash": "94c1a39099682e59c5eeb17e74f916ae",
     8    "packages": [
     9        {
     10            "name": "monolog/monolog",
     11            "version": "3.9.0",
     12            "source": {
     13                "type": "git",
     14                "url": "https://github.com/Seldaek/monolog.git",
     15                "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6"
     16            },
     17            "dist": {
     18                "type": "zip",
     19                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6",
     20                "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6",
     21                "shasum": ""
     22            },
     23            "require": {
     24                "php": ">=8.1",
     25                "psr/log": "^2.0 || ^3.0"
     26            },
     27            "provide": {
     28                "psr/log-implementation": "3.0.0"
     29            },
     30            "require-dev": {
     31                "aws/aws-sdk-php": "^3.0",
     32                "doctrine/couchdb": "~1.0@dev",
     33                "elasticsearch/elasticsearch": "^7 || ^8",
     34                "ext-json": "*",
     35                "graylog2/gelf-php": "^1.4.2 || ^2.0",
     36                "guzzlehttp/guzzle": "^7.4.5",
     37                "guzzlehttp/psr7": "^2.2",
     38                "mongodb/mongodb": "^1.8",
     39                "php-amqplib/php-amqplib": "~2.4 || ^3",
     40                "php-console/php-console": "^3.1.8",
     41                "phpstan/phpstan": "^2",
     42                "phpstan/phpstan-deprecation-rules": "^2",
     43                "phpstan/phpstan-strict-rules": "^2",
     44                "phpunit/phpunit": "^10.5.17 || ^11.0.7",
     45                "predis/predis": "^1.1 || ^2",
     46                "rollbar/rollbar": "^4.0",
     47                "ruflin/elastica": "^7 || ^8",
     48                "symfony/mailer": "^5.4 || ^6",
     49                "symfony/mime": "^5.4 || ^6"
     50            },
     51            "suggest": {
     52                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
     53                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
     54                "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
     55                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
     56                "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
     57                "ext-mbstring": "Allow to work properly with unicode symbols",
     58                "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
     59                "ext-openssl": "Required to send log messages using SSL",
     60                "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
     61                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
     62                "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
     63                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
     64                "rollbar/rollbar": "Allow sending log messages to Rollbar",
     65                "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
     66            },
     67            "type": "library",
     68            "extra": {
     69                "branch-alias": {
     70                    "dev-main": "3.x-dev"
     71                }
     72            },
     73            "autoload": {
     74                "psr-4": {
     75                    "Monolog\\": "src/Monolog"
     76                }
     77            },
     78            "notification-url": "https://packagist.org/downloads/",
     79            "license": [
     80                "MIT"
     81            ],
     82            "authors": [
     83                {
     84                    "name": "Jordi Boggiano",
     85                    "email": "j.boggiano@seld.be",
     86                    "homepage": "https://seld.be"
     87                }
     88            ],
     89            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
     90            "homepage": "https://github.com/Seldaek/monolog",
     91            "keywords": [
     92                "log",
     93                "logging",
     94                "psr-3"
     95            ],
     96            "support": {
     97                "issues": "https://github.com/Seldaek/monolog/issues",
     98                "source": "https://github.com/Seldaek/monolog/tree/3.9.0"
     99            },
     100            "funding": [
     101                {
     102                    "url": "https://github.com/Seldaek",
     103                    "type": "github"
     104                },
     105                {
     106                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
     107                    "type": "tidelift"
     108                }
     109            ],
     110            "time": "2025-03-24T10:02:05+00:00"
     111        },
     112        {
     113            "name": "psr/log",
     114            "version": "3.0.2",
     115            "source": {
     116                "type": "git",
     117                "url": "https://github.com/php-fig/log.git",
     118                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
     119            },
     120            "dist": {
     121                "type": "zip",
     122                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
     123                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
     124                "shasum": ""
     125            },
     126            "require": {
     127                "php": ">=8.0.0"
     128            },
     129            "type": "library",
     130            "extra": {
     131                "branch-alias": {
     132                    "dev-master": "3.x-dev"
     133                }
     134            },
     135            "autoload": {
     136                "psr-4": {
     137                    "Psr\\Log\\": "src"
     138                }
     139            },
     140            "notification-url": "https://packagist.org/downloads/",
     141            "license": [
     142                "MIT"
     143            ],
     144            "authors": [
     145                {
     146                    "name": "PHP-FIG",
     147                    "homepage": "https://www.php-fig.org/"
     148                }
     149            ],
     150            "description": "Common interface for logging libraries",
     151            "homepage": "https://github.com/php-fig/log",
     152            "keywords": [
     153                "log",
     154                "psr",
     155                "psr-3"
     156            ],
     157            "support": {
     158                "source": "https://github.com/php-fig/log/tree/3.0.2"
     159            },
     160            "time": "2024-09-11T13:17:53+00:00"
     161        },
     162        {
     163            "name": "rollbar/rollbar",
     164            "version": "v4.1.3",
     165            "source": {
     166                "type": "git",
     167                "url": "https://github.com/rollbar/rollbar-php.git",
     168                "reference": "99eb7bd2ea1ef3be4a6e693b022911b1db1582bf"
     169            },
     170            "dist": {
     171                "type": "zip",
     172                "url": "https://api.github.com/repos/rollbar/rollbar-php/zipball/99eb7bd2ea1ef3be4a6e693b022911b1db1582bf",
     173                "reference": "99eb7bd2ea1ef3be4a6e693b022911b1db1582bf",
     174                "shasum": ""
     175            },
     176            "require": {
     177                "ext-curl": "*",
     178                "monolog/monolog": "^2 || ^3",
     179                "php": ">=8.1.0 <9.0",
     180                "psr/log": "^1 || ^2 || ^3"
     181            },
     182            "require-dev": {
     183                "mockery/mockery": "^1.5.1",
     184                "phpmd/phpmd": "^2.13",
     185                "phpunit/phpunit": "^9.6 || ^10.1",
     186                "squizlabs/php_codesniffer": "^3.7",
     187                "vimeo/psalm": "^5.9"
     188            },
     189            "suggest": {
     190                "fluent/logger": "Needed to use the 'fluent' handler for fluentd support"
     191            },
     192            "type": "library",
     193            "autoload": {
     194                "psr-4": {
     195                    "Rollbar\\": "src/"
     196                }
     197            },
     198            "notification-url": "https://packagist.org/downloads/",
     199            "license": [
     200                "MIT"
     201            ],
     202            "authors": [
     203                {
     204                    "name": "Rollbar, Inc.",
     205                    "email": "support@rollbar.com",
     206                    "role": "Developer"
     207                }
     208            ],
     209            "description": "Monitors errors and exceptions and reports them to Rollbar",
     210            "homepage": "https://github.com/rollbar/rollbar-php",
     211            "keywords": [
     212                "debugging",
     213                "errors",
     214                "exceptions",
     215                "logging",
     216                "monitoring"
     217            ],
     218            "support": {
     219                "email": "support@rollbar.com",
     220                "issues": "https://github.com/rollbar/rollbar-php/issues",
     221                "source": "https://github.com/rollbar/rollbar-php/tree/v4.1.3"
     222            },
     223            "time": "2025-04-17T19:11:14+00:00"
     224        }
     225    ],
    9226    "packages-dev": [
    10227        {
     
    85302        {
    86303            "name": "doctrine/instantiator",
    87             "version": "1.5.0",
     304            "version": "2.0.0",
    88305            "source": {
    89306                "type": "git",
    90307                "url": "https://github.com/doctrine/instantiator.git",
    91                 "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
    92             },
    93             "dist": {
    94                 "type": "zip",
    95                 "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
    96                 "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
    97                 "shasum": ""
    98             },
    99             "require": {
    100                 "php": "^7.1 || ^8.0"
    101             },
    102             "require-dev": {
    103                 "doctrine/coding-standard": "^9 || ^11",
     308                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
     309            },
     310            "dist": {
     311                "type": "zip",
     312                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
     313                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
     314                "shasum": ""
     315            },
     316            "require": {
     317                "php": "^8.1"
     318            },
     319            "require-dev": {
     320                "doctrine/coding-standard": "^11",
    104321                "ext-pdo": "*",
    105322                "ext-phar": "*",
    106                 "phpbench/phpbench": "^0.16 || ^1",
    107                 "phpstan/phpstan": "^1.4",
    108                 "phpstan/phpstan-phpunit": "^1",
    109                 "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
    110                 "vimeo/psalm": "^4.30 || ^5.4"
     323                "phpbench/phpbench": "^1.2",
     324                "phpstan/phpstan": "^1.9.4",
     325                "phpstan/phpstan-phpunit": "^1.3",
     326                "phpunit/phpunit": "^9.5.27",
     327                "vimeo/psalm": "^5.4"
    111328            },
    112329            "type": "library",
     
    135352            "support": {
    136353                "issues": "https://github.com/doctrine/instantiator/issues",
    137                 "source": "https://github.com/doctrine/instantiator/tree/1.5.0"
     354                "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
    138355            },
    139356            "funding": [
     
    151368                }
    152369            ],
    153             "time": "2022-12-30T00:15:36+00:00"
     370            "time": "2022-12-30T00:23:10+00:00"
    154371        },
    155372        {
    156373            "name": "myclabs/deep-copy",
    157             "version": "1.11.1",
     374            "version": "1.13.4",
    158375            "source": {
    159376                "type": "git",
    160377                "url": "https://github.com/myclabs/DeepCopy.git",
    161                 "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
    162             },
    163             "dist": {
    164                 "type": "zip",
    165                 "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
    166                 "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
     378                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
     379            },
     380            "dist": {
     381                "type": "zip",
     382                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
     383                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
    167384                "shasum": ""
    168385            },
     
    172389            "conflict": {
    173390                "doctrine/collections": "<1.6.8",
    174                 "doctrine/common": "<2.13.3 || >=3,<3.2.2"
     391                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
    175392            },
    176393            "require-dev": {
    177394                "doctrine/collections": "^1.6.8",
    178395                "doctrine/common": "^2.13.3 || ^3.2.2",
     396                "phpspec/prophecy": "^1.10",
    179397                "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
    180398            },
     
    202420            "support": {
    203421                "issues": "https://github.com/myclabs/DeepCopy/issues",
    204                 "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
     422                "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
    205423            },
    206424            "funding": [
     
    210428                }
    211429            ],
    212             "time": "2023-03-08T13:26:56+00:00"
     430            "time": "2025-08-01T08:46:24+00:00"
    213431        },
    214432        {
    215433            "name": "nikic/php-parser",
    216             "version": "v4.16.0",
     434            "version": "v5.6.1",
    217435            "source": {
    218436                "type": "git",
    219437                "url": "https://github.com/nikic/PHP-Parser.git",
    220                 "reference": "19526a33fb561ef417e822e85f08a00db4059c17"
    221             },
    222             "dist": {
    223                 "type": "zip",
    224                 "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
    225                 "reference": "19526a33fb561ef417e822e85f08a00db4059c17",
    226                 "shasum": ""
    227             },
    228             "require": {
     438                "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
     439            },
     440            "dist": {
     441                "type": "zip",
     442                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
     443                "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
     444                "shasum": ""
     445            },
     446            "require": {
     447                "ext-ctype": "*",
     448                "ext-json": "*",
    229449                "ext-tokenizer": "*",
    230                 "php": ">=7.0"
     450                "php": ">=7.4"
    231451            },
    232452            "require-dev": {
    233453                "ircmaxell/php-yacc": "^0.0.7",
    234                 "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
     454                "phpunit/phpunit": "^9.0"
    235455            },
    236456            "bin": [
     
    240460            "extra": {
    241461                "branch-alias": {
    242                     "dev-master": "4.9-dev"
     462                    "dev-master": "5.x-dev"
    243463                }
    244464            },
     
    264484            "support": {
    265485                "issues": "https://github.com/nikic/PHP-Parser/issues",
    266                 "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
    267             },
    268             "time": "2023-06-25T14:52:30+00:00"
     486                "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
     487            },
     488            "time": "2025-08-13T20:13:15+00:00"
    269489        },
    270490        {
    271491            "name": "phar-io/manifest",
    272             "version": "2.0.3",
     492            "version": "2.0.4",
    273493            "source": {
    274494                "type": "git",
    275495                "url": "https://github.com/phar-io/manifest.git",
    276                 "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
    277             },
    278             "dist": {
    279                 "type": "zip",
    280                 "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
    281                 "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
     496                "reference": "54750ef60c58e43759730615a392c31c80e23176"
     497            },
     498            "dist": {
     499                "type": "zip",
     500                "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
     501                "reference": "54750ef60c58e43759730615a392c31c80e23176",
    282502                "shasum": ""
    283503            },
    284504            "require": {
    285505                "ext-dom": "*",
     506                "ext-libxml": "*",
    286507                "ext-phar": "*",
    287508                "ext-xmlwriter": "*",
     
    324545            "support": {
    325546                "issues": "https://github.com/phar-io/manifest/issues",
    326                 "source": "https://github.com/phar-io/manifest/tree/2.0.3"
    327             },
    328             "time": "2021-07-20T11:28:43+00:00"
     547                "source": "https://github.com/phar-io/manifest/tree/2.0.4"
     548            },
     549            "funding": [
     550                {
     551                    "url": "https://github.com/theseer",
     552                    "type": "github"
     553                }
     554            ],
     555            "time": "2024-03-03T12:33:53+00:00"
    329556        },
    330557        {
     
    443670        {
    444671            "name": "phpunit/php-code-coverage",
    445             "version": "9.2.26",
     672            "version": "9.2.32",
    446673            "source": {
    447674                "type": "git",
    448675                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
    449                 "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
    450             },
    451             "dist": {
    452                 "type": "zip",
    453                 "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
    454                 "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
     676                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
     677            },
     678            "dist": {
     679                "type": "zip",
     680                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
     681                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
    455682                "shasum": ""
    456683            },
     
    459686                "ext-libxml": "*",
    460687                "ext-xmlwriter": "*",
    461                 "nikic/php-parser": "^4.15",
     688                "nikic/php-parser": "^4.19.1 || ^5.1.0",
    462689                "php": ">=7.3",
    463                 "phpunit/php-file-iterator": "^3.0.3",
    464                 "phpunit/php-text-template": "^2.0.2",
    465                 "sebastian/code-unit-reverse-lookup": "^2.0.2",
    466                 "sebastian/complexity": "^2.0",
    467                 "sebastian/environment": "^5.1.2",
    468                 "sebastian/lines-of-code": "^1.0.3",
    469                 "sebastian/version": "^3.0.1",
    470                 "theseer/tokenizer": "^1.2.0"
    471             },
    472             "require-dev": {
    473                 "phpunit/phpunit": "^9.3"
     690                "phpunit/php-file-iterator": "^3.0.6",
     691                "phpunit/php-text-template": "^2.0.4",
     692                "sebastian/code-unit-reverse-lookup": "^2.0.3",
     693                "sebastian/complexity": "^2.0.3",
     694                "sebastian/environment": "^5.1.5",
     695                "sebastian/lines-of-code": "^1.0.4",
     696                "sebastian/version": "^3.0.2",
     697                "theseer/tokenizer": "^1.2.3"
     698            },
     699            "require-dev": {
     700                "phpunit/phpunit": "^9.6"
    474701            },
    475702            "suggest": {
     
    480707            "extra": {
    481708                "branch-alias": {
    482                     "dev-master": "9.2-dev"
     709                    "dev-main": "9.2.x-dev"
    483710                }
    484711            },
     
    508735            "support": {
    509736                "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
    510                 "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
     737                "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
     738                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
    511739            },
    512740            "funding": [
     
    516744                }
    517745            ],
    518             "time": "2023-03-06T12:58:08+00:00"
     746            "time": "2024-08-22T04:23:01+00:00"
    519747        },
    520748        {
     
    761989        {
    762990            "name": "phpunit/phpunit",
    763             "version": "9.6.10",
     991            "version": "9.6.24",
    764992            "source": {
    765993                "type": "git",
    766994                "url": "https://github.com/sebastianbergmann/phpunit.git",
    767                 "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328"
    768             },
    769             "dist": {
    770                 "type": "zip",
    771                 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328",
    772                 "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328",
    773                 "shasum": ""
    774             },
    775             "require": {
    776                 "doctrine/instantiator": "^1.3.1 || ^2",
     995                "reference": "ea49afa29aeea25ea7bf9de9fdd7cab163cc0701"
     996            },
     997            "dist": {
     998                "type": "zip",
     999                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea49afa29aeea25ea7bf9de9fdd7cab163cc0701",
     1000                "reference": "ea49afa29aeea25ea7bf9de9fdd7cab163cc0701",
     1001                "shasum": ""
     1002            },
     1003            "require": {
     1004                "doctrine/instantiator": "^1.5.0 || ^2",
    7771005                "ext-dom": "*",
    7781006                "ext-json": "*",
     
    7811009                "ext-xml": "*",
    7821010                "ext-xmlwriter": "*",
    783                 "myclabs/deep-copy": "^1.10.1",
    784                 "phar-io/manifest": "^2.0.3",
    785                 "phar-io/version": "^3.0.2",
     1011                "myclabs/deep-copy": "^1.13.4",
     1012                "phar-io/manifest": "^2.0.4",
     1013                "phar-io/version": "^3.2.1",
    7861014                "php": ">=7.3",
    787                 "phpunit/php-code-coverage": "^9.2.13",
    788                 "phpunit/php-file-iterator": "^3.0.5",
     1015                "phpunit/php-code-coverage": "^9.2.32",
     1016                "phpunit/php-file-iterator": "^3.0.6",
    7891017                "phpunit/php-invoker": "^3.1.1",
    790                 "phpunit/php-text-template": "^2.0.3",
    791                 "phpunit/php-timer": "^5.0.2",
    792                 "sebastian/cli-parser": "^1.0.1",
    793                 "sebastian/code-unit": "^1.0.6",
    794                 "sebastian/comparator": "^4.0.8",
    795                 "sebastian/diff": "^4.0.3",
    796                 "sebastian/environment": "^5.1.3",
    797                 "sebastian/exporter": "^4.0.5",
    798                 "sebastian/global-state": "^5.0.1",
    799                 "sebastian/object-enumerator": "^4.0.3",
    800                 "sebastian/resource-operations": "^3.0.3",
    801                 "sebastian/type": "^3.2",
     1018                "phpunit/php-text-template": "^2.0.4",
     1019                "phpunit/php-timer": "^5.0.3",
     1020                "sebastian/cli-parser": "^1.0.2",
     1021                "sebastian/code-unit": "^1.0.8",
     1022                "sebastian/comparator": "^4.0.9",
     1023                "sebastian/diff": "^4.0.6",
     1024                "sebastian/environment": "^5.1.5",
     1025                "sebastian/exporter": "^4.0.6",
     1026                "sebastian/global-state": "^5.0.8",
     1027                "sebastian/object-enumerator": "^4.0.4",
     1028                "sebastian/resource-operations": "^3.0.4",
     1029                "sebastian/type": "^3.2.1",
    8021030                "sebastian/version": "^3.0.2"
    8031031            },
     
    8441072                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
    8451073                "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
    846                 "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10"
     1074                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.24"
    8471075            },
    8481076            "funding": [
     
    8561084                },
    8571085                {
     1086                    "url": "https://liberapay.com/sebastianbergmann",
     1087                    "type": "liberapay"
     1088                },
     1089                {
     1090                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
     1091                    "type": "thanks_dev"
     1092                },
     1093                {
    8581094                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
    8591095                    "type": "tidelift"
    8601096                }
    8611097            ],
    862             "time": "2023-07-10T04:04:23+00:00"
     1098            "time": "2025-08-10T08:32:42+00:00"
    8631099        },
    8641100        {
    8651101            "name": "sebastian/cli-parser",
    866             "version": "1.0.1",
     1102            "version": "1.0.2",
    8671103            "source": {
    8681104                "type": "git",
    8691105                "url": "https://github.com/sebastianbergmann/cli-parser.git",
    870                 "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
    871             },
    872             "dist": {
    873                 "type": "zip",
    874                 "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
    875                 "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
     1106                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
     1107            },
     1108            "dist": {
     1109                "type": "zip",
     1110                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
     1111                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
    8761112                "shasum": ""
    8771113            },
     
    9081144            "support": {
    9091145                "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
    910                 "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
     1146                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
    9111147            },
    9121148            "funding": [
     
    9161152                }
    9171153            ],
    918             "time": "2020-09-28T06:08:49+00:00"
     1154            "time": "2024-03-02T06:27:43+00:00"
    9191155        },
    9201156        {
     
    10311267        {
    10321268            "name": "sebastian/comparator",
    1033             "version": "4.0.8",
     1269            "version": "4.0.9",
    10341270            "source": {
    10351271                "type": "git",
    10361272                "url": "https://github.com/sebastianbergmann/comparator.git",
    1037                 "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
    1038             },
    1039             "dist": {
    1040                 "type": "zip",
    1041                 "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
    1042                 "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
     1273                "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5"
     1274            },
     1275            "dist": {
     1276                "type": "zip",
     1277                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
     1278                "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
    10431279                "shasum": ""
    10441280            },
     
    10931329            "support": {
    10941330                "issues": "https://github.com/sebastianbergmann/comparator/issues",
    1095                 "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
     1331                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9"
    10961332            },
    10971333            "funding": [
     
    10991335                    "url": "https://github.com/sebastianbergmann",
    11001336                    "type": "github"
    1101                 }
    1102             ],
    1103             "time": "2022-09-14T12:41:17+00:00"
     1337                },
     1338                {
     1339                    "url": "https://liberapay.com/sebastianbergmann",
     1340                    "type": "liberapay"
     1341                },
     1342                {
     1343                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
     1344                    "type": "thanks_dev"
     1345                },
     1346                {
     1347                    "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
     1348                    "type": "tidelift"
     1349                }
     1350            ],
     1351            "time": "2025-08-10T06:51:50+00:00"
    11041352        },
    11051353        {
    11061354            "name": "sebastian/complexity",
    1107             "version": "2.0.2",
     1355            "version": "2.0.3",
    11081356            "source": {
    11091357                "type": "git",
    11101358                "url": "https://github.com/sebastianbergmann/complexity.git",
    1111                 "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
    1112             },
    1113             "dist": {
    1114                 "type": "zip",
    1115                 "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
    1116                 "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
    1117                 "shasum": ""
    1118             },
    1119             "require": {
    1120                 "nikic/php-parser": "^4.7",
     1359                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
     1360            },
     1361            "dist": {
     1362                "type": "zip",
     1363                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
     1364                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
     1365                "shasum": ""
     1366            },
     1367            "require": {
     1368                "nikic/php-parser": "^4.18 || ^5.0",
    11211369                "php": ">=7.3"
    11221370            },
     
    11501398            "support": {
    11511399                "issues": "https://github.com/sebastianbergmann/complexity/issues",
    1152                 "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
     1400                "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
    11531401            },
    11541402            "funding": [
     
    11581406                }
    11591407            ],
    1160             "time": "2020-10-26T15:52:27+00:00"
     1408            "time": "2023-12-22T06:19:30+00:00"
    11611409        },
    11621410        {
    11631411            "name": "sebastian/diff",
    1164             "version": "4.0.5",
     1412            "version": "4.0.6",
    11651413            "source": {
    11661414                "type": "git",
    11671415                "url": "https://github.com/sebastianbergmann/diff.git",
    1168                 "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
    1169             },
    1170             "dist": {
    1171                 "type": "zip",
    1172                 "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
    1173                 "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
     1416                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
     1417            },
     1418            "dist": {
     1419                "type": "zip",
     1420                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
     1421                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
    11741422                "shasum": ""
    11751423            },
     
    12161464            "support": {
    12171465                "issues": "https://github.com/sebastianbergmann/diff/issues",
    1218                 "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
     1466                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
    12191467            },
    12201468            "funding": [
     
    12241472                }
    12251473            ],
    1226             "time": "2023-05-07T05:35:17+00:00"
     1474            "time": "2024-03-02T06:30:58+00:00"
    12271475        },
    12281476        {
     
    12911539        {
    12921540            "name": "sebastian/exporter",
    1293             "version": "4.0.5",
     1541            "version": "4.0.6",
    12941542            "source": {
    12951543                "type": "git",
    12961544                "url": "https://github.com/sebastianbergmann/exporter.git",
    1297                 "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
    1298             },
    1299             "dist": {
    1300                 "type": "zip",
    1301                 "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
    1302                 "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
     1545                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
     1546            },
     1547            "dist": {
     1548                "type": "zip",
     1549                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
     1550                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
    13031551                "shasum": ""
    13041552            },
     
    13561604            "support": {
    13571605                "issues": "https://github.com/sebastianbergmann/exporter/issues",
    1358                 "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
     1606                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
    13591607            },
    13601608            "funding": [
     
    13641612                }
    13651613            ],
    1366             "time": "2022-09-14T06:03:37+00:00"
     1614            "time": "2024-03-02T06:33:00+00:00"
    13671615        },
    13681616        {
    13691617            "name": "sebastian/global-state",
    1370             "version": "5.0.5",
     1618            "version": "5.0.8",
    13711619            "source": {
    13721620                "type": "git",
    13731621                "url": "https://github.com/sebastianbergmann/global-state.git",
    1374                 "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
    1375             },
    1376             "dist": {
    1377                 "type": "zip",
    1378                 "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
    1379                 "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
     1622                "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6"
     1623            },
     1624            "dist": {
     1625                "type": "zip",
     1626                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
     1627                "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
    13801628                "shasum": ""
    13811629            },
     
    14201668            "support": {
    14211669                "issues": "https://github.com/sebastianbergmann/global-state/issues",
    1422                 "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
     1670                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8"
    14231671            },
    14241672            "funding": [
     
    14261674                    "url": "https://github.com/sebastianbergmann",
    14271675                    "type": "github"
    1428                 }
    1429             ],
    1430             "time": "2022-02-14T08:28:10+00:00"
     1676                },
     1677                {
     1678                    "url": "https://liberapay.com/sebastianbergmann",
     1679                    "type": "liberapay"
     1680                },
     1681                {
     1682                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
     1683                    "type": "thanks_dev"
     1684                },
     1685                {
     1686                    "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
     1687                    "type": "tidelift"
     1688                }
     1689            ],
     1690            "time": "2025-08-10T07:10:35+00:00"
    14311691        },
    14321692        {
    14331693            "name": "sebastian/lines-of-code",
    1434             "version": "1.0.3",
     1694            "version": "1.0.4",
    14351695            "source": {
    14361696                "type": "git",
    14371697                "url": "https://github.com/sebastianbergmann/lines-of-code.git",
    1438                 "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
    1439             },
    1440             "dist": {
    1441                 "type": "zip",
    1442                 "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
    1443                 "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
    1444                 "shasum": ""
    1445             },
    1446             "require": {
    1447                 "nikic/php-parser": "^4.6",
     1698                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
     1699            },
     1700            "dist": {
     1701                "type": "zip",
     1702                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
     1703                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
     1704                "shasum": ""
     1705            },
     1706            "require": {
     1707                "nikic/php-parser": "^4.18 || ^5.0",
    14481708                "php": ">=7.3"
    14491709            },
     
    14771737            "support": {
    14781738                "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
    1479                 "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
     1739                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
    14801740            },
    14811741            "funding": [
     
    14851745                }
    14861746            ],
    1487             "time": "2020-11-28T06:42:11+00:00"
     1747            "time": "2023-12-22T06:20:34+00:00"
    14881748        },
    14891749        {
     
    16011861        {
    16021862            "name": "sebastian/recursion-context",
    1603             "version": "4.0.5",
     1863            "version": "4.0.6",
    16041864            "source": {
    16051865                "type": "git",
    16061866                "url": "https://github.com/sebastianbergmann/recursion-context.git",
    1607                 "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
    1608             },
    1609             "dist": {
    1610                 "type": "zip",
    1611                 "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
    1612                 "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
     1867                "reference": "539c6691e0623af6dc6f9c20384c120f963465a0"
     1868            },
     1869            "dist": {
     1870                "type": "zip",
     1871                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0",
     1872                "reference": "539c6691e0623af6dc6f9c20384c120f963465a0",
    16131873                "shasum": ""
    16141874            },
     
    16521912            "support": {
    16531913                "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
    1654                 "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
     1914                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6"
    16551915            },
    16561916            "funding": [
     
    16581918                    "url": "https://github.com/sebastianbergmann",
    16591919                    "type": "github"
    1660                 }
    1661             ],
    1662             "time": "2023-02-03T06:07:39+00:00"
     1920                },
     1921                {
     1922                    "url": "https://liberapay.com/sebastianbergmann",
     1923                    "type": "liberapay"
     1924                },
     1925                {
     1926                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
     1927                    "type": "thanks_dev"
     1928                },
     1929                {
     1930                    "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
     1931                    "type": "tidelift"
     1932                }
     1933            ],
     1934            "time": "2025-08-10T06:57:39+00:00"
    16631935        },
    16641936        {
    16651937            "name": "sebastian/resource-operations",
    1666             "version": "3.0.3",
     1938            "version": "3.0.4",
    16671939            "source": {
    16681940                "type": "git",
    16691941                "url": "https://github.com/sebastianbergmann/resource-operations.git",
    1670                 "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
    1671             },
    1672             "dist": {
    1673                 "type": "zip",
    1674                 "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
    1675                 "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
     1942                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
     1943            },
     1944            "dist": {
     1945                "type": "zip",
     1946                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
     1947                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
    16761948                "shasum": ""
    16771949            },
     
    16851957            "extra": {
    16861958                "branch-alias": {
    1687                     "dev-master": "3.0-dev"
     1959                    "dev-main": "3.0-dev"
    16881960                }
    16891961            },
     
    17061978            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
    17071979            "support": {
    1708                 "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
    1709                 "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
     1980                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
    17101981            },
    17111982            "funding": [
     
    17151986                }
    17161987            ],
    1717             "time": "2020-09-28T06:45:17+00:00"
     1988            "time": "2024-03-14T16:00:52+00:00"
    17181989        },
    17191990        {
     
    18282099        {
    18292100            "name": "sirbrillig/phpcs-variable-analysis",
    1830             "version": "v2.11.16",
     2101            "version": "v2.12.0",
    18312102            "source": {
    18322103                "type": "git",
    18332104                "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git",
    1834                 "reference": "dc5582dc5a93a235557af73e523c389aac9a8e88"
    1835             },
    1836             "dist": {
    1837                 "type": "zip",
    1838                 "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/dc5582dc5a93a235557af73e523c389aac9a8e88",
    1839                 "reference": "dc5582dc5a93a235557af73e523c389aac9a8e88",
     2105                "reference": "4debf5383d9ade705e0a25121f16c3fecaf433a7"
     2106            },
     2107            "dist": {
     2108                "type": "zip",
     2109                "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/4debf5383d9ade705e0a25121f16c3fecaf433a7",
     2110                "reference": "4debf5383d9ade705e0a25121f16c3fecaf433a7",
    18402111                "shasum": ""
    18412112            },
     
    18482119                "phpcsstandards/phpcsdevcs": "^1.1",
    18492120                "phpstan/phpstan": "^1.7",
    1850                 "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0",
    1851                 "sirbrillig/phpcs-import-detection": "^1.1",
    1852                 "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta"
     2121                "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3",
     2122                "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0"
    18532123            },
    18542124            "type": "phpcodesniffer-standard",
     
    18822152                "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki"
    18832153            },
    1884             "time": "2023-03-31T16:46:32+00:00"
     2154            "time": "2025-03-17T16:17:38+00:00"
    18852155        },
    18862156        {
    18872157            "name": "squizlabs/php_codesniffer",
    1888             "version": "3.7.2",
    1889             "source": {
    1890                 "type": "git",
    1891                 "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
    1892                 "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
    1893             },
    1894             "dist": {
    1895                 "type": "zip",
    1896                 "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
    1897                 "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
     2158            "version": "3.13.2",
     2159            "source": {
     2160                "type": "git",
     2161                "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
     2162                "reference": "5b5e3821314f947dd040c70f7992a64eac89025c"
     2163            },
     2164            "dist": {
     2165                "type": "zip",
     2166                "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c",
     2167                "reference": "5b5e3821314f947dd040c70f7992a64eac89025c",
    18982168                "shasum": ""
    18992169            },
     
    19052175            },
    19062176            "require-dev": {
    1907                 "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
     2177                "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
    19082178            },
    19092179            "bin": [
    1910                 "bin/phpcs",
    1911                 "bin/phpcbf"
     2180                "bin/phpcbf",
     2181                "bin/phpcs"
    19122182            ],
    19132183            "type": "library",
     
    19242194                {
    19252195                    "name": "Greg Sherwood",
    1926                     "role": "lead"
     2196                    "role": "Former lead"
     2197                },
     2198                {
     2199                    "name": "Juliette Reinders Folmer",
     2200                    "role": "Current lead"
     2201                },
     2202                {
     2203                    "name": "Contributors",
     2204                    "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
    19272205                }
    19282206            ],
    19292207            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
    1930             "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
     2208            "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
    19312209            "keywords": [
    19322210                "phpcs",
     
    19352213            ],
    19362214            "support": {
    1937                 "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
    1938                 "source": "https://github.com/squizlabs/PHP_CodeSniffer",
    1939                 "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
    1940             },
    1941             "time": "2023-02-22T23:07:41+00:00"
     2215                "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
     2216                "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
     2217                "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
     2218                "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
     2219            },
     2220            "funding": [
     2221                {
     2222                    "url": "https://github.com/PHPCSStandards",
     2223                    "type": "github"
     2224                },
     2225                {
     2226                    "url": "https://github.com/jrfnl",
     2227                    "type": "github"
     2228                },
     2229                {
     2230                    "url": "https://opencollective.com/php_codesniffer",
     2231                    "type": "open_collective"
     2232                },
     2233                {
     2234                    "url": "https://thanks.dev/u/gh/phpcsstandards",
     2235                    "type": "thanks_dev"
     2236                }
     2237            ],
     2238            "time": "2025-06-17T22:17:01+00:00"
    19422239        },
    19432240        {
    19442241            "name": "theseer/tokenizer",
    1945             "version": "1.2.1",
     2242            "version": "1.2.3",
    19462243            "source": {
    19472244                "type": "git",
    19482245                "url": "https://github.com/theseer/tokenizer.git",
    1949                 "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
    1950             },
    1951             "dist": {
    1952                 "type": "zip",
    1953                 "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
    1954                 "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
     2246                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
     2247            },
     2248            "dist": {
     2249                "type": "zip",
     2250                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
     2251                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
    19552252                "shasum": ""
    19562253            },
     
    19812278            "support": {
    19822279                "issues": "https://github.com/theseer/tokenizer/issues",
    1983                 "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
     2280                "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
    19842281            },
    19852282            "funding": [
     
    19892286                }
    19902287            ],
    1991             "time": "2021-07-28T10:34:58+00:00"
     2288            "time": "2024-03-03T12:36:25+00:00"
    19922289        },
    19932290        {
     
    20442341        {
    20452342            "name": "yoast/phpunit-polyfills",
    2046             "version": "2.0.0",
     2343            "version": "4.0.0",
    20472344            "source": {
    20482345                "type": "git",
    20492346                "url": "https://github.com/Yoast/PHPUnit-Polyfills.git",
    2050                 "reference": "c758753e8f9dac251fed396a73c8305af3f17922"
    2051             },
    2052             "dist": {
    2053                 "type": "zip",
    2054                 "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/c758753e8f9dac251fed396a73c8305af3f17922",
    2055                 "reference": "c758753e8f9dac251fed396a73c8305af3f17922",
    2056                 "shasum": ""
    2057             },
    2058             "require": {
    2059                 "php": ">=5.6",
    2060                 "phpunit/phpunit": "^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0"
    2061             },
    2062             "require-dev": {
    2063                 "yoast/yoastcs": "^2.3.0"
    2064             },
    2065             "type": "library",
    2066             "extra": {
    2067                 "branch-alias": {
    2068                     "dev-main": "2.x-dev"
     2347                "reference": "134921bfca9b02d8f374c48381451da1d98402f9"
     2348            },
     2349            "dist": {
     2350                "type": "zip",
     2351                "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/134921bfca9b02d8f374c48381451da1d98402f9",
     2352                "reference": "134921bfca9b02d8f374c48381451da1d98402f9",
     2353                "shasum": ""
     2354            },
     2355            "require": {
     2356                "php": ">=7.1",
     2357                "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0 || ^11.0 || ^12.0"
     2358            },
     2359            "require-dev": {
     2360                "php-parallel-lint/php-console-highlighter": "^1.0.0",
     2361                "php-parallel-lint/php-parallel-lint": "^1.4.0",
     2362                "yoast/yoastcs": "^3.1.0"
     2363            },
     2364            "type": "library",
     2365            "extra": {
     2366                "branch-alias": {
     2367                    "dev-main": "4.x-dev"
    20692368                }
    20702369            },
     
    20982397            "support": {
    20992398                "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues",
     2399                "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy",
    21002400                "source": "https://github.com/Yoast/PHPUnit-Polyfills"
    21012401            },
    2102             "time": "2023-06-06T20:28:24+00:00"
     2402            "time": "2025-02-09T18:58:54+00:00"
    21032403        }
    21042404    ],
    21052405    "aliases": [],
    21062406    "minimum-stability": "stable",
    2107     "stability-flags": [],
     2407    "stability-flags": {},
    21082408    "prefer-stable": false,
    21092409    "prefer-lowest": false,
    2110     "platform": [],
    2111     "platform-dev": [],
    2112     "plugin-api-version": "2.3.0"
     2410    "platform": {
     2411        "php": "^8.1"
     2412    },
     2413    "platform-dev": {},
     2414    "plugin-api-version": "2.6.0"
    21132415}
  • rollbar/trunk/mu-plugin/rollbar-mu-plugin.php

    r2034564 r3380353  
    22
    33/**
    4  * Plugin Name: Rollbar PHP Wordpress Must Use Plugin
     4 * Plugin Name: Rollbar PHP WordPress Must Use Plugin
    55 * Plugin URI: https://github.com/rollbar/rollbar-php-wordpress
    6  * Description: "Must-use" proxy plugin for Rollbar PHP Wordpress.
    7  * Author:          Rollbar
    8  * Author URI:      https://rollbar.com
     6 * Description: "Must-use" proxy plugin for Rollbar PHP WordPress.
     7 * Author: Rollbar
     8 * Author URI: https://rollbar.com
    99 */
    10  
    11 $rollbar_plugin = __DIR__ . '/../plugins/rollbar/rollbar-php-wordpress.php';
    1210
    13 if ( ! file_exists( $rollbar_plugin ) ) {
    14     return;
     11$rollbar_plugin = __DIR__ . '/../plugins/rollbar/rollbar.php';
     12
     13if (!file_exists($rollbar_plugin)) {
     14    return;
    1515}
    1616
  • rollbar/trunk/readme.txt

    r2966780 r3380353  
    11=== Rollbar ===
    2 Contributors: arturmoczulski, jorbin
     2Contributors: arturmoczulski, jorbin, danielmorell
    33Tags: rollbar, full stack, error, tracking, error tracking, error reporting, reporting, debug
    4 Requires at least: 4.4.0
    5 Tested up to: 6.3.1
    6 Stable tag: 2.7.1
     4Requires at least: 6.5.0
     5Tested up to: 6.8
     6Requires PHP: 8.1
     7Stable tag: 3.0.0
    78License: GPLv2 or later
    89License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    1112
    1213== Description ==
     14
    1315Rollbar collects errors that happen in your application, notifies you, and analyzes them so you can debug and fix them.
    14 
    1516This plugin integrates Rollbar into your WordPress installation.
    1617
    17 Find out [how Rollbar can help you decrease development and maintenance costs](https://rollbar.com/features/).
    18 
    19 See [real companies improving their development workflow thanks to Rollbar](https://rollbar.com/customers/).
    20 
    2118= Features =
    2219
    23 *   PHP & Javascript error logging
    24 *   Define an environment for each single WordPress installation or Multisite blog
    25 *   Specify your desired logging level
     20*   PHP & JavaScript error logging.
     21*   Define an environment for each single WordPress installation or Multisite blog.
     22*   Specify your desired logging level.
    2623*   Regular updates and improvements!
    2724
    28 > <strong>Please note</strong><br>
    29 > In order to use this plugin, a [Rollbar account](https://rollbar.com/) is required.
     25**Please note:**
     26In order to use this plugin, a [Rollbar account](https://rollbar.com/) is required.
    3027
    3128= Support =
    3229
    33 * Browse [issue tracker](https://github.com/rollbar/rollbar-php-wordpress/issues) on GitHub and report new issues
    34 * If you run into any issues, please email us at [support@rollbar.com](mailto:support@rollbar.com)
     30* Browse [issue tracker](https://github.com/rollbar/rollbar-php-wordpress/issues) on GitHub and report new issues.
     31* If you run into any issues, please email us at [support@rollbar.com](mailto:support@rollbar.com).
    3532* For bug reports, please [open an issue on GitHub](https://github.com/rollbar/rollbar-php-wordpress/issues/new).
    3633
     
    4744The installation and configuration of the plugin are as simple as it can be.
    4845
    49 = Through [WordPress Plugin directory](https://wordpress.org/plugins/rollbar/) =
    50 
    51 The easiest way to install the plugin is from the WordPress Plugin directory. If you have an existing WordPress installation and you want to add Rollbar:
     46= Through WordPress Plugin directory =
     47
     48The easiest way to install the plugin is from the WordPress Plugin directory. If you have an existing WordPress
     49installation, and you want to add Rollbar:
    5250
    53511. In your WordPress administration panel go to `Plugins` → `Add New`.
    54522. Search for "Rollbar" and find `Rollbar` by Rollbar in the search results.
    55533. Click `Install Now` next to the `Rollbar` plugin.
    56 4. In `Plugins` → `Installed plugins` find `Rollbar` and click `activate` underneath.
    57 5. Log into your [Rollbar account dashboard](https://rollbar.com/login/).
    58 6. Go to `Settings` → `Project Access Tokens`.
    59 7. Copy the token value under `post_client_item` and `post_server_item`.
    60 8. Navigate to `Tools` → `Rollbar`.
    61 9. Enable `PHP error logging` and/or `Javascript error logging` depending on your needs.
    62 10. Paste the tokens you copied in step 7 in `Access Token` section.
    63 11. Provide the name of your environment in `Environment`. By default, the environment will be taken from `WP_ENV` environment variable if it's set otherwise it's blank. We recommend to fill this out either with `development` or `production`.
    64 12. Pick a minimum logging level. Only errors at that or higher level will be reported. For reference: [PHP Manual: Predefined Error Constants](http://php.net/manual/en/errorfunc.constants.php).
    65 13. Click `Save Changes`.
    66 
    67 **Warning**: This installation method might not be suitable for complex WordPress projects. The plugin installed this way will be self-contained and include all of the required dependencies for itself and `rollbar/rollbar-php` library. In complex projects, this might lead to version conflicts between dependencies and other plugins/packages. If this is an issue in your project, we recommend the "Advanced" installation method. For more information why this might be important for you, read [Using Composer with WordPress]().
    68 
    69 = Through [wpackagist](https://wpackagist.org/) (if you manage your project with Composer) *recommended* =
    70 
    71 This is a recommended way to install Rollbar plugin for advanced projects. This way ensures the plugin and all of its' dependencies are managed by Composer.
    72 
    73 1. If your WordPress project is not managed with Composer yet, we suggest looking into upgrading your WordPress: [Using Composer with WordPress]().
    74 2. In your `composer.json` add `wpackagist-plugin/rollbar` to your `require` section, i.e.:
     544. In `Plugins` → `Installed plugins` find `Rollbar` and click `Activate` underneath.
     55
     56**Warning**: This installation method might not be suitable for complex WordPress projects. The plugin installed this
     57way will be self-contained and include all of the required dependencies for itself and the `rollbar/rollbar-php`
     58library. In complex projects, this might lead to version conflicts between dependencies and other plugins/packages. If
     59this is an issue in your project, we recommend the "Packagist" installation method.
     60
     61= Through Packagist =
     62
     63*Note: this only works if your WordPress project is managed with Composer.
     64Read [Using Composer with WordPress](https://roots.io/using-composer-with-wordpress/) for more details.*
     65
     66This is a recommended way to install the Rollbar plugin for advanced projects. This way ensures the plugin and all of
     67its dependencies are managed by Composer.
     68
     69You can install the plugin by running the following command in the root directory of your WordPress project:
     70
     71```txt
     72composer require rollbar/rollbar-php-wordpress:^3.0
    7573```
    76   "require": {
    77     "php": ">=5.5",
    78     ...,
    79     "wpackagist-plugin/rollbar": "*"
    80   }
     74
     75= Through WPackagist =
     76
     77*Note: if your WordPress project is managed with Composer, we strongly recommend installing the plugin through
     78Packagist instead.*
     79
     80*Installing the plugin from wpackagist.org instead of packagist.org will result in the plugin being managed by
     81Composer. However, the downside is that it's dependencies will not be managed by composer. Instead they will be packaged
     82in the plugin's `vendor` directory not in your project's `vendor` directory. This has the potential to cause name
     83collisions if other plugins or your project use different versions of the same dependencies.*
     84
     85To install the plugin from wpackagist.org run the following steps command in the root directory of your WordPress
     86project:
     87
     88```txt
     89composer require wpackagist-plugin/rollbar
    8190```
    82 3. Issue command `composer install` in the root directory of your WordPress project.
    83 4. In `Plugins` → `Installed plugins` find `Rollbar` and click `Activate` underneath.
    84 5. Log into your [Rollbar account dashboard](https://rollbar.com/login/).
    85 6. Go to `Settings` → `Project Access Tokens`.
    86 7. Copy the token value under `post_client_item` and `post_server_item`.
    87 8. Navigate to `Tools` → `Rollbar`.
    88 9. Enable `PHP error logging` and/or `Javascript error logging` depending on your needs.
    89 10. Paste the tokens you copied in step 7 in `Access Token` section.
    90 11. Provide the name of your environment in `Environment`. By default, the environment will be taken from `WP_ENV` environment variable if it's set otherwise it's blank.
    91 12. Pick a minimum logging level. Only errors at that or higher level will be reported. For reference: [PHP Manual: Predefined Error Constants](http://php.net/manual/en/errorfunc.constants.php).
    92 13. Click `Save Changes`.
     91
     92= Configuration =
     93
     94The plugin can be configured in the WordPress Admin or programmatically.
     95
     96**WordPress Admin**
     97
     98The plugin provides a settings page in the WordPress Admin that allows you to configure the plugin. This settings page
     99can be disabled by setting the `ROLLBAR_DISABLE_ADMIN` constant to `true` in your `wp-config.php` file.
     100
     1011. In `Plugins` → `Installed plugins` find `Rollbar` and click `Activate` underneath.
     1022. Log into your [Rollbar account dashboard](https://rollbar.com/login/):
     103    1. Go to `Settings` → `Project Access Tokens`.
     104    2. Copy the token value under `post_client_item` and `post_server_item`.
     1053. In WordPress, navigate to `Settings` → `Rollbar`:
     106    1. Enable `PHP error logging` and/or `Javascript error logging` depending on your needs.
     107    2. Paste the tokens you copied in step 7 in `Access Token` section.
     108    3. Provide the name of your environment in `Environment`. By default, the environment will be taken from `WP_ENV`
     109       environment variable if it's set otherwise it's blank. We recommend to fill this out either with `development` or
     110       `production`.
     111    4. Pick a minimum logging level. Only errors at that or higher level will be reported. For
     112       reference: [PHP Manual: Predefined Error Constants](http://php.net/manual/en/errorfunc.constants.php).
     113    5. Click `Save Changes`.
     114
     115**Programmatic Configuration**
     116
     117The plugin can also be configured programmatically. This is useful if you want to configure the plugin in a more
     118advanced way or if you want to disable the admin settings page.
     119
     120```php
     121// wp-config.php
     122
     123// Configure the plugin.
     124define( 'ROLLBAR_SETTINGS', [
     125    'php_logging_enabled' => true,
     126    'server_side_access_token' => '<your token>',
     127    'js_logging_enabled' => true,
     128    'client_side_access_token' => '<your client token>',
     129    'environment' => 'development',
     130    'included_errno' => E_ERROR,
     131    'enable_person_reporting' => true,
     132] );
     133
     134// Optional: disable the admin settings page so the plugin is configured only programmatically.
     135define( 'ROLLBAR_DISABLE_ADMIN', true );
     136```
    93137
    94138== Frequently Asked Questions ==
    95139
    96140= Multisite supported? =
    97 Yes of course. Additionally, you can assign different environments to each of your blogs.
     141Yes, of course. Additionally, you can assign different environments to each of your blogs.
    98142
    99143= I have a complex WordPress project and use composer for managing dependencies. Is your plugin composer friendly? =
    100 Yes. It's actually the recommended method of installation.
     144Yes. It's actually the recommended method of installation. You can install the `rollbar/rollbar-php-wordpress` package
     145using composer.
    101146
    102147== Screenshots ==
    103148
    104 1. Settings page
     1491. Settings page.
    105150
    106151== Changelog ==
     152
     153= Version 3.0.0 (pending)
     154* Fixed CSRF vulnerability.
     155* Removed support for PHP 8.0 and below.
     156* Updated and improved the settings page.
     157* Updated the Rollbar core PHP SDK to v4.1.
     158* Updated the Rollbar core JavaScript SDK to v2.26.
     159* Added support for telemetry and added auto-instrumentation.
     160* Added support for `ROLLBAR_DISABLE_ADMIN` to remove the plugin settings page from the admin.
     161* Added support for `ROLLBAR_SETTINGS` to configure the plugin without the admin page.
     162* Added support for `ROLLBAR_CLIENT_ACCESS_TOKEN` constant or environment variable to set the client access token.
     163* Added support for `WP_PROXY_BYPASS_HOSTS`, `WP_PROXY_USERNAME`, and `WP_PROXY_PASSWORD` for better proxy management.
     164* Added `rollbar_api_admin_permission` filter to allow custom authorization of the admin API.
     165* Added `rollbar_user_can_view_admin` filter to allow custom disabling of the admin page.
     166* Added `rollbar_php_config` filter to allow more exact control over Rollbar PHP configurations.
     167* Added `rollbar_telemetry_actions` filter to allow control of which actions are logged via telemetry.
     168* Added `rollbar_telemetry_custom_handlers` filter to allow custom control over what is logged in telemetry messages.
     169* Added 'framework' details with the WordPress version to the item payload.
    107170
    108171= Version 2.7.1 (September 13 2023)
     
    129192
    130193= Version 2.5.1 (February 20th 2019) =
    131 * Fixed a call to Rollbar\Wordpress\Defaults for enableMustUsePlugin (https://github.com/rollbar/rollbar-php-wordpress/pull/75)
     194* Fixed a call to Rollbar\WordPress\Defaults for enableMustUsePlugin (https://github.com/rollbar/rollbar-php-wordpress/pull/75)
    132195
    133196= Version 2.5.0 (February 19th 2019) =
     
    172235
    173236= Version 2.4.0 (17th May 2018) =
    174 * Added capture_ip, capture_email and capture_username to the config options.
     237* Added capture_ip, capture_email, and capture_username to the config options.
    175238* Fixed populating config options from the database to the plugin for boolean values.
    176239* Updated rollbar-php dependency to v1.5.0
     
    202265= Version 2.1.0 (11th October 2017) =
    203266* Added "Send test message to Rollbar" button
    204 * Fixed the plugin's name inconsistency between Wordpress plugin directory and composer.
     267* Fixed the plugin's name inconsistency between WordPress plugin directory and composer.
    205268
    206269= Version 2.0.1 (6th October 2017) =
     
    248311
    249312= Version 2.5.1 (February 20th 2019) =
    250 * Fixed a call to Rollbar\Wordpress\Defaults for enableMustUsePlugin (https://github.com/rollbar/rollbar-php-wordpress/pull/75)
     313* Fixed a call to Rollbar\WordPress\Defaults for enableMustUsePlugin (https://github.com/rollbar/rollbar-php-wordpress/pull/75)
    251314
    252315= Version 2.5.0 (February 19th 2019) =
     
    291354
    292355= Version 2.4.0 (5th April 2018) =
    293 * Added capture_ip, capture_email and capture_username to the config options.
     356* Added capture_ip, capture_email, and capture_username to the config options.
    294357* Fixed populating config options from the database to the plugin for boolean values.
    295358* Updated rollbar-php dependency to v1.5.0
     
    321384= Version 2.1.0 (11th October 2017) =
    322385* Added "Send test message to Rollbar" button
    323 * Fixed the plugin's name inconsistency between Wordpress plugin directory and composer.
     386* Fixed the plugin's name inconsistency between WordPress plugin directory and composer.
    324387
    325388= Version 2.0.1 (6th October 2017) =
  • rollbar/trunk/src/Plugin.php

    r2966780 r3380353  
    11<?php
    2  
    3 namespace Rollbar\Wordpress;
    4 
    5 use \Rollbar\Payload\Level as Level;
     2
     3namespace Rollbar\WordPress;
     4
     5use Exception;
     6use Rollbar\Rollbar;
     7use Rollbar\RollbarJsHelper;
     8use Rollbar\WordPress\Admin\FlashMessages;
     9use Rollbar\WordPress\Admin\SettingsPage;
     10use Rollbar\WordPress\API\AdminAPI;
     11use Rollbar\WordPress\Lib\AbstractSingleton;
     12use Rollbar\WordPress\Settings\SettingType;
     13use Rollbar\WordPress\Telemetry\Listener;
    614
    715// Exit if accessed directly
    8 if( !defined( 'ABSPATH' ) ) exit;
    9 
    10 class Plugin {
    11    
    12     const VERSION = "2.7.1";
    13    
    14     private $config;
    15    
    16     private static $instance;
    17    
    18     private static $pluginOptions = array(
    19         'enable_must_use_plugin'
    20     );
    21    
    22     private $settings = null;
    23    
    24     private function __construct() {
    25         $this->config = array();
    26     }
    27    
    28     public static function instance() {
    29         if( !self::$instance ) {
    30             self::$instance = new Plugin();
    31             self::$instance->loadTextdomain();
    32             self::$instance->hooks();
    33             self::$instance->initSettings();
    34             self::$instance->initPhpLogging();
    35         }
    36 
    37         return self::$instance;
    38     }
    39    
    40     public static function load() {
    41         return Plugin::instance();
    42     }
    43    
    44     public function configure(array $config) {
     16// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
     17defined('ABSPATH') || exit;
     18// phpcs:enable
     19
     20/**
     21 * Class Plugin
     22 *
     23 * The main plugin engine room. It is responsible for setting up and running the plugin.
     24 */
     25final class Plugin extends AbstractSingleton
     26{
     27    public const VERSION = '3.0.0';
     28
     29    /**
     30     * Configuration array for Rollbar.
     31     *
     32     * @var array
     33     */
     34    private array $config;
     35
     36    /**
     37     * Settings instance for managing plugin configuration
     38     *
     39     * @var Settings|null
     40     */
     41    private Settings|null $settings;
     42
     43    /**
     44     * The telemetry listener instance.
     45     *
     46     * @var Listener|null
     47     */
     48    private Listener|null $listener;
     49
     50    /**
     51     * Initialize the Plugin instance
     52     *
     53     * Sets up settings, initializes configuration, registers hooks, and starts PHP logging.
     54     */
     55    protected function __construct()
     56    {
     57        $this->settings = Settings::getInstance();
     58        $this->config = [];
     59        $this->hooks();
     60        $this->initPhpLogging();
     61    }
     62
     63    /**
     64     * Post-initialization tasks
     65     *
     66     * Sets up admin views and API after the main initialization is complete.
     67     *
     68     * @return void
     69     */
     70    protected function postInit(): void
     71    {
     72        // Set up the telemetry listener.
     73        if ($this->getSetting('enable_telemetry_listener')) {
     74            $this->listener = Listener::getInstance();
     75        }
     76    }
     77
     78    /**
     79     * Handles the 'init' action hook.
     80     *
     81     * @return void
     82     */
     83    public function onInit(): void
     84    {
     85        // Set up admin views and API.
     86        SettingsPage::getInstance();
     87        AdminAPI::getInstance();
     88    }
     89
     90    /**
     91     * Updates the plugin configuration
     92     *
     93     * Merges the provided configuration with the existing one and applies
     94     * it to the Rollbar logger if available.
     95     *
     96     * @param array $config Configuration options to merge with existing config
     97     * @return void
     98     */
     99    public function configure(array $config): void
     100    {
    45101        $this->config = array_merge($this->config, $config);
    46        
    47         if ($logger = \Rollbar\Rollbar::logger()) {
     102
     103        if ($logger = Rollbar::logger()) {
    48104            $logger->configure($this->config);
    49105        }
    50106    }
    51    
    52     private function initSettings() {
    53         Settings::init();
    54     }
    55 
    56     public static function getEnvironment()
    57     {
    58         return ( getenv('WP_ENV') ?: ( defined( 'WP_ENV' ) ? WP_ENV : null ) );
    59     }
    60    
    61     /**
    62      * Fetch settings provided in Admin -> Tools -> Rollbar
    63      *
    64      * @returns array
    65      */
    66     private function fetchSettings() {
    67        
    68         $options = $this->settings ?: array();
    69        
    70         if ($saved_options = get_option( 'rollbar_wp' )) {
    71             $options = array_merge($options, $saved_options);
    72         }
    73        
    74         if (!isset($options['environment']) || empty($options['environment'])) {
    75            
    76             if ($wpEnv = $this->getEnvironment()) {
    77                 $options['environment'] = $wpEnv;
    78             }
    79            
    80         }
    81 
    82         if (!isset($options['proxy']) || empty($options['proxy'])) {
    83 
    84             if (defined('WP_PROXY_HOST') && defined('WP_PROXY_PORT')) {
    85               $options['proxy'] = WP_PROXY_HOST.":". WP_PROXY_PORT;
    86             }
    87 
    88         }
    89        
    90         if (!isset($options['server_side_access_token']) || empty($options['server_side_access_token'])) {
    91            
    92             if (defined('ROLLBAR_ACCESS_TOKEN')) {
    93                
    94                 $options['server_side_access_token'] = ROLLBAR_ACCESS_TOKEN;
    95                
    96             } else if ($token = getenv('ROLLBAR_ACCESS_TOKEN')) {
    97                
    98                 $options['server_side_access_token'] = $token;
    99                
    100             }
    101         }
    102        
    103         $settings = array(
    104            
    105             'php_logging_enabled' => (!empty($options['php_logging_enabled'])) ? 1 : 0,
    106            
    107             'js_logging_enabled' => (!empty($options['js_logging_enabled'])) ? 1 : 0,
    108            
    109             'server_side_access_token' => (!empty($options['server_side_access_token'])) ?
    110                 esc_attr(trim($options['server_side_access_token'])) :
    111                 '',
    112                
    113             'client_side_access_token' => (!empty($options['client_side_access_token'])) ?
    114                 trim($options['client_side_access_token']) :
    115                 '',
    116            
    117             'logging_level' => (!empty($options['logging_level'])) ?
    118                 esc_attr(trim($options['logging_level'])) :
    119                 Settings::DEFAULT_LOGGING_LEVEL
    120         );
    121        
    122         foreach (self::listOptions() as $option) {
    123            
    124             // 'access_token' and 'enabled' are different in Wordpress plugin
    125             // look for 'server_side_access_token' and 'php_logging_enabled' above
    126             if (in_array($option, array('access_token', 'enabled'))) {
    127                 continue;
    128             }
    129            
    130             if (!isset($options[$option])) {
    131                 $value = $this->getDefaultOption($option);
    132             } else {
    133                 $value = $options[$option];
    134             }
    135            
    136             $settings[$option] = $value;
    137                
    138         }
    139        
    140         $this->settings = \apply_filters('rollbar_plugin_settings', $settings);
    141        
    142     }
    143    
    144     public function setting() {
    145         $args = func_get_args();
    146         $setting = $args[0];
    147         if (isset($args[1])) {
    148             $value = $args[1];
    149         }
    150        
    151         if (isset($value)) {
    152             $this->settings[$setting] = $value;
    153         } else {
    154             return $this->settings[$setting];
    155         }
    156     }
    157 
    158     private function hooks() {
    159         \add_action('wp_head', array(&$this, 'initJsLogging'));
    160         \add_action('admin_head', array(&$this, 'initJsLogging'));
    161         $this->registerTestEndpoint();
    162     }
    163    
    164     private function registerTestEndpoint() {
    165         \add_action( 'rest_api_init', function () {
    166             \register_rest_route(
    167                 'rollbar/v1',
    168                 '/test-php-logging',
    169                 array(
    170                     'methods' => 'POST',
    171                     'callback' => '\Rollbar\Wordpress\Plugin::testPhpLogging',
    172                     'permission_callback' => '__return_true',
    173                     'args' => array(
    174                         'server_side_access_token' => array(
    175                             'required' => true
    176                         ),
    177                         'environment' => array(
    178                             'required' => true
    179                         ),
    180                         'logging_level' => array(
    181                             'required' => true
    182                         )
    183                     )
    184                 )
    185             );
    186         });
    187     }
    188    
    189     public static function testPhpLogging(\WP_REST_Request $request) {
    190        
    191         $plugin = self::instance();
    192        
    193         foreach(self::listOptions() as $option) {
    194             $plugin->settings[$option] = $request->get_param($option);
    195         }
    196        
    197         $plugin->settings['server_side_access_token'] = $request->get_param('server_side_access_token');
    198        
    199         $response = null;
    200        
    201         try {
    202             $plugin->initPhpLogging();
    203 
    204             // in the PHP8 version, $response will be null if we use `log` instead of `report`
    205             if ( is_callable( '\Rollbar\Rollbar::report' ) ){
    206                 $response = \Rollbar\Rollbar::report(
    207                     Level::INFO,
    208                     "Test message from Rollbar Wordpress plugin using PHP: ".
    209                     "integration with Wordpress successful"
    210                 );
    211             } else {
    212                 $response = \Rollbar\Rollbar::log(
    213                     Level::INFO,
    214                     "Test message from Rollbar Wordpress plugin using PHP: ".
    215                     "integration with Wordpress successful"
    216                 );
    217             }
    218 
    219            
    220         } catch( \Exception $exception ) {
    221            
    222             return new \WP_REST_Response(
    223                 array(
    224                     'message' => $exception->getMessage()
    225                 ), 
    226                 500
    227             );   
    228         }
    229        
    230         $info = $response->getInfo();
    231        
    232         $response = array('code' => $response->getStatus());
    233         if (is_array($info)) {
    234             $response = array_merge($response, $info);
    235         } else {
    236             $response['message'] = $info;
    237         }
    238        
    239         return new \WP_REST_Response($response, 200);
    240        
    241     }
    242 
    243     public function loadTextdomain() {
    244         \load_plugin_textdomain( 'rollbar', false, dirname( \plugin_basename( __FILE__  ) ) . '/languages/' );
    245     }
    246    
    247     public static function buildIncludedErrno($cutoff)
    248     {
    249            
    250         $levels = array(
     107
     108    /**
     109     * Returns true if the admin area should be disabled.
     110     *
     111     * Disable the admin settings page if the `ROLLBAR_DISABLE_ADMIN` constant is defined and set to `true`.
     112     * This allows for the plugin to be used without the admin settings page, for example, if the plugin is managed
     113     * via the `wp-config.php` file.
     114     *
     115     * @return bool
     116     * @since 3.0.0
     117     */
     118    public static function disabledAdmin(): bool
     119    {
     120        return defined('ROLLBAR_DISABLE_ADMIN') && constant('ROLLBAR_DISABLE_ADMIN');
     121    }
     122
     123    /**
     124     * Returns true if the admin area should be disabled.
     125     *
     126     * @return bool
     127     * @since 3.0.0
     128     */
     129    public static function userCanViewAdmin(): bool
     130    {
     131        if (self::disabledAdmin()) {
     132            return false;
     133        }
     134
     135        /**
     136         * Filter to enable / disable the admin settings page of the plugin for the current user.
     137         *
     138         * This filter cannot override the `ROLLBAR_DISABLE_ADMIN` constant.
     139         *
     140         * @param bool $allow `true` to enable the admin settings page, `false` to disable it.
     141         * @since 3.0.0
     142         */
     143        return apply_filters('rollbar_user_can_view_admin', current_user_can('manage_options')) === true;
     144    }
     145
     146    /**
     147     * @param string $path
     148     * @return string
     149     *
     150     * @since 3.0.0
     151     */
     152    public static function getAssetUrl(string $path): string
     153    {
     154        if (str_starts_with($path, '/')) {
     155            $path = substr($path, 1);
     156        }
     157        return plugin_dir_url(ROLLBAR_PLUGIN_FILE) . $path;
     158    }
     159
     160    /**
     161     * Retrieve the value of a specific setting.
     162     *
     163     * @param string $setting The name of the setting to retrieve.
     164     * @return mixed The value of the setting, or null if the setting does not exist.
     165     *
     166     * @since 3.0.0
     167     */
     168    public function getSetting(string $setting): mixed
     169    {
     170        return $this->settings->get($setting) ?? null;
     171    }
     172
     173    /**
     174     * Sets a specific setting with the provided value.
     175     *
     176     * @param string $setting The name of the setting to be updated.
     177     * @param mixed $value The value to be assigned to the specified setting.
     178     * @return void
     179     *
     180     * @since 3.0.0
     181     */
     182    public function setSetting(string $setting, mixed $value): void
     183    {
     184        $this->settings->set($setting, $value);
     185    }
     186
     187    /**
     188     * Get the Settings instance used by this plugin
     189     *
     190     * @return Settings The settings instance
     191     */
     192    public function settingsInstance(): Settings
     193    {
     194        return $this->settings;
     195    }
     196
     197    /**
     198     * Register WordPress hooks and actions
     199     *
     200     * Sets up action hooks for JavaScript logging in both frontend and admin areas.
     201     *
     202     * @return void
     203     */
     204    private function hooks(): void
     205    {
     206        add_action('init', $this->onInit(...));
     207        add_action('wp_head', $this->initJsLogging(...));
     208        add_action('admin_head', $this->initJsLogging(...));
     209    }
     210
     211    /**
     212     * Build the error reporting level bitmask
     213     *
     214     * Creates a bitmask of PHP error reporting levels up to and including the specified cutoff level.
     215     *
     216     * @param int $cutoff The maximum error level to include
     217     * @return int The combined bitmask of all error levels up to the cutoff
     218     */
     219    public static function buildIncludedErrno(int $cutoff): int
     220    {
     221        $levels = [
    251222            E_ERROR,
    252223            E_WARNING,
     
    264235            E_DEPRECATED,
    265236            E_USER_DEPRECATED,
    266             E_ALL
    267         );
    268        
     237            E_ALL,
     238        ];
     239
    269240        $included_errno = 0;
    270        
     241
    271242        foreach ($levels as $level) {
    272            
    273243            if ($level <= $cutoff) {
    274                 $included_errno |= $level;   
     244                $included_errno |= $level;
    275245            }
    276            
    277         }
    278        
     246        }
     247
    279248        return $included_errno;
    280249    }
    281    
    282     public function initPhpLogging()
    283     {
    284         $this->fetchSettings();
    285 
     250
     251    /**
     252     * Initialize PHP error logging with Rollbar
     253     *
     254     * Sets up the Rollbar PHP error handler if PHP logging is enabled.
     255     * Handles configuration errors by displaying appropriate error messages.
     256     *
     257     * @param bool $ignoreEnabledSetting If true, the plugin will not check the 'php_logging_enabled' setting first.
     258     *
     259     * @return void
     260     */
     261    public function initPhpLogging(bool $ignoreEnabledSetting = false): void
     262    {
    286263        // Return if logging is not enabled
    287         if ( $this->settings['php_logging_enabled'] === 0 ) {
     264        if (!$ignoreEnabledSetting && false === $this->getSetting('php_logging_enabled')) {
    288265            return;
    289266        }
    290        
     267
    291268        // installs global error and exception handlers
    292269        try {
    293            
    294             \Rollbar\Rollbar::init($this->buildPHPConfig());
    295            
    296         } catch (\InvalidArgumentException $exception) {
    297            
    298             \add_action(
    299                 'admin_notices',
    300                 array(
    301                     '\Rollbar\Wordpress\UI',
    302                     'pluginMisconfiguredNotice'
    303                 )
     270            Rollbar::init($this->buildPHPConfig());
     271        } catch (Exception $exception) {
     272            FlashMessages::addMessage(
     273                message: 'Rollbar is misconfigured. Please, fix your configuration here: <a href="'
     274                . admin_url('/options-general.php?page=rollbar_wp') . '">Rollbar Settings</a>.',
     275                type: 'error',
    304276            );
    305            
    306             global $wp_settings_errors;
    307             $wp_settings_errors[] = array(
    308                     'setting' => 'rollbar-wp',
    309                     'code'    => 'rollbar-wp',
    310                     'message' => 'Rollbar PHP: ' . $exception->getMessage(),
    311                     'type'    => 'error'
    312             );
    313            
    314         } catch (\Exception $exception) {
    315            
    316             global $wp_settings_errors;
    317             $wp_settings_errors[] = array(
    318                     'setting' => 'rollbar-wp',
    319                     'code'    => 'rollbar-wp',
    320                     'message' => 'Rollbar PHP: ' . $exception->getMessage(),
    321                     'type'    => 'error'
    322             );
    323            
    324         }
    325        
    326     }
    327    
    328     public function buildPHPConfig()
    329     {
    330         $config = $this->settings;
    331        
    332         $config['access_token'] = $this->settings['server_side_access_token'];
    333         $config['included_errno'] = self::buildIncludedErrno($this->settings['logging_level']);
    334         $config['timeout'] = intval($this->settings['timeout']);
    335        
    336         foreach (UI::settingsOfType(UI::SETTING_INPUT_TYPE_PHP) as $setting) {
    337            
    338             if (isset($config[$setting])) {
    339                
    340                 $code = is_string($config[$setting]) ?: 'return ' . var_export($config[$setting], true) . ';';
    341                
    342                 $config[$setting] = eval($code);
     277        }
     278    }
     279
     280    /**
     281     * Build the PHP configuration for Rollbar
     282     *
     283     * Generates the configuration array for the Rollbar PHP SDK from the plugin settings.
     284     * Processes boolean values and special settings like error reporting levels and person function.
     285     *
     286     * @return array The complete Rollbar PHP configuration
     287     */
     288    public function buildPHPConfig(): array
     289    {
     290        $config = $this->settings->getAll();
     291
     292        $config['access_token'] = $this->getSetting('server_side_access_token');
     293        $config['included_errno'] = self::buildIncludedErrno($this->getSetting('included_errno'));
     294        $config['timeout'] = intval($this->getSetting('timeout'));
     295
     296        // Set up telemetry
     297        $config['telemetry'] = false;
     298        if ($this->getSetting('enable_telemetry_listener')) {
     299            $config['telemetry'] = [
     300                'includeItemsInTelemetry' => $this->getSetting('include_items_in_telemetry'),
     301                'includeIgnoredItemsInTelemetry' => $this->getSetting('include_ignored_items_in_telemetry'),
     302            ];
     303        }
     304
     305        foreach ($config as $setting => $value) {
     306            if (SettingType::Boolean !== Settings::getSettingType($setting)) {
     307                continue;
    343308            }
    344         }
    345        
    346         foreach (UI::settingsOfType(UI::SETTING_INPUT_TYPE_BOOLEAN) as $setting) {
    347            
    348             if (isset($config[$setting]) && $config[$setting] === 'false') {
    349                 $config[$setting] = false;
    350             } else if (isset($config[$setting]) && $config[$setting] === 'true') {
    351                 $config[$setting] = true;
    352             }
    353 
    354             // also handle 1 and 0 as booleans
    355             else if (isset($config[$setting]) && $config[$setting] === '0') {
    356                 $config[$setting] = false;
    357             } else if (isset($config[$setting]) && $config[$setting] === '1') {
    358                 $config[$setting] = true;
    359             }
    360         }
    361        
    362         return $config;
    363     }
    364    
    365     public function initJsLogging()
     309            $config[$setting] = Settings::toBoolean($value);
     310        }
     311
     312        if ($config['enable_person_reporting'] && empty($config['person_fn']) && empty($config['person'])) {
     313            $config['person_fn'] = Settings::getPersonFunction(...);
     314        }
     315
     316        $config['framework'] = 'wordpress ' . get_bloginfo('version');
     317
     318        /**
     319         * Filters the Rollbar Core SDK PHP configuration.
     320         *
     321         * @param array $config The Rollbar PHP configuration array.
     322         * @since 3.0.0
     323         */
     324        return apply_filters('rollbar_php_config', $config);
     325    }
     326
     327    /**
     328     * Initialize JavaScript error logging with Rollbar
     329     *
     330     * Sets up the Rollbar JavaScript error handler if JS logging is enabled.
     331     * Checks for valid configuration and outputs the necessary JavaScript code.
     332     *
     333     * @return void
     334     */
     335    public function initJsLogging(): void
    366336    {
    367337        // Return if logging is not enabled
    368         if ( $this->settings['js_logging_enabled'] === 0 ) {
     338        if (false === $this->getSetting('js_logging_enabled')) {
    369339            return;
    370340        }
    371    
     341
    372342        // Return if access token is not set
    373         if ($this->settings['client_side_access_token'] == '') {
    374             add_action(
    375                 'admin_notices',
    376                 array(
    377                     '\Rollbar\Wordpress\UI',
    378                     'pluginMisconfiguredNotice'
    379                 )
     343        if (empty($this->getSetting('client_side_access_token'))) {
     344            FlashMessages::addMessage(
     345                message: 'Rollbar is misconfigured. Please, fix your configuration here: <a href="'
     346                . admin_url('/options-general.php?page=rollbar_wp') . '">Rollbar Settings</a>.',
     347                type: 'error',
    380348            );
    381349            return;
    382350        }
    383        
    384         $rollbarJs = \Rollbar\RollbarJsHelper::buildJs($this->buildJsConfig());
    385        
     351
     352        $rollbarJs = RollbarJsHelper::buildJs($this->buildJsConfig());
     353
    386354        echo $rollbarJs;
    387        
    388     }
    389    
    390     public function buildJsConfig()
    391     {
    392         $rollbarJsConfig = array(
    393           'accessToken' => $this->settings['client_side_access_token'],
    394           'captureUncaught' => true,
    395           'payload' => array(
    396             'environment' => $this->settings['environment']
    397           ),
    398         );
    399 
    400         $rollbarJsConfig = apply_filters('rollbar_js_config', $rollbarJsConfig);
    401        
    402         return $rollbarJsConfig;
    403     }
    404    
    405     public function updateSettings(array $settings)
    406     {
    407         $option = get_option('rollbar_wp');
    408        
    409         $option = array_merge($option, $settings);
    410        
    411         foreach ($settings as $setting => $value) {
    412             $this->settings[$setting] = $value;
    413         }
    414        
    415         update_option('rollbar_wp', $option);
    416     }
    417    
    418     public function restoreDefaults()
    419     {
    420         $settings = array();
    421        
    422         foreach (self::listOptions() as $option) {
    423             $settings[$option] = $this->getDefaultOption($option);
    424         }
    425        
    426         $this->updateSettings($settings);
    427     }
    428    
    429     public function getDefaultOption($setting)
    430     {
    431         $spaced = str_replace('_', ' ', $setting);
    432         $method = lcfirst(str_replace(' ', '', ucwords($spaced)));
    433        
    434         // Handle the "branch" exception
    435         switch($method) {
    436             case "branch":
    437                 $method = "gitBranch";
    438                 break;
    439             case "captureIp":
    440                 $method = "captureIP";
    441                 break;
    442         }
    443        
    444         $rollbarDefaults = \Rollbar\Defaults::get();
    445         $wordpressDefaults = \Rollbar\Wordpress\Defaults::instance();
    446        
    447         $value = null;
    448        
    449         if (method_exists($wordpressDefaults, $method) && $value === null) {
    450             try {
    451                 $value = $wordpressDefaults->$method();
    452             } catch (\Throwable $e) {
    453                 $value = null;
    454             } catch (\Exception $e) {
    455                 $value = null;
    456             }
    457         }
    458        
    459         if (method_exists($rollbarDefaults, $method) && $value === null) {
    460             try {
    461                 $value = $rollbarDefaults->$method();
    462             } catch (\Throwable $e) {
    463                 $value = null;
    464             } catch (\Exception $e) {
    465                 $value = null;
    466             }
    467         }
    468        
    469         return $value;
    470     }
    471    
    472     public static function listOptions()
    473     {
    474         return array_merge(
    475             \Rollbar\Config::listOptions(),
    476             self::$pluginOptions
    477         );
    478     }
    479    
    480     public function enableMustUsePlugin()
     355    }
     356
     357    /**
     358     * Build the JavaScript configuration for Rollbar
     359     *
     360     * Generates the configuration array for the Rollbar JavaScript SDK from the plugin settings.
     361     * Applies filters to allow customization of the JavaScript configuration.
     362     *
     363     * @return array The complete Rollbar JavaScript configuration
     364     */
     365    public function buildJsConfig(): array
     366    {
     367        $config = [
     368            'accessToken' => $this->getSetting('client_side_access_token'),
     369            'captureUncaught' => true,
     370            'payload' => [
     371                'environment' => $this->getSetting('environment'),
     372            ],
     373        ];
     374
     375        /**
     376         * Filters the Rollbar JavaScript configuration.
     377         *
     378         * @param array $config The Rollbar JavaScript configuration array.
     379         * @since 3.0.0
     380         *
     381         */
     382        return apply_filters('rollbar_js_config', $config);
     383    }
     384
     385    /**
     386     * Check if the Must-Use plugin is enabled
     387     *
     388     * Determines if the Rollbar Must-Use plugin is installed and active.
     389     *
     390     * @return bool True if the Must-Use plugin exists, false otherwise
     391     */
     392    public static function mustUsePluginEnabled(): bool
     393    {
     394        return file_exists(plugin_dir_path(__DIR__) . '../../mu-plugins/rollbar-mu-plugin.php');
     395    }
     396
     397    /**
     398     * Enable the Must-Use plugin
     399     *
     400     * Copies the Rollbar Must-Use plugin into the WordPress mu-plugins directory,
     401     * creating the directory if it doesn't exist.
     402     *
     403     * @return void
     404     * @throws Exception If the directory cannot be created or the plugin cannot be copied
     405     */
     406    public function enableMustUsePlugin(): void
    481407    {
    482408        $muPluginsDir = plugin_dir_path(__DIR__) . '../../mu-plugins/';
    483        
     409
    484410        $muPluginFilepath = plugin_dir_path(__DIR__) . 'mu-plugin/rollbar-mu-plugin.php';
    485        
     411
    486412        if (!file_exists($muPluginsDir) && !mkdir($muPluginsDir, 0700)) {
    487             throw new \Exception("Can't create the mu-plugins directory: $muPluginsDir");
    488         }
    489        
     413            throw new Exception('Can\'t create the mu-plugins directory: ' . $muPluginsDir);
     414        }
     415
    490416        if (!copy($muPluginFilepath, $muPluginsDir . 'rollbar-mu-plugin.php')) {
    491             throw new \Exception("Can't copy mu-plugin from $muPluginFilepath to $muPluginsDir");
    492         }
    493     }
    494    
    495     public function disableMustUsePlugin()
     417            throw new Exception('Can\'t copy mu-plugin from ' . $muPluginFilepath . ' to ' . $muPluginsDir);
     418        }
     419    }
     420
     421    /**
     422     * Disable the Must-Use plugin
     423     *
     424     * Removes the Rollbar Must-Use plugin from the WordPress mu-plugins directory if it exists.
     425     *
     426     * @return void
     427     * @throws Exception If the plugin file cannot be deleted
     428     */
     429    public function disableMustUsePlugin(): void
    496430    {
    497431        $file = plugin_dir_path(__DIR__) . '../../mu-plugins/rollbar-mu-plugin.php';
    498432        if (file_exists($file) && !unlink($file)) {
    499             throw new \Exception("Can't delete the mu-plugin");
     433            throw new Exception('Can\'t delete the mu-plugin');
    500434        }
    501435    }
  • rollbar/trunk/src/Settings.php

    r2965452 r3380353  
    11<?php
    2 namespace Rollbar\Wordpress;
    3 
    4 use Michelf\Markdown;
     2
     3namespace Rollbar\WordPress;
     4
     5use Psr\Log\LogLevel;
     6use Rollbar\Config;
     7use Rollbar\Defaults;
     8use Rollbar\Payload\Level;
     9use Rollbar\WordPress\Lib\AbstractSingleton;
     10use Rollbar\WordPress\Settings\SettingType;
     11use Rollbar\WordPress\Telemetry\Listener;
     12use WP_HTTP_Proxy;
    513
    614// Exit if accessed directly
    7 if (!defined('ABSPATH')) exit;
    8 
    9 class Settings
     15// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
     16defined('ABSPATH') || exit;
     17// phpcs:enable
     18
     19/**
     20 * Class Settings
     21 *
     22 * Represents the configuration management for the Rollbar plugin. This class is responsible for
     23 * providing and managing settings that are configured through the WordPress admin interface,
     24 * environment variables, or system constants. Implements the Singleton design pattern to ensure a
     25 * single instance of the settings is used application-wide.
     26 *
     27 * @since 3.0.0
     28 */
     29final class Settings extends AbstractSingleton
    1030{
    11     const DEFAULT_LOGGING_LEVEL = E_ERROR;
    12    
    13     private static $instance;
    14    
    15     private $plugin;
    16 
    17     private function __construct() {
    18         $this->plugin = \Rollbar\Wordpress\Plugin::instance();
    19     }
    20    
    21     public static function instance()
    22     {
    23         if (!self::$instance) {
    24             self::$instance = new self();
    25         }
    26        
    27         return self::$instance;
    28     }
    29    
    30     public static function init() {
    31         $instance = self::instance();
    32         \add_action('admin_menu', array(&$instance, 'addAdminMenu'));
    33         \add_filter('plugin_action_links_'.basename(dirname(__DIR__)).'/rollbar-php-wordpress.php', array(&$instance, 'addAdminMenuLink'));
    34         \add_action('admin_init', array(&$instance, 'addSettings'));
    35         \add_action('admin_enqueue_scripts', function($hook) {
    36            
    37             if ($hook != 'settings_page_rollbar_wp') {
    38                 return;
    39             }
    40            
    41             \wp_register_script(
    42                 'RollbarWordpressSettings.js',
    43                 \plugin_dir_url(__FILE__)."../public/js/RollbarWordpressSettings.js",
    44                 array("jquery"),
    45                 Plugin::VERSION
    46             );
    47 
    48             \wp_localize_script(
    49                 'RollbarWordpressSettings.js',
    50                 'RollbarWordpress',
    51                 array(
    52                     // This is used to load the rollbar snippet, assume the php8 version is more recent.
    53                     'plugin_url' => \plugin_dir_url(__FILE__) . "../php8/",
    54                 )
    55             );
    56            
    57             \wp_enqueue_script(
    58                 "RollbarWordpressSettings.js",
    59                 \plugin_dir_url(__FILE__)."../public/js/RollbarWordpressSettings.js",
    60                 array("jquery"),
    61                 Plugin::VERSION
    62             );
    63            
    64             \wp_register_style(
    65                 'RollbarWordpressSettings',
    66                 \plugin_dir_url(__FILE__)."../public/css/RollbarWordpressSettings.css",
    67                 false,
    68                 Plugin::VERSION
    69             );
    70             \wp_enqueue_style('RollbarWordpressSettings');
    71         });
    72 
    73         \add_action('admin_post_rollbar_wp_restore_defaults', array(get_called_class(), 'restoreDefaultsAction'));
    74        
    75         \add_action('pre_update_option_rollbar_wp', array(get_called_class(), 'preUpdate'));
    76     }
    77 
    78     function addAdminMenu()
    79     {
    80         add_submenu_page(
    81             'options-general.php',
    82             'Rollbar',
    83             'Rollbar',
    84             'manage_options',
    85             'rollbar_wp',
    86             array(&$this, 'optionsPage')
    87         );
    88     }
    89 
    90     function addAdminMenuLink($links)
    91     {
    92         $args = array('page' => 'rollbar_wp');
    93 
    94         $links['settings'] = '<a href="'.admin_url( 'options-general.php?'.http_build_query( $args ) ).'">'.__('Settings', 'rollbar').'</a>';
    95 
    96         return $links;
    97     }
    98 
    99     function addSettings()
    100     {
    101         \register_setting(
    102             'rollbar_wp',
    103             'rollbar_wp'
    104         );
    105 
    106         // SECTION: General
    107         \add_settings_section(
    108             'rollbar_wp_general',
    109             false,
    110             false,
    111             'rollbar_wp'
    112         );
    113 
    114         // On/off & tokens
    115         \add_settings_field(
    116             'rollbar_wp_status',
    117             __('Status', 'rollbar'),
    118             array('\Rollbar\Wordpress\UI', 'status'),
    119             'rollbar_wp',
    120             'rollbar_wp_general',
    121             array(
    122                 'php_logging_enabled' => (!empty($this->plugin->setting('php_logging_enabled'))) ? 1 : 0,
    123                 'server_side_access_token' => $this->plugin->setting('server_side_access_token'),
    124                 'js_logging_enabled' => (!empty($this->plugin->setting('js_logging_enabled'))) ? 1 : 0,
    125                 'client_side_access_token' => $this->plugin->setting('client_side_access_token')
    126             )
    127         );
    128 
    129         $envDescription = $this->parseSettingDescription('environment');
    130         $envDescription .= UI::environmentSettingNote();
    131         $this->addSetting(
    132             'environment',
    133             'rollbar_wp_general',
    134             array(
    135                 'description' => $envDescription
    136             )
    137         );
    138        
    139         $included_errno_options = UI::getSettingOptions('included_errno');
    140         $human_friendly_errno_options = array();
    141         foreach ($included_errno_options as $included_errno) {
    142             $human_friendly_errno_options[$included_errno] = UI::getIncludedErrnoDescriptions($included_errno);
    143         }
    144        
    145         $this->addSetting(
    146             'logging_level',
    147             'rollbar_wp_general',
    148             array(
    149                 'type' => UI::SETTING_INPUT_TYPE_SELECTBOX,
    150                 'options' => $human_friendly_errno_options,
    151                 'default' => E_ERROR
    152             )
    153         );
    154        
    155         // SECTION: Advanced
    156         \add_settings_section(
    157             'rollbar_wp_advanced',
    158             null,
    159             array(&$this, 'advancedSectionHeader'),
    160             'rollbar_wp'
    161         );
    162        
    163         $options = \Rollbar\Wordpress\Plugin::listOptions();
    164         $skip = array(
    165             'access_token', 'environment', 'enabled', 'included_errno',
    166             'base_api_url', 'enable_must_use_plugin'
    167         );
    168        
    169         foreach ($options as $option) {
    170             if (in_array($option, $skip)) {
     31    /**
     32     * The option name where the plugin settings are saved.
     33     */
     34    private const OPTIONS_KEY = 'rollbar_wp';
     35
     36    /**
     37     * The array of plugin settings.
     38     *
     39     * @var array
     40     */
     41    private array $settings = [];
     42
     43    /**
     44     * @inheritdoc
     45     */
     46    protected function __construct()
     47    {
     48        $this->fetchSettings();
     49        $this->hooks();
     50    }
     51
     52    /**
     53     * Register the event handlers for the settings.
     54     *
     55     * @return void
     56     */
     57    private function hooks(): void
     58    {
     59        add_filter('pre_update_option_rollbar_wp', $this->preUpdate(...));
     60    }
     61
     62    /**
     63     * Returns an array of {@see Setting} that can be used in the plugin.
     64     *
     65     * @return array<string, null|Setting>
     66     */
     67    public static function settings(): array
     68    {
     69        static $settings;
     70        if (isset($settings)) {
     71            return $settings;
     72        }
     73        $env = Settings::getEnvironment(null);
     74
     75        $defaults = Defaults::get();
     76
     77        $settings = [
     78            'php_logging_enabled' => new Setting(
     79                id: 'php_logging_enabled',
     80                type: SettingType::Boolean,
     81                default: false,
     82                section: 'rollbar_wp_general',
     83            ),
     84            'server_side_access_token' => new Setting(
     85                id: 'server_side_access_token',
     86                type: SettingType::Text,
     87                default: '',
     88                section: 'rollbar_wp_general',
     89            ),
     90            'js_logging_enabled' => new Setting(
     91                id: 'js_logging_enabled',
     92                type: SettingType::Boolean,
     93                default: false,
     94                section: 'rollbar_wp_general',
     95            ),
     96            'client_side_access_token' => new Setting(
     97                id: 'client_side_access_token',
     98                type: SettingType::Text,
     99                default: '',
     100                section: 'rollbar_wp_general',
     101            ),
     102            'environment' => new Setting(
     103                id: 'environment',
     104                type: SettingType::Text,
     105                helpText: '<p><code>WP_ENV</code> environment variable: <code>' . $env . '</code></p>' .
     106                '<p>Rollbar for WordPress honors the <code>WP_ENV</code> environment variable. ' .
     107                'If the <code>environment</code> setting is not specified here, it will take ' .
     108                'precendence over the default value.</strong></p>',
     109                default: 'production',
     110                section: 'rollbar_wp_general',
     111            ),
     112            'included_errno' => new Setting(
     113                id: 'included_errno',
     114                type: SettingType::Select,
     115                label: 'Logging Level',
     116                default: E_ERROR,
     117                options: [
     118                    E_ERROR => 'Fatal run-time errors (E_ERROR) only',
     119                    E_WARNING => 'Run-time warnings (E_WARNING) and above',
     120                    E_PARSE => 'Compile-time parse errors (E_PARSE) and above',
     121                    E_NOTICE => 'Run-time notices (E_NOTICE) and above',
     122                    E_USER_ERROR => 'User-generated error messages (E_USER_ERROR) and above',
     123                    E_USER_WARNING => 'User-generated warning messages (E_USER_WARNING) and above',
     124                    E_USER_NOTICE => 'User-generated notice messages (E_USER_NOTICE) and above',
     125                    E_STRICT => 'Suggest code changes to ensure forward compatibility (E_STRICT) and above',
     126                    E_DEPRECATED => 'Warnings about code that won\'t work in future versions (E_DEPRECATED) and above',
     127                    E_ALL => 'Absolutely everything (E_ALL)',
     128                ],
     129                section: 'rollbar_wp_general',
     130            ),
     131            'agent_log_location' => new Setting(
     132                id: 'agent_log_location',
     133                type: SettingType::Text,
     134                default: $defaults->agentLogLocation(),
     135            ),
     136            'allow_exec' => new Setting(
     137                id: 'allow_exec',
     138                type: SettingType::Boolean,
     139                default: $defaults->allowExec(),
     140            ),
     141            'autodetect_branch' => new Setting(
     142                id: 'autodetect_branch',
     143                type: SettingType::Boolean,
     144                default: $defaults->autodetectBranch(),
     145            ),
     146            'branch' => new Setting(
     147                id: 'branch',
     148                type: SettingType::Text,
     149                default: $defaults->branch(),
     150            ),
     151            'capture_error_stacktraces' => new Setting(
     152                id: 'capture_error_stacktraces',
     153                type: SettingType::Boolean,
     154                default: $defaults->captureErrorStacktraces(),
     155            ),
     156            'code_version' => new Setting(
     157                id: 'code_version',
     158                type: SettingType::Text,
     159                default: $defaults->codeVersion(),
     160            ),
     161            'endpoint' => new Setting(
     162                id: 'endpoint',
     163                type: SettingType::Text,
     164                default: $defaults->endpoint(),
     165            ),
     166            'fluent_host' => new Setting(
     167                id: 'fluent_host',
     168                type: SettingType::Text,
     169                default: $defaults->fluentHost(),
     170            ),
     171            'fluent_port' => new Setting(
     172                id: 'fluent_port',
     173                type: SettingType::Text,
     174                default: $defaults->fluentPort(),
     175            ),
     176            'fluent_tag' => new Setting(
     177                id: 'fluent_tag',
     178                type: SettingType::Text,
     179                default: $defaults->fluentTag(),
     180            ),
     181            'handler' => new Setting(
     182                id: 'handler',
     183                type: SettingType::Select,
     184                default: $defaults->handler(),
     185                options: [
     186                    'blocking' => 'blocking',
     187                    'agent' => 'agent',
     188                    'fluent' => 'fluent',
     189                ],
     190            ),
     191            'host' => new Setting(
     192                id: 'host',
     193                type: SettingType::Text,
     194                default: $defaults->host(),
     195            ),
     196            'include_error_code_context' => new Setting(
     197                id: 'include_error_code_context',
     198                type: SettingType::Boolean,
     199                default: $defaults->includeErrorCodeContext(),
     200            ),
     201            'include_exception_code_context' => new Setting(
     202                id: 'include_exception_code_context',
     203                type: SettingType::Boolean,
     204                default: $defaults->includeExceptionCodeContext(),
     205            ),
     206            'include_raw_request_body' => new Setting(
     207                id: 'include_raw_request_body',
     208                type: SettingType::Boolean,
     209                default: $defaults->rawRequestBody(),
     210            ),
     211            'local_vars_dump' => new Setting(
     212                id: 'local_vars_dump',
     213                type: SettingType::Boolean,
     214                default: $defaults->localVarsDump(),
     215            ),
     216            'log_payload' => new Setting(
     217                id: 'log_payload',
     218                type: SettingType::Boolean,
     219                default: $defaults->logPayload(),
     220            ),
     221            'max_items' => new Setting(
     222                id: 'max_items',
     223                type: SettingType::Integer,
     224                default: $defaults->maxItems(),
     225            ),
     226            'max_nesting_depth' => new Setting(
     227                id: 'max_nesting_depth',
     228                type: SettingType::Integer,
     229                default: $defaults->maxNestingDepth(),
     230            ),
     231            'minimum_level' => new Setting(
     232                id: 'minimum_level',
     233                type: SettingType::Select,
     234                default: $defaults->minimumLevel(),
     235                options: [
     236                    100000 => Level::EMERGENCY . ', ' . Level::ALERT . ', ' . Level::CRITICAL,
     237                    10000 => Level::ERROR . ', ' . Level::WARNING,
     238                    1000 => Level::WARNING,
     239                    100 => Level::NOTICE . ', ' . Level::INFO,
     240                    10 => Level::DEBUG,
     241                ],
     242            ),
     243            'enable_person_reporting' => new Setting(
     244                id: 'enable_person_reporting',
     245                type: SettingType::Boolean,
     246                helpText: 'Adds the current user to the payload as a person. This will allow Rollbar to display the '
     247                . 'user\'s details in the Rollbar UI.',
     248                default: false,
     249            ),
     250            'capture_ip' => new Setting(
     251                id: 'capture_ip',
     252                type: SettingType::Boolean,
     253                label: 'Capture IP Address',
     254                default: $defaults->captureIp(),
     255            ),
     256            'capture_email' => new Setting(
     257                id: 'capture_email',
     258                type: SettingType::Boolean,
     259                default: $defaults->captureEmail(),
     260            ),
     261            'capture_username' => new Setting(
     262                id: 'capture_username',
     263                type: SettingType::Boolean,
     264                default: $defaults->captureUsername(),
     265            ),
     266            'proxy' => new Setting(
     267                id: 'proxy',
     268                type: SettingType::Text,
     269                default: '',
     270            ),
     271            'raise_on_error' => new Setting(
     272                id: 'raise_on_error',
     273                type: SettingType::Boolean,
     274                default: $defaults->raiseOnError(),
     275            ),
     276            'report_suppressed' => new Setting(
     277                id: 'report_suppressed',
     278                type: SettingType::Boolean,
     279                default: $defaults->reportSuppressed(),
     280            ),
     281            'root' => new Setting(
     282                id: 'root',
     283                type: SettingType::Text,
     284                default: ABSPATH,
     285            ),
     286            'send_message_trace' => new Setting(
     287                id: 'send_message_trace',
     288                type: SettingType::Boolean,
     289                default: $defaults->sendMessageTrace(),
     290            ),
     291            'timeout' => new Setting(
     292                id: 'timeout',
     293                type: SettingType::Integer,
     294                default: $defaults->timeout(),
     295            ),
     296            'transmit' => new Setting(
     297                id: 'transmit',
     298                type: SettingType::Boolean,
     299                default: $defaults->transmit(),
     300            ),
     301            'use_error_reporting' => new Setting(
     302                id: 'use_error_reporting',
     303                type: SettingType::Boolean,
     304                default: $defaults->useErrorReporting(),
     305            ),
     306            'verbose' => new Setting(
     307                id: 'verbose',
     308                type: SettingType::Select,
     309                default: $defaults->verbose(),
     310                options: [
     311                    LogLevel::EMERGENCY => LogLevel::EMERGENCY,
     312                    LogLevel::ALERT => LogLevel::ALERT,
     313                    LogLevel::CRITICAL => LogLevel::CRITICAL,
     314                    LogLevel::ERROR => LogLevel::ERROR,
     315                    LogLevel::WARNING => LogLevel::WARNING,
     316                    LogLevel::NOTICE => LogLevel::NOTICE,
     317                    LogLevel::INFO => LogLevel::INFO,
     318                    LogLevel::DEBUG => LogLevel::DEBUG,
     319                ],
     320            ),
     321            'enable_must_use_plugin' => new Setting(
     322                id: 'enable_must_use_plugin',
     323                type: SettingType::Boolean,
     324                helpText: 'Allows Rollbar plugin to be loaded as early as possible as a Must-Use plugin. Activating / '
     325                . 'deactivating the plugin in the plugins admin panel won\'t have an effect as long as this option '
     326                . 'in enabled.',
     327                default: false,
     328            ),
     329            'enable_telemetry_listener' => new Setting(
     330                id: 'enable_telemetry_listener',
     331                type: SettingType::Boolean,
     332                helpText: 'Enables the collection of telemetry data to help debug issues.',
     333                default: true,
     334                section: 'rollbar_wp_telemetry',
     335            ),
     336            'include_items_in_telemetry' => new Setting(
     337                id: 'include_items_in_telemetry',
     338                type: SettingType::Boolean,
     339                helpText: 'Include Rollbar captured exceptions and messages in the telemetry data of future exceptions '
     340                . 'and messages.',
     341                default: true,
     342                section: 'rollbar_wp_telemetry',
     343            ),
     344            'include_ignored_items_in_telemetry' => new Setting(
     345                id: 'include_ignored_items_in_telemetry',
     346                type: SettingType::Boolean,
     347                helpText: 'Include Rollbar captured exceptions and messages in the telemetry data of future exceptions '
     348                . 'and messages even if they they are ignored because they have a lower level.',
     349                default: false,
     350                section: 'rollbar_wp_telemetry',
     351            ),
     352            'telemetry_hooks' => new Setting(
     353                id: 'telemetry_hooks',
     354                type: SettingType::CheckBox,
     355                label: 'Enable Telemetry Actions',
     356                helpText: 'Adds a telemetry event for each action that is hooked enabled in this list.',
     357                default: array_keys(Listener::DEFAULT_ACTIONS),
     358                options: array_combine(array_keys(Listener::ALL_ACTIONS), array_keys(Listener::ALL_ACTIONS)),
     359                section: 'rollbar_wp_telemetry',
     360                inputArgs: [
     361                    'sort' => true,
     362                ],
     363            ),
     364            // The following fields are intentionally left out of the Admin UI. They will be set later in the plugin or
     365            // can be programmed by an end user in their WP site.
     366            'access_token' => null,
     367            'ca_cert_path' => null,
     368            'check_ignore' => null,
     369            'custom' => null,
     370            'custom_data_method' => null,
     371            'custom_truncation' => null,
     372            'base_api_url' => null,
     373            'enabled' => null,
     374            'error_sample_rates' => null,
     375            'exception_sample_rates' => null,
     376            'log_payload_logger' => null,
     377            'person' => null,
     378            'person_fn' => null,
     379            'scrubber' => null,
     380            'scrub_fields' => null,
     381            'scrub_safelist' => null,
     382            'transformer' => null,
     383            'telemetry' => null,
     384            'verbose_logger' => null,
     385        ];
     386        return $settings;
     387    }
     388
     389    /**
     390     * Returns the type of the setting, otherwise null if the key is not found, or it is skipped.
     391     *
     392     * @param string $key The setting key.
     393     * @return SettingType|null
     394     */
     395    public static function getSettingType(string $key): null|SettingType
     396    {
     397        return self::settings()[$key]?->type ?? null;
     398    }
     399
     400    /**
     401     * Returns the default value for a setting.
     402     *
     403     * @param string $setting
     404     * @return mixed
     405     */
     406    public static function getDefaultOption(string $setting): mixed
     407    {
     408        return self::settings()[$setting]?->default ?? null;
     409    }
     410
     411    /**
     412     * The filter applied before the `rollbar_wp` settings are saved to the DB.
     413     *
     414     * @param array $settings The array of settings.
     415     * @return array
     416     */
     417    public static function preUpdate(array $settings): array
     418    {
     419        // Empty checkboxes don't get sent in the $_POST. Fill missing boolean settings with default values.
     420        foreach (Settings::settings() as $setting) {
     421            if (null == $setting || isset($settings[$setting->id]) || SettingType::Boolean !== $setting->type) {
    171422                continue;
    172423            }
    173            
    174             // TODO: https://github.com/rollbar/rollbar-php-wordpress/issues/41
    175             if (UI::getSettingType($option) == UI::SETTING_INPUT_TYPE_PHP) {
    176                 continue;
    177             }
    178            
    179             $this->addSetting($option, 'rollbar_wp_advanced');
    180         }
    181        
    182         $this->addSetting(
    183             'enable_must_use_plugin',
    184             'rollbar_wp_advanced',
    185             array(
    186                 'type' => UI::getSettingType('enable_must_use_plugin'),
    187                 'default' => \Rollbar\Wordpress\Defaults::instance()->enableMustUsePlugin(),
    188                 'description' => __('Allows Rollbar plugin to be loaded as early ' .
    189                                     'as possible as a Must-Use plugin. Activating / ' .
    190                                     'deactivating the plugin in the plugins admin panel ' .
    191                                     'won\'t have an effect as long as this option in enabled.', 'rollbar'),
    192                 'display_name' => __('Enable as a Must-Use plugin', 'rollbar')
    193             )
    194         );
    195     }
    196    
    197     private function addSetting($setting, $section, array $overrides = array())
    198     {
    199         $type = isset($overrides['type']) ?
    200             $overrides['type'] :
    201             UI::getSettingType($setting);
    202            
    203         $options = isset($overrides['options']) ?
    204             $overrides['options'] :
    205             UI::getSettingOptions($setting);
    206            
    207         if ($type === false || $options === false) {
    208             return;
    209         }
    210        
    211         $display_name = isset($overrides['display_name']) ?
    212             $overrides['display_name'] :
    213             ucfirst(str_replace("_", " ", $setting));
    214        
    215         if (isset($overrides['description'])) {
    216             $description = $overrides['description'];
    217         } else {
    218             $description = $this->parseSettingDescription($setting);
    219         }
    220            
    221         $default = isset($overrides['default']) ?
    222             $overrides['default'] :
    223             $this->settingDefault($setting);
    224            
    225         $value = $this->setting($setting);
    226        
    227         \add_settings_field(
    228             'rollbar_wp_' . $setting,
    229             __($display_name, 'rollbar'),
    230             array('Rollbar\Wordpress\UI', 'setting'),
    231             'rollbar_wp',
    232             $section,
    233             array(
    234                 'label_for' => 'rollbar_wp_' . $setting,
    235                 'name' => $setting,
    236                 'display_name' => $display_name,
    237                 'value' => $value,
    238                 'description' => $description,
    239                 'type' => $type,
    240                 'options' => $options,
    241                 'default' => $default
    242             )
    243         );
    244     }
    245    
    246     private function setting($setting)
    247     {
    248         return $this->settingToString($this->plugin->setting($setting));
    249     }
    250    
    251     private function settingToString($value)
    252     {
    253         if (is_string($value)) {
    254             $value = esc_attr(trim($value));
    255         } else if (is_array($value)) {
    256             $value = var_export($value, true);
    257         }
    258        
    259         return $value;
    260     }
    261    
    262     public function settingDefault($setting)
    263     {
    264         return $this->settingToString($this->plugin->getDefaultOption($setting));
    265     }
    266    
    267     public function advancedSectionHeader()
    268     {
    269         $output = '';
    270        
    271         $output .=  "<h3 class='hover-pointer' id='rollbar_settings_advanced_header'>" .
    272                     "   <span id='rollbar_settings_advanced_toggle'>►</span> " .
    273                     "   Advanced" .
    274                     "</h3>";
    275        
    276         $output .=  "<div id='rollbar_settings_advanced' style='display:none;'>";
    277        
    278         echo $output;
    279     }
    280 
    281     function optionsPage()
    282     {
    283        
    284         UI::flashMessage();
    285        
    286         ?>
    287         <form action='options.php' method='post'>
    288 
    289             <h2 class="rollbar-header">
    290                 <img class="logo" alt="Rollbar" src="//cdn.rollbar.com/static/img/rollbar-icon-white.svg?ts=1548370449v8" width="auto" height="24">
    291                 Rollbar for WordPress
    292             </h2>
    293 
    294             <?php
    295             \settings_fields('rollbar_wp');
    296             \do_settings_sections('rollbar_wp');
    297             ?>
    298             </div>
    299            
    300             <?php
    301             \submit_button();
    302             ?>
    303 
    304         </form>
    305         <?php
    306        
    307         UI::restoreAllDefaultsButton();
    308         UI::testButton();
    309     }
    310    
    311     private function parseSettingDescription($option)
    312     {
    313        
    314         if ( version_compare( PHP_VERSION, '8.0.0', '<' ) ) {
    315             $readme = file_get_contents(__DIR__ . '/../php7/vendor/rollbar/rollbar/README.md');
    316         } else {
    317             $readme = file_get_contents(__DIR__ . '/../php8/vendor/rollbar/rollbar/README.md');
    318         }
    319        
    320         $option_pos = stripos($readme, '<dt>' . $option);
    321 
    322         $desc = '';
    323        
    324         if ($option_pos !== false) {
    325        
    326             $desc_pos = stripos($readme, '<dd>', $option_pos) + strlen('<dd>');
    327            
    328             $desc_close = stripos($readme, '</dd>', $desc_pos);
    329            
    330             $desc = substr($readme, $desc_pos, $desc_close - $desc_pos);
    331            
    332         }
    333        
    334         $desc = str_replace('```php', '```', $desc);
    335         $desc = Markdown::defaultTransform($desc);
    336         $desc = str_replace('```', '', $desc);
    337        
    338         return $desc;
    339     }
    340    
    341     public static function restoreDefaultsAction()
    342     {
    343         \Rollbar\Wordpress\Plugin::instance()->restoreDefaults();
    344        
    345         self::flashRedirect(
    346             "updated",
    347             __("Default Rollbar settings restored.", "rollbar")
    348         );
    349     }
    350    
    351     public static function flashRedirect($type, $message)
    352     {
    353         self::flashMessage($type, $message);
    354        
    355         wp_redirect(admin_url('/options-general.php?page=rollbar_wp'));
    356     }
    357    
    358     public static function flashMessage($type, $message)
    359     {
    360         // This is only designed to run in the admin for the main HTML request.
    361         // If there is no session at this point something has gone terribly
    362         // wrong, and we should bail out.
    363         if( ! is_admin() || ! session_id() || wp_doing_cron() ) {
    364             return;
    365         }
    366 
    367         $_SESSION['rollbar_wp_flash_message'] = array(
    368             "type" => $type,
    369             "message" => $message
    370         );
    371     }
    372    
    373     public static function preUpdate($settings)
    374     {
    375        
    376         // Empty checkboxes don't get propagated into the $_POST at all. Fill out
    377         // missing boolean settings with default values.
    378         foreach (UI::settingsOfType(UI::SETTING_INPUT_TYPE_BOOLEAN) as $setting) {
    379            
    380             if (!isset($settings[$setting])) {
    381                 $settings[$setting] = false;
    382             }
    383            
    384         }
    385        
    386         $settings['enabled'] = isset($settings['php_logging_enabled']) && $settings['php_logging_enabled'];
    387    
     424            $settings[$setting->id] = false;
     425        }
     426
     427        $settings['enabled'] = $settings['php_logging_enabled'] ?? false;
     428
    388429        if (isset($settings['enable_must_use_plugin']) && $settings['enable_must_use_plugin']) {
    389430            try {
    390                 Plugin::instance()->enableMustUsePlugin();
     431                Plugin::getInstance()->enableMustUsePlugin();
    391432            } catch (\Exception $exception) {
    392433                add_action('admin_notices', function () {
    393                     echo '<div class="error notice"><p><strong>Error:</strong> failed to enable the Rollbar Must-Use plugin.</p></div>';
     434                    echo '<div class="error notice"><p><strong>Error:</strong>'
     435                    . 'failed to enable the Rollbar Must-Use plugin.</p></div>';
    394436                });
    395437                $settings['enable_must_use_plugin'] = false;
     
    397439        } else {
    398440            try {
    399                 Plugin::instance()->disableMustUsePlugin();
     441                Plugin::getInstance()->disableMustUsePlugin();
    400442            } catch (\Exception $exception) {
    401443                add_action('admin_notices', function () {
    402                     echo '<div class="error notice"><p><strong>Error:</strong> failed to disable the Rollbar Must-Use plugin.</p></div>';
     444                    echo '<div class="error notice"><p><strong>Error:</strong>'
     445                        . 'failed to disable the Rollbar Must-Use plugin.</p></div>';
    403446                });
    404447                $settings['enable_must_use_plugin'] = true;
    405448            }
    406449        }
    407        
    408         // Don't store default values in the database. This is so that future updates
    409         // to default values in PHP SDK don't get stored in users databases.
     450
     451        // Don't store default values in the database, so future updates to default values in the SDK get propagated.
    410452        foreach ($settings as $setting_name => $setting_value) {
    411             if ($setting_value == Plugin::instance()->getDefaultOption($setting_name)) {
     453            // Loose comparison to allow for boolean values to be set to 0 or 1 and integers to be strings, which is how
     454            // they are posted via HTTP.
     455            if ($setting_value == Plugin::getInstance()->settingsInstance()->getDefaultOption($setting_name)) {
    412456                unset($settings[$setting_name]);
    413457            }
    414458        }
    415        
     459
    416460        return $settings;
    417461    }
     462
     463    /**
     464     * Returns all the settings as an array.
     465     *
     466     * @return array
     467     */
     468    public function getAll(): array
     469    {
     470        return $this->settings;
     471    }
     472
     473    /**
     474     * Returns a single setting, otherwise null if the $name is invalid.
     475     *
     476     * @param string $name The setting name.
     477     * @return mixed
     478     */
     479    public function get(string $name): mixed
     480    {
     481        return $this->settings[$name] ?? null;
     482    }
     483
     484    /**
     485     * Sets a value to the setting of the given name.
     486     *
     487     * @param string $name The name of the setting.
     488     * @param mixed $value The value of the setting.
     489     * @return void
     490     */
     491    public function set(string $name, mixed $value): void
     492    {
     493        $this->settings[$name] = $value;
     494    }
     495
     496    /**
     497     * Save settings to the DB.
     498     *
     499     * @param array $settings
     500     * @return void
     501     */
     502    public function saveSettings(array $settings): void
     503    {
     504        $option = get_option('rollbar_wp');
     505
     506        $option = array_merge($option, $settings);
     507
     508        foreach ($settings as $setting => $value) {
     509            $this->settings[$setting] = $value;
     510        }
     511
     512        update_option('rollbar_wp', $option);
     513    }
     514
     515    /**
     516     * Sets all the settings back to the default value.
     517     *
     518     * @return void
     519     */
     520    public function restoreDefaults(): void
     521    {
     522        $settings = [];
     523
     524        foreach (Settings::listOptions() as $option) {
     525            $settings[$option] = $this->getDefaultOption($option);
     526        }
     527
     528        $this->saveSettings($settings);
     529    }
     530
     531    /**
     532     * Returns the array of option names for the Rollbar configs.
     533     *
     534     * @return string[]
     535     */
     536    public static function listOptions(): array
     537    {
     538        return array_merge(
     539            Config::listOptions(),
     540            array_keys(self::settings()),
     541        );
     542    }
     543
     544    /**
     545     * Returns a reasonable boolean from a given value.
     546     *
     547     * @param mixed $value
     548     * @return bool
     549     */
     550    public static function toBoolean(mixed $value): bool
     551    {
     552        if (is_bool($value)) {
     553            return $value;
     554        }
     555        if (is_string($value)) {
     556            return in_array(strtolower($value), ['true', '1', 'yes', 'on']);
     557        }
     558        if (is_int($value)) {
     559            return $value !== 0;
     560        }
     561        return boolval($value);
     562    }
     563
     564    /**
     565     * Returns a reasonable integer from a given value.
     566     *
     567     * @param mixed $value The value to convert to an integer.
     568     * @return int
     569     */
     570    public static function toInteger(mixed $value): int
     571    {
     572        if (is_int($value)) {
     573            return $value;
     574        }
     575        if (is_string($value)) {
     576            return intval($value);
     577        }
     578        if (is_bool($value)) {
     579            return $value ? 1 : 0;
     580        }
     581        if (is_numeric($value)) {
     582            return intval($value);
     583        }
     584        return 0;
     585    }
     586
     587    /**
     588     * Returns a reasonable string from a given value.
     589     *
     590     * @param mixed $value The value to convert to a string.
     591     * @return string
     592     */
     593    public static function toString(mixed $value): string
     594    {
     595        if (is_string($value)) {
     596            return $value;
     597        }
     598        if (is_bool($value)) {
     599            return $value ? 'true' : 'false';
     600        }
     601        if (is_int($value)) {
     602            return (string) $value;
     603        }
     604        if (is_numeric($value)) {
     605            return (string) $value;
     606        }
     607        return '';
     608    }
     609
     610    /**
     611     * Returns an array of strings from a given value.
     612     *
     613     * @param mixed $value The value to convert to an array of strings.
     614     * @return string[]
     615     */
     616    public static function toStringArray(mixed $value): array
     617    {
     618        if (is_array($value)) {
     619            return array_map(fn($v) => self::toString($v), $value);
     620        }
     621        if (is_string($value)) {
     622            return [$value];
     623        }
     624        return [];
     625    }
     626
     627    /**
     628     * Fetch settings provided in Admin -> Tools -> Rollbar
     629     *
     630     * @returns void
     631     */
     632    private function fetchSettings(): void
     633    {
     634        $options = $this->settings;
     635
     636        if (!Plugin::disabledAdmin() && $saved_options = get_option(self::OPTIONS_KEY)) {
     637            $options = array_merge($options, $saved_options);
     638        }
     639        if (defined('ROLLBAR_SETTINGS') && is_array(constant('ROLLBAR_SETTINGS'))) {
     640            $options = array_merge($options, constant('ROLLBAR_SETTINGS'));
     641        }
     642
     643        $options['environment'] = self::getEnvironment($options['environment'] ?? null);
     644        $options['proxy'] = self::getProxySettings($options['proxy'] ?? null);
     645        $options['server_side_access_token'] = self::getServerAccessToken(
     646            $options['server_side_access_token'] ?? null,
     647        );
     648        $options['client_side_access_token'] = self::getClientAccessToken(
     649            $options['client_side_access_token'] ?? null,
     650        );
     651
     652        $this->settings = self::normalizeSettings($options);
     653    }
     654
     655    /**
     656     * Normalizes the settings array to ensure all required fields are set and properly formatted.
     657     *
     658     * @param array<string, mixed> $options
     659     * @return array
     660     */
     661    public static function normalizeSettings(array $options): array
     662    {
     663        $settings = [
     664            'php_logging_enabled' => (!empty($options['php_logging_enabled'])) ? 1 : 0,
     665            'js_logging_enabled' => (!empty($options['js_logging_enabled'])) ? 1 : 0,
     666            'server_side_access_token' => (!empty($options['server_side_access_token'])) ?
     667                esc_attr(trim($options['server_side_access_token'])) :
     668                '',
     669            'client_side_access_token' => (!empty($options['client_side_access_token'])) ?
     670                esc_attr(trim($options['client_side_access_token'])) :
     671                '',
     672            'included_errno' => (!empty($options['included_errno'])) ?
     673                esc_attr(trim($options['included_errno'])) :
     674                self::getDefaultOption('included_errno'),
     675        ];
     676
     677        // Filter out options that are not in the list of options.
     678        $options = array_intersect_key($options, array_flip(self::listOptions()));
     679
     680        foreach (self::settings() as $key => $setting) {
     681            // 'access_token' and 'enabled' are different in WordPress plugin
     682            // look for 'server_side_access_token' and 'php_logging_enabled' above
     683            if (in_array($key, ['access_token', 'enabled'])) {
     684                continue;
     685            }
     686
     687            $value = $options[$key] ?? ($setting?->default ?? null);
     688            if ($setting !== null) {
     689                $value = $setting->coerceValue($value);
     690            } elseif (!isset($options[$key])) {
     691                continue;
     692            }
     693            $settings[$key] = $value;
     694        }
     695
     696        /**
     697         * Filter the Rollbar plugin settings.
     698         *
     699         * @param array $settings The Rollbar plugin settings array.
     700         * @since 3.0.0
     701         *
     702         */
     703        return apply_filters('rollbar_plugin_settings', $settings);
     704    }
     705
     706    /**
     707     * Returns the provided environment if set, otherwise retrieves it from the system config or environment.
     708     *
     709     * @param string|null $environment The current environment value.
     710     * @return string|null
     711     */
     712    public static function getEnvironment(string|null $environment): string|null
     713    {
     714        if (null !== $environment) {
     715            $environment = trim($environment);
     716        }
     717        if (empty($environment)) {
     718            $environment = null;
     719        }
     720        $environment = trim(self::getSystemSetting('WP_ENV', $environment) ?? '');
     721        if (!empty($environment)) {
     722            return $environment;
     723        }
     724        return trim(self::getSystemSetting('WP_ENVIRONMENT_TYPE', $environment) ?? '');
     725    }
     726
     727    /**
     728     * The default `person_fn` method.
     729     *
     730     * @return array|null
     731     */
     732    public static function getPersonFunction(): null|array
     733    {
     734        $user = wp_get_current_user();
     735        if (!$user) {
     736            return null;
     737        }
     738        return [
     739            'id' => $user->ID,
     740            'username' => $user->user_login,
     741            'email' => $user->user_email,
     742        ];
     743    }
     744
     745    /**
     746     * Returns the provided client access token if set, otherwise retrieves it from the system config or environment.
     747     *
     748     * @param string|null $token The current access token value.
     749     * @return string|null The access token to use for the frontend.
     750     */
     751    private static function getClientAccessToken(string|null $token): string|null
     752    {
     753        if (!empty($token)) {
     754            $token = trim($token);
     755        }
     756        if (empty($token)) {
     757            $token = null;
     758        }
     759        return trim(self::getSystemSetting('ROLLBAR_CLIENT_ACCESS_TOKEN', $token) ?? '');
     760    }
     761
     762    /**
     763     * Returns the provided server access token if set, otherwise retrieves it from the system config or environment.
     764     *
     765     * @param string|null $token The current access token value.
     766     * @return string|null The access token to use server-side.
     767     */
     768    private static function getServerAccessToken(string|null $token): string|null
     769    {
     770        if (!empty($token)) {
     771            $token = trim($token);
     772        }
     773        if (empty($token)) {
     774            $token = null;
     775        }
     776        return trim(self::getSystemSetting('ROLLBAR_ACCESS_TOKEN', $token) ?? '');
     777    }
     778
     779    /**
     780     * Retrieves the specified setting from either a constant or environment variable.
     781     *
     782     * If the default is provided, it will be used if the constant does not exist. If the default is `null`, the
     783     * environment variable will be used if it exists. Otherwise, `null` will be returned.
     784     *
     785     * @param string $key The name of the constant or environment variable.
     786     * @param mixed $default The default value to use if the setting is not found.
     787     * @return mixed The value of the constant, environment variable, the default, or null.
     788     */
     789    private static function getSystemSetting(string $key, mixed $default = null): mixed
     790    {
     791        if (defined($key)) {
     792            return constant($key);
     793        }
     794        if (null !== $default) {
     795            return $default;
     796        }
     797        if ($value = getenv($key)) {
     798            return $value;
     799        }
     800        return $default;
     801    }
     802
     803    /**
     804     * Retrieves the proxy settings based on provided input or system config.
     805     *
     806     * @param string|array|null $proxy The proxy settings as string, array, or null. If null or empty, attempts to fetch
     807     *                                 system-defined proxy constants.
     808     *
     809     * @return string|array|null The proxy settings in string, array, or null if no proxy is defined or enabled.
     810     */
     811    private function getProxySettings(string|array|null $proxy): string|array|null
     812    {
     813        if (!empty($proxy)) {
     814            return $proxy;
     815        }
     816        $proxy = new WP_HTTP_Proxy();
     817        if (!$proxy->is_enabled() || !$proxy->send_through_proxy('https://api.rollbar.com/api')) {
     818            return null;
     819        }
     820        $proxySettings = [
     821            'address' => $proxy->host() . ':' . $proxy->port(),
     822        ];
     823        if ($proxy->username() && $proxy->password()) {
     824            $proxySettings['username'] = $proxy->username();
     825            $proxySettings['password'] = $proxy->password();
     826        }
     827        return $proxySettings;
     828    }
    418829}
    419 
    420 ?>
Note: See TracChangeset for help on using the changeset viewer.