├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock └── src ├── Config.php ├── Extensions ├── GoogleImageExtension.php └── GoogleVideoExtension.php ├── FileSystem.php ├── IConfig.php ├── IFileSystem.php ├── IRuntime.php ├── Runtime.php └── SitemapGenerator.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dmitrii Prisacari 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Sitemap Generator 2 | 3 | ![CI status](https://github.com/icamys/php-sitemap-generator/actions/workflows/ci.yml/badge.svg) 4 | [![codecov.io](https://codecov.io/github/icamys/php-sitemap-generator/coverage.svg?branch=master)](https://codecov.io/github/icamys/php-sitemap-generator?branch=master) 5 | [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%208.0-8892BF.svg)](https://php.net/) 6 | [![Latest Stable Version](https://poser.pugx.org/icamys/php-sitemap-generator/v/stable.png)](https://packagist.org/packages/icamys/php-sitemap-generator) 7 | [![Total Downloads](https://poser.pugx.org/icamys/php-sitemap-generator/downloads)](https://packagist.org/packages/icamys/php-sitemap-generator) 8 | 9 | Library for sitemap generation and submission. 10 | 11 | Features: 12 | * Follows [sitemaps.org](https://sitemaps.org/) protocol 13 | * Supports alternative links for multi-language pages (see [google documentation](https://webmasters.googleblog.com/2012/05/multilingual-and-multinational-site.html)) 14 | * Supports video and image sitemap generation 15 | * Low memory usage for any amount of URLs 16 | * Supports sitemap stylesheets 17 | 18 | Installation with Composer: 19 | 20 | ``` 21 | composer require icamys/php-sitemap-generator 22 | ``` 23 | 24 | ## Survey 25 | 26 | If you found this package useful, please [take a short survey](https://forms.gle/ngeponiTd1zWgmkC9) to improve your sitemap generation experience. 27 | 28 | ## Usage 29 | 30 | ```php 31 | setBaseURL('https://example.com'); 39 | 40 | // OPTIONAL. Setting the current working directory to be output directory 41 | // for generated sitemaps (and, if needed, robots.txt) 42 | // The output directory setting is optional and provided for demonstration purposes. 43 | // The generator writes output to the current directory by default. 44 | $config->setSaveDirectory(sys_get_temp_dir()); 45 | 46 | // OPTIONAL. Setting a custom sitemap URL base in case if the sitemap files location 47 | // is different from the website root. Most of the time this is unnecessary and can be skipped. 48 | $config->setSitemapIndexURL('https://example.com/sitemaps/'); 49 | 50 | $generator = new \Icamys\SitemapGenerator\SitemapGenerator($config); 51 | 52 | // Create a compressed sitemap 53 | $generator->enableCompression(); 54 | 55 | // Determine how many urls should be put into one file; 56 | // this feature is useful in case if you have too large urls 57 | // and your sitemap is out of allowed size (50Mb) 58 | // according to the standard protocol 50000 urls per sitemap 59 | // is the maximum allowed value (see http://www.sitemaps.org/protocol.html) 60 | $generator->setMaxURLsPerSitemap(50000); 61 | 62 | // Set the sitemap file name 63 | $generator->setSitemapFileName("sitemap.xml"); 64 | 65 | // Set the sitemap index file name 66 | $generator->setSitemapIndexFileName("sitemap-index.xml"); 67 | 68 | // Add alternate languages if needed 69 | $alternates = [ 70 | ['hreflang' => 'de', 'href' => "http://www.example.com/de"], 71 | ['hreflang' => 'fr', 'href' => "http://www.example.com/fr"], 72 | ]; 73 | 74 | // Add url components: `path`, `lastmodified`, `changefreq`, `priority`, `alternates` 75 | // Instead of storing all urls in the memory, the generator will flush sets of added urls 76 | // to the temporary files created on your disk. 77 | // The file format is 'sm-{index}-{timestamp}.xml' 78 | $generator->addURL('/path/to/page/', new DateTime(), 'always', 0.5, $alternates); 79 | 80 | // Optional: add sitemap stylesheet. Note that you need to create 81 | // the file 'sitemap.xsl' beforehand on your own. 82 | $generator->setSitemapStylesheet('sitemap.xsl'); 83 | 84 | // Flush all stored urls from memory to the disk and close all necessary tags. 85 | $generator->flush(); 86 | 87 | // Move flushed files to their final location. Compress if the option is enabled. 88 | $generator->finalize(); 89 | 90 | // Update robots.txt file in output directory or create a new one 91 | $generator->updateRobots(); 92 | 93 | // Submit your sitemaps to Yandex. 94 | $generator->submitSitemap(); 95 | ``` 96 | 97 | ### Video sitemap example 98 | 99 | To create video sitemap, pass the `$extensions` parameter to the `addURL()` method as follows: 100 | 101 | ```php 102 | 'http://www.example.com/thumbs/123.jpg', 112 | 'title' => 'Grilling steaks for summer', 113 | 'description' => 'Alkis shows you how to get perfectly done steaks every time', 114 | 'content_loc' => 'http://streamserver.example.com/video123.mp4', 115 | 'player_loc' => 'http://www.example.com/videoplayer.php?video=123', 116 | 'duration' => 600, 117 | 'expiration_date' => '2021-11-05T19:20:30+08:00', 118 | 'rating' => 4.2, 119 | 'view_count' => 12345, 120 | 'publication_date' => '2007-11-05T19:20:30+08:00', 121 | 'family_friendly' => 'yes', 122 | 'restriction' => [ 123 | 'relationship' => 'allow', 124 | 'value' => 'IE GB US CA', 125 | ], 126 | 'platform' => [ 127 | 'relationship' => 'allow', 128 | 'value' => 'web mobile', 129 | ], 130 | 'price' => [ 131 | [ 132 | 'currency' => 'EUR', 133 | 'value' => 1.99, 134 | 'type' => 'rent', 135 | 'resolution' => 'hd', 136 | ] 137 | ], 138 | 'requires_subscription' => 'yes', 139 | 'uploader' => [ 140 | 'info' => 'https://example.com/users/grillymcgrillerson', 141 | 'value' => 'GrillyMcGrillerson', 142 | ], 143 | 'live' => 'no', 144 | 'tag' => [ 145 | "steak", "meat", "summer", "outdoor" 146 | ], 147 | 'category' => 'baking', 148 | ]; 149 | 150 | 151 | $extensions = [ 152 | 'google_video' => $videoTags 153 | ]; 154 | 155 | $generator->addURL('/path/to/page/', null, null, null, null, $extensions); 156 | 157 | // generate, flush, etc. 158 | // ... 159 | ``` 160 | 161 | 162 | ### Image sitemap example 163 | 164 | To create image sitemap, pass the `$extensions` parameter to the `addURL()` method as follows: 165 | 166 | ```php 167 | 'https://www.example.com/thumbs/123.jpg', 177 | 'title' => 'Cat vs Cabbage', 178 | 'caption' => 'A funny picture of a cat eating cabbage', 179 | 'geo_location' => 'Lyon, France', 180 | 'license' => 'https://example.com/image-license', 181 | ]; 182 | 183 | // Alternatively, if you need to pass multiple images per URL, use the format below. 184 | // Maximum number of images per URL is 1000. 185 | $imageTags = [ 186 | [ 187 | 'loc' => 'https://www.example.com/thumbs/123.jpg', 188 | 'title' => 'Cat vs Cabbage', 189 | 'caption' => 'A funny picture of a cat eating cabbage', 190 | 'geo_location' => 'Lyon, France', 191 | 'license' => 'https://example.com/image-license', 192 | ], 193 | [ 194 | 'loc' => 'https://www.example.com/thumbs/456.jpg', 195 | 'title' => 'Dog vs Carrot', 196 | 'caption' => 'A funny picture of a dog eating carrot', 197 | 'geo_location' => 'Lyon, France', 198 | 'license' => 'https://example.com/image-license', 199 | ] 200 | ]; 201 | 202 | $extensions = [ 203 | 'google_image' => $imageTags 204 | ]; 205 | 206 | $generator->addURL('/path/to/page/', null, null, null, null, $extensions); 207 | 208 | // generate, flush, etc. 209 | // ... 210 | ``` 211 | 212 | ## Testing 213 | 214 | Run tests with command: 215 | 216 | ```bash 217 | $ ./vendor/bin/phpunit 218 | ``` 219 | 220 | Run code coverage: 221 | 222 | ```bash 223 | $ XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-html ./coverage 224 | ``` 225 | 226 | ## Changelog 227 | 228 | You can find full changelog on the [releases page](https://github.com/icamys/php-sitemap-generator/releases). 229 | 230 | ## Todo 231 | 232 | * Remove `$yahooAppId` parameter. 233 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "icamys/php-sitemap-generator", 3 | "description": "Simple PHP sitemap generator.", 4 | "keywords": ["php", "sitemap", "generator", "psr-1", "psr-2", "psr-4"], 5 | "homepage": "https://github.com/icamys/php-sitemap-generator", 6 | "type": "library", 7 | "license": "MIT", 8 | "minimum-stability": "stable", 9 | "authors": [ 10 | { 11 | "name": "Dmitrii Prisacari", 12 | "email": "prisacari.dmitrii@gmail.com", 13 | "homepage": "https://github.com/icamys/" 14 | } 15 | ], 16 | "require": { 17 | "php": "^8.0", 18 | "ext-curl": "*", 19 | "ext-dom": "*", 20 | "ext-mbstring": "*", 21 | "ext-simplexml": "*", 22 | "ext-SPL": "*", 23 | "ext-xml": "*", 24 | "ext-xmlwriter": "*", 25 | "ext-zlib": "*" 26 | }, 27 | "autoload": { 28 | "psr-4": {"Icamys\\SitemapGenerator\\": "src/"} 29 | }, 30 | "autoload-dev": { 31 | "psr-0": { 32 | "Icamys\\SitemapGenerator\\Tests\\": "test/" 33 | } 34 | }, 35 | "require-dev": { 36 | "phpunit/phpunit": "^9.6", 37 | "php-mock/php-mock-phpunit": "^2.7", 38 | "vimeo/psalm": "^5.15" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "c1b3fc1eb5f240393732c8a7d0f0acb5", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "amphp/amp", 12 | "version": "v2.6.2", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/amphp/amp.git", 16 | "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", 21 | "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": ">=7.1" 26 | }, 27 | "require-dev": { 28 | "amphp/php-cs-fixer-config": "dev-master", 29 | "amphp/phpunit-util": "^1", 30 | "ext-json": "*", 31 | "jetbrains/phpstorm-stubs": "^2019.3", 32 | "phpunit/phpunit": "^7 | ^8 | ^9", 33 | "psalm/phar": "^3.11@dev", 34 | "react/promise": "^2" 35 | }, 36 | "type": "library", 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "2.x-dev" 40 | } 41 | }, 42 | "autoload": { 43 | "files": [ 44 | "lib/functions.php", 45 | "lib/Internal/functions.php" 46 | ], 47 | "psr-4": { 48 | "Amp\\": "lib" 49 | } 50 | }, 51 | "notification-url": "https://packagist.org/downloads/", 52 | "license": [ 53 | "MIT" 54 | ], 55 | "authors": [ 56 | { 57 | "name": "Daniel Lowrey", 58 | "email": "rdlowrey@php.net" 59 | }, 60 | { 61 | "name": "Aaron Piotrowski", 62 | "email": "aaron@trowski.com" 63 | }, 64 | { 65 | "name": "Bob Weinand", 66 | "email": "bobwei9@hotmail.com" 67 | }, 68 | { 69 | "name": "Niklas Keller", 70 | "email": "me@kelunik.com" 71 | } 72 | ], 73 | "description": "A non-blocking concurrency framework for PHP applications.", 74 | "homepage": "https://amphp.org/amp", 75 | "keywords": [ 76 | "async", 77 | "asynchronous", 78 | "awaitable", 79 | "concurrency", 80 | "event", 81 | "event-loop", 82 | "future", 83 | "non-blocking", 84 | "promise" 85 | ], 86 | "support": { 87 | "irc": "irc://irc.freenode.org/amphp", 88 | "issues": "https://github.com/amphp/amp/issues", 89 | "source": "https://github.com/amphp/amp/tree/v2.6.2" 90 | }, 91 | "funding": [ 92 | { 93 | "url": "https://github.com/amphp", 94 | "type": "github" 95 | } 96 | ], 97 | "time": "2022-02-20T17:52:18+00:00" 98 | }, 99 | { 100 | "name": "amphp/byte-stream", 101 | "version": "v1.8.1", 102 | "source": { 103 | "type": "git", 104 | "url": "https://github.com/amphp/byte-stream.git", 105 | "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" 106 | }, 107 | "dist": { 108 | "type": "zip", 109 | "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", 110 | "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", 111 | "shasum": "" 112 | }, 113 | "require": { 114 | "amphp/amp": "^2", 115 | "php": ">=7.1" 116 | }, 117 | "require-dev": { 118 | "amphp/php-cs-fixer-config": "dev-master", 119 | "amphp/phpunit-util": "^1.4", 120 | "friendsofphp/php-cs-fixer": "^2.3", 121 | "jetbrains/phpstorm-stubs": "^2019.3", 122 | "phpunit/phpunit": "^6 || ^7 || ^8", 123 | "psalm/phar": "^3.11.4" 124 | }, 125 | "type": "library", 126 | "extra": { 127 | "branch-alias": { 128 | "dev-master": "1.x-dev" 129 | } 130 | }, 131 | "autoload": { 132 | "files": [ 133 | "lib/functions.php" 134 | ], 135 | "psr-4": { 136 | "Amp\\ByteStream\\": "lib" 137 | } 138 | }, 139 | "notification-url": "https://packagist.org/downloads/", 140 | "license": [ 141 | "MIT" 142 | ], 143 | "authors": [ 144 | { 145 | "name": "Aaron Piotrowski", 146 | "email": "aaron@trowski.com" 147 | }, 148 | { 149 | "name": "Niklas Keller", 150 | "email": "me@kelunik.com" 151 | } 152 | ], 153 | "description": "A stream abstraction to make working with non-blocking I/O simple.", 154 | "homepage": "http://amphp.org/byte-stream", 155 | "keywords": [ 156 | "amp", 157 | "amphp", 158 | "async", 159 | "io", 160 | "non-blocking", 161 | "stream" 162 | ], 163 | "support": { 164 | "irc": "irc://irc.freenode.org/amphp", 165 | "issues": "https://github.com/amphp/byte-stream/issues", 166 | "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" 167 | }, 168 | "funding": [ 169 | { 170 | "url": "https://github.com/amphp", 171 | "type": "github" 172 | } 173 | ], 174 | "time": "2021-03-30T17:13:30+00:00" 175 | }, 176 | { 177 | "name": "composer/pcre", 178 | "version": "3.1.0", 179 | "source": { 180 | "type": "git", 181 | "url": "https://github.com/composer/pcre.git", 182 | "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" 183 | }, 184 | "dist": { 185 | "type": "zip", 186 | "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", 187 | "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", 188 | "shasum": "" 189 | }, 190 | "require": { 191 | "php": "^7.4 || ^8.0" 192 | }, 193 | "require-dev": { 194 | "phpstan/phpstan": "^1.3", 195 | "phpstan/phpstan-strict-rules": "^1.1", 196 | "symfony/phpunit-bridge": "^5" 197 | }, 198 | "type": "library", 199 | "extra": { 200 | "branch-alias": { 201 | "dev-main": "3.x-dev" 202 | } 203 | }, 204 | "autoload": { 205 | "psr-4": { 206 | "Composer\\Pcre\\": "src" 207 | } 208 | }, 209 | "notification-url": "https://packagist.org/downloads/", 210 | "license": [ 211 | "MIT" 212 | ], 213 | "authors": [ 214 | { 215 | "name": "Jordi Boggiano", 216 | "email": "j.boggiano@seld.be", 217 | "homepage": "http://seld.be" 218 | } 219 | ], 220 | "description": "PCRE wrapping library that offers type-safe preg_* replacements.", 221 | "keywords": [ 222 | "PCRE", 223 | "preg", 224 | "regex", 225 | "regular expression" 226 | ], 227 | "support": { 228 | "issues": "https://github.com/composer/pcre/issues", 229 | "source": "https://github.com/composer/pcre/tree/3.1.0" 230 | }, 231 | "funding": [ 232 | { 233 | "url": "https://packagist.com", 234 | "type": "custom" 235 | }, 236 | { 237 | "url": "https://github.com/composer", 238 | "type": "github" 239 | }, 240 | { 241 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 242 | "type": "tidelift" 243 | } 244 | ], 245 | "time": "2022-11-17T09:50:14+00:00" 246 | }, 247 | { 248 | "name": "composer/semver", 249 | "version": "3.4.0", 250 | "source": { 251 | "type": "git", 252 | "url": "https://github.com/composer/semver.git", 253 | "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" 254 | }, 255 | "dist": { 256 | "type": "zip", 257 | "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", 258 | "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", 259 | "shasum": "" 260 | }, 261 | "require": { 262 | "php": "^5.3.2 || ^7.0 || ^8.0" 263 | }, 264 | "require-dev": { 265 | "phpstan/phpstan": "^1.4", 266 | "symfony/phpunit-bridge": "^4.2 || ^5" 267 | }, 268 | "type": "library", 269 | "extra": { 270 | "branch-alias": { 271 | "dev-main": "3.x-dev" 272 | } 273 | }, 274 | "autoload": { 275 | "psr-4": { 276 | "Composer\\Semver\\": "src" 277 | } 278 | }, 279 | "notification-url": "https://packagist.org/downloads/", 280 | "license": [ 281 | "MIT" 282 | ], 283 | "authors": [ 284 | { 285 | "name": "Nils Adermann", 286 | "email": "naderman@naderman.de", 287 | "homepage": "http://www.naderman.de" 288 | }, 289 | { 290 | "name": "Jordi Boggiano", 291 | "email": "j.boggiano@seld.be", 292 | "homepage": "http://seld.be" 293 | }, 294 | { 295 | "name": "Rob Bast", 296 | "email": "rob.bast@gmail.com", 297 | "homepage": "http://robbast.nl" 298 | } 299 | ], 300 | "description": "Semver library that offers utilities, version constraint parsing and validation.", 301 | "keywords": [ 302 | "semantic", 303 | "semver", 304 | "validation", 305 | "versioning" 306 | ], 307 | "support": { 308 | "irc": "ircs://irc.libera.chat:6697/composer", 309 | "issues": "https://github.com/composer/semver/issues", 310 | "source": "https://github.com/composer/semver/tree/3.4.0" 311 | }, 312 | "funding": [ 313 | { 314 | "url": "https://packagist.com", 315 | "type": "custom" 316 | }, 317 | { 318 | "url": "https://github.com/composer", 319 | "type": "github" 320 | }, 321 | { 322 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 323 | "type": "tidelift" 324 | } 325 | ], 326 | "time": "2023-08-31T09:50:34+00:00" 327 | }, 328 | { 329 | "name": "composer/xdebug-handler", 330 | "version": "3.0.3", 331 | "source": { 332 | "type": "git", 333 | "url": "https://github.com/composer/xdebug-handler.git", 334 | "reference": "ced299686f41dce890debac69273b47ffe98a40c" 335 | }, 336 | "dist": { 337 | "type": "zip", 338 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", 339 | "reference": "ced299686f41dce890debac69273b47ffe98a40c", 340 | "shasum": "" 341 | }, 342 | "require": { 343 | "composer/pcre": "^1 || ^2 || ^3", 344 | "php": "^7.2.5 || ^8.0", 345 | "psr/log": "^1 || ^2 || ^3" 346 | }, 347 | "require-dev": { 348 | "phpstan/phpstan": "^1.0", 349 | "phpstan/phpstan-strict-rules": "^1.1", 350 | "symfony/phpunit-bridge": "^6.0" 351 | }, 352 | "type": "library", 353 | "autoload": { 354 | "psr-4": { 355 | "Composer\\XdebugHandler\\": "src" 356 | } 357 | }, 358 | "notification-url": "https://packagist.org/downloads/", 359 | "license": [ 360 | "MIT" 361 | ], 362 | "authors": [ 363 | { 364 | "name": "John Stevenson", 365 | "email": "john-stevenson@blueyonder.co.uk" 366 | } 367 | ], 368 | "description": "Restarts a process without Xdebug.", 369 | "keywords": [ 370 | "Xdebug", 371 | "performance" 372 | ], 373 | "support": { 374 | "irc": "irc://irc.freenode.org/composer", 375 | "issues": "https://github.com/composer/xdebug-handler/issues", 376 | "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" 377 | }, 378 | "funding": [ 379 | { 380 | "url": "https://packagist.com", 381 | "type": "custom" 382 | }, 383 | { 384 | "url": "https://github.com/composer", 385 | "type": "github" 386 | }, 387 | { 388 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 389 | "type": "tidelift" 390 | } 391 | ], 392 | "time": "2022-02-25T21:32:43+00:00" 393 | }, 394 | { 395 | "name": "dnoegel/php-xdg-base-dir", 396 | "version": "v0.1.1", 397 | "source": { 398 | "type": "git", 399 | "url": "https://github.com/dnoegel/php-xdg-base-dir.git", 400 | "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" 401 | }, 402 | "dist": { 403 | "type": "zip", 404 | "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", 405 | "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", 406 | "shasum": "" 407 | }, 408 | "require": { 409 | "php": ">=5.3.2" 410 | }, 411 | "require-dev": { 412 | "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" 413 | }, 414 | "type": "library", 415 | "autoload": { 416 | "psr-4": { 417 | "XdgBaseDir\\": "src/" 418 | } 419 | }, 420 | "notification-url": "https://packagist.org/downloads/", 421 | "license": [ 422 | "MIT" 423 | ], 424 | "description": "implementation of xdg base directory specification for php", 425 | "support": { 426 | "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", 427 | "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" 428 | }, 429 | "time": "2019-12-04T15:06:13+00:00" 430 | }, 431 | { 432 | "name": "doctrine/deprecations", 433 | "version": "v1.1.1", 434 | "source": { 435 | "type": "git", 436 | "url": "https://github.com/doctrine/deprecations.git", 437 | "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" 438 | }, 439 | "dist": { 440 | "type": "zip", 441 | "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", 442 | "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", 443 | "shasum": "" 444 | }, 445 | "require": { 446 | "php": "^7.1 || ^8.0" 447 | }, 448 | "require-dev": { 449 | "doctrine/coding-standard": "^9", 450 | "phpstan/phpstan": "1.4.10 || 1.10.15", 451 | "phpstan/phpstan-phpunit": "^1.0", 452 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 453 | "psalm/plugin-phpunit": "0.18.4", 454 | "psr/log": "^1 || ^2 || ^3", 455 | "vimeo/psalm": "4.30.0 || 5.12.0" 456 | }, 457 | "suggest": { 458 | "psr/log": "Allows logging deprecations via PSR-3 logger implementation" 459 | }, 460 | "type": "library", 461 | "autoload": { 462 | "psr-4": { 463 | "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" 464 | } 465 | }, 466 | "notification-url": "https://packagist.org/downloads/", 467 | "license": [ 468 | "MIT" 469 | ], 470 | "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", 471 | "homepage": "https://www.doctrine-project.org/", 472 | "support": { 473 | "issues": "https://github.com/doctrine/deprecations/issues", 474 | "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" 475 | }, 476 | "time": "2023-06-03T09:27:29+00:00" 477 | }, 478 | { 479 | "name": "doctrine/instantiator", 480 | "version": "1.5.0", 481 | "source": { 482 | "type": "git", 483 | "url": "https://github.com/doctrine/instantiator.git", 484 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" 485 | }, 486 | "dist": { 487 | "type": "zip", 488 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", 489 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", 490 | "shasum": "" 491 | }, 492 | "require": { 493 | "php": "^7.1 || ^8.0" 494 | }, 495 | "require-dev": { 496 | "doctrine/coding-standard": "^9 || ^11", 497 | "ext-pdo": "*", 498 | "ext-phar": "*", 499 | "phpbench/phpbench": "^0.16 || ^1", 500 | "phpstan/phpstan": "^1.4", 501 | "phpstan/phpstan-phpunit": "^1", 502 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 503 | "vimeo/psalm": "^4.30 || ^5.4" 504 | }, 505 | "type": "library", 506 | "autoload": { 507 | "psr-4": { 508 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 509 | } 510 | }, 511 | "notification-url": "https://packagist.org/downloads/", 512 | "license": [ 513 | "MIT" 514 | ], 515 | "authors": [ 516 | { 517 | "name": "Marco Pivetta", 518 | "email": "ocramius@gmail.com", 519 | "homepage": "https://ocramius.github.io/" 520 | } 521 | ], 522 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 523 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 524 | "keywords": [ 525 | "constructor", 526 | "instantiate" 527 | ], 528 | "support": { 529 | "issues": "https://github.com/doctrine/instantiator/issues", 530 | "source": "https://github.com/doctrine/instantiator/tree/1.5.0" 531 | }, 532 | "funding": [ 533 | { 534 | "url": "https://www.doctrine-project.org/sponsorship.html", 535 | "type": "custom" 536 | }, 537 | { 538 | "url": "https://www.patreon.com/phpdoctrine", 539 | "type": "patreon" 540 | }, 541 | { 542 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 543 | "type": "tidelift" 544 | } 545 | ], 546 | "time": "2022-12-30T00:15:36+00:00" 547 | }, 548 | { 549 | "name": "felixfbecker/advanced-json-rpc", 550 | "version": "v3.2.1", 551 | "source": { 552 | "type": "git", 553 | "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", 554 | "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" 555 | }, 556 | "dist": { 557 | "type": "zip", 558 | "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", 559 | "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", 560 | "shasum": "" 561 | }, 562 | "require": { 563 | "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", 564 | "php": "^7.1 || ^8.0", 565 | "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" 566 | }, 567 | "require-dev": { 568 | "phpunit/phpunit": "^7.0 || ^8.0" 569 | }, 570 | "type": "library", 571 | "autoload": { 572 | "psr-4": { 573 | "AdvancedJsonRpc\\": "lib/" 574 | } 575 | }, 576 | "notification-url": "https://packagist.org/downloads/", 577 | "license": [ 578 | "ISC" 579 | ], 580 | "authors": [ 581 | { 582 | "name": "Felix Becker", 583 | "email": "felix.b@outlook.com" 584 | } 585 | ], 586 | "description": "A more advanced JSONRPC implementation", 587 | "support": { 588 | "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", 589 | "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" 590 | }, 591 | "time": "2021-06-11T22:34:44+00:00" 592 | }, 593 | { 594 | "name": "felixfbecker/language-server-protocol", 595 | "version": "v1.5.2", 596 | "source": { 597 | "type": "git", 598 | "url": "https://github.com/felixfbecker/php-language-server-protocol.git", 599 | "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" 600 | }, 601 | "dist": { 602 | "type": "zip", 603 | "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", 604 | "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", 605 | "shasum": "" 606 | }, 607 | "require": { 608 | "php": ">=7.1" 609 | }, 610 | "require-dev": { 611 | "phpstan/phpstan": "*", 612 | "squizlabs/php_codesniffer": "^3.1", 613 | "vimeo/psalm": "^4.0" 614 | }, 615 | "type": "library", 616 | "extra": { 617 | "branch-alias": { 618 | "dev-master": "1.x-dev" 619 | } 620 | }, 621 | "autoload": { 622 | "psr-4": { 623 | "LanguageServerProtocol\\": "src/" 624 | } 625 | }, 626 | "notification-url": "https://packagist.org/downloads/", 627 | "license": [ 628 | "ISC" 629 | ], 630 | "authors": [ 631 | { 632 | "name": "Felix Becker", 633 | "email": "felix.b@outlook.com" 634 | } 635 | ], 636 | "description": "PHP classes for the Language Server Protocol", 637 | "keywords": [ 638 | "language", 639 | "microsoft", 640 | "php", 641 | "server" 642 | ], 643 | "support": { 644 | "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", 645 | "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" 646 | }, 647 | "time": "2022-03-02T22:36:06+00:00" 648 | }, 649 | { 650 | "name": "fidry/cpu-core-counter", 651 | "version": "0.5.1", 652 | "source": { 653 | "type": "git", 654 | "url": "https://github.com/theofidry/cpu-core-counter.git", 655 | "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623" 656 | }, 657 | "dist": { 658 | "type": "zip", 659 | "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623", 660 | "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623", 661 | "shasum": "" 662 | }, 663 | "require": { 664 | "php": "^7.2 || ^8.0" 665 | }, 666 | "require-dev": { 667 | "fidry/makefile": "^0.2.0", 668 | "phpstan/extension-installer": "^1.2.0", 669 | "phpstan/phpstan": "^1.9.2", 670 | "phpstan/phpstan-deprecation-rules": "^1.0.0", 671 | "phpstan/phpstan-phpunit": "^1.2.2", 672 | "phpstan/phpstan-strict-rules": "^1.4.4", 673 | "phpunit/phpunit": "^9.5.26 || ^8.5.31", 674 | "theofidry/php-cs-fixer-config": "^1.0", 675 | "webmozarts/strict-phpunit": "^7.5" 676 | }, 677 | "type": "library", 678 | "autoload": { 679 | "psr-4": { 680 | "Fidry\\CpuCoreCounter\\": "src/" 681 | } 682 | }, 683 | "notification-url": "https://packagist.org/downloads/", 684 | "license": [ 685 | "MIT" 686 | ], 687 | "authors": [ 688 | { 689 | "name": "Théo FIDRY", 690 | "email": "theo.fidry@gmail.com" 691 | } 692 | ], 693 | "description": "Tiny utility to get the number of CPU cores.", 694 | "keywords": [ 695 | "CPU", 696 | "core" 697 | ], 698 | "support": { 699 | "issues": "https://github.com/theofidry/cpu-core-counter/issues", 700 | "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1" 701 | }, 702 | "funding": [ 703 | { 704 | "url": "https://github.com/theofidry", 705 | "type": "github" 706 | } 707 | ], 708 | "time": "2022-12-24T12:35:10+00:00" 709 | }, 710 | { 711 | "name": "myclabs/deep-copy", 712 | "version": "1.11.1", 713 | "source": { 714 | "type": "git", 715 | "url": "https://github.com/myclabs/DeepCopy.git", 716 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" 717 | }, 718 | "dist": { 719 | "type": "zip", 720 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 721 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 722 | "shasum": "" 723 | }, 724 | "require": { 725 | "php": "^7.1 || ^8.0" 726 | }, 727 | "conflict": { 728 | "doctrine/collections": "<1.6.8", 729 | "doctrine/common": "<2.13.3 || >=3,<3.2.2" 730 | }, 731 | "require-dev": { 732 | "doctrine/collections": "^1.6.8", 733 | "doctrine/common": "^2.13.3 || ^3.2.2", 734 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 735 | }, 736 | "type": "library", 737 | "autoload": { 738 | "files": [ 739 | "src/DeepCopy/deep_copy.php" 740 | ], 741 | "psr-4": { 742 | "DeepCopy\\": "src/DeepCopy/" 743 | } 744 | }, 745 | "notification-url": "https://packagist.org/downloads/", 746 | "license": [ 747 | "MIT" 748 | ], 749 | "description": "Create deep copies (clones) of your objects", 750 | "keywords": [ 751 | "clone", 752 | "copy", 753 | "duplicate", 754 | "object", 755 | "object graph" 756 | ], 757 | "support": { 758 | "issues": "https://github.com/myclabs/DeepCopy/issues", 759 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" 760 | }, 761 | "funding": [ 762 | { 763 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 764 | "type": "tidelift" 765 | } 766 | ], 767 | "time": "2023-03-08T13:26:56+00:00" 768 | }, 769 | { 770 | "name": "netresearch/jsonmapper", 771 | "version": "v4.2.0", 772 | "source": { 773 | "type": "git", 774 | "url": "https://github.com/cweiske/jsonmapper.git", 775 | "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" 776 | }, 777 | "dist": { 778 | "type": "zip", 779 | "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", 780 | "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", 781 | "shasum": "" 782 | }, 783 | "require": { 784 | "ext-json": "*", 785 | "ext-pcre": "*", 786 | "ext-reflection": "*", 787 | "ext-spl": "*", 788 | "php": ">=7.1" 789 | }, 790 | "require-dev": { 791 | "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", 792 | "squizlabs/php_codesniffer": "~3.5" 793 | }, 794 | "type": "library", 795 | "autoload": { 796 | "psr-0": { 797 | "JsonMapper": "src/" 798 | } 799 | }, 800 | "notification-url": "https://packagist.org/downloads/", 801 | "license": [ 802 | "OSL-3.0" 803 | ], 804 | "authors": [ 805 | { 806 | "name": "Christian Weiske", 807 | "email": "cweiske@cweiske.de", 808 | "homepage": "http://github.com/cweiske/jsonmapper/", 809 | "role": "Developer" 810 | } 811 | ], 812 | "description": "Map nested JSON structures onto PHP classes", 813 | "support": { 814 | "email": "cweiske@cweiske.de", 815 | "issues": "https://github.com/cweiske/jsonmapper/issues", 816 | "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" 817 | }, 818 | "time": "2023-04-09T17:37:40+00:00" 819 | }, 820 | { 821 | "name": "nikic/php-parser", 822 | "version": "v4.17.1", 823 | "source": { 824 | "type": "git", 825 | "url": "https://github.com/nikic/PHP-Parser.git", 826 | "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" 827 | }, 828 | "dist": { 829 | "type": "zip", 830 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", 831 | "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", 832 | "shasum": "" 833 | }, 834 | "require": { 835 | "ext-tokenizer": "*", 836 | "php": ">=7.0" 837 | }, 838 | "require-dev": { 839 | "ircmaxell/php-yacc": "^0.0.7", 840 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" 841 | }, 842 | "bin": [ 843 | "bin/php-parse" 844 | ], 845 | "type": "library", 846 | "extra": { 847 | "branch-alias": { 848 | "dev-master": "4.9-dev" 849 | } 850 | }, 851 | "autoload": { 852 | "psr-4": { 853 | "PhpParser\\": "lib/PhpParser" 854 | } 855 | }, 856 | "notification-url": "https://packagist.org/downloads/", 857 | "license": [ 858 | "BSD-3-Clause" 859 | ], 860 | "authors": [ 861 | { 862 | "name": "Nikita Popov" 863 | } 864 | ], 865 | "description": "A PHP parser written in PHP", 866 | "keywords": [ 867 | "parser", 868 | "php" 869 | ], 870 | "support": { 871 | "issues": "https://github.com/nikic/PHP-Parser/issues", 872 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" 873 | }, 874 | "time": "2023-08-13T19:53:39+00:00" 875 | }, 876 | { 877 | "name": "phar-io/manifest", 878 | "version": "2.0.3", 879 | "source": { 880 | "type": "git", 881 | "url": "https://github.com/phar-io/manifest.git", 882 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53" 883 | }, 884 | "dist": { 885 | "type": "zip", 886 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", 887 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53", 888 | "shasum": "" 889 | }, 890 | "require": { 891 | "ext-dom": "*", 892 | "ext-phar": "*", 893 | "ext-xmlwriter": "*", 894 | "phar-io/version": "^3.0.1", 895 | "php": "^7.2 || ^8.0" 896 | }, 897 | "type": "library", 898 | "extra": { 899 | "branch-alias": { 900 | "dev-master": "2.0.x-dev" 901 | } 902 | }, 903 | "autoload": { 904 | "classmap": [ 905 | "src/" 906 | ] 907 | }, 908 | "notification-url": "https://packagist.org/downloads/", 909 | "license": [ 910 | "BSD-3-Clause" 911 | ], 912 | "authors": [ 913 | { 914 | "name": "Arne Blankerts", 915 | "email": "arne@blankerts.de", 916 | "role": "Developer" 917 | }, 918 | { 919 | "name": "Sebastian Heuer", 920 | "email": "sebastian@phpeople.de", 921 | "role": "Developer" 922 | }, 923 | { 924 | "name": "Sebastian Bergmann", 925 | "email": "sebastian@phpunit.de", 926 | "role": "Developer" 927 | } 928 | ], 929 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 930 | "support": { 931 | "issues": "https://github.com/phar-io/manifest/issues", 932 | "source": "https://github.com/phar-io/manifest/tree/2.0.3" 933 | }, 934 | "time": "2021-07-20T11:28:43+00:00" 935 | }, 936 | { 937 | "name": "phar-io/version", 938 | "version": "3.2.1", 939 | "source": { 940 | "type": "git", 941 | "url": "https://github.com/phar-io/version.git", 942 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 943 | }, 944 | "dist": { 945 | "type": "zip", 946 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 947 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 948 | "shasum": "" 949 | }, 950 | "require": { 951 | "php": "^7.2 || ^8.0" 952 | }, 953 | "type": "library", 954 | "autoload": { 955 | "classmap": [ 956 | "src/" 957 | ] 958 | }, 959 | "notification-url": "https://packagist.org/downloads/", 960 | "license": [ 961 | "BSD-3-Clause" 962 | ], 963 | "authors": [ 964 | { 965 | "name": "Arne Blankerts", 966 | "email": "arne@blankerts.de", 967 | "role": "Developer" 968 | }, 969 | { 970 | "name": "Sebastian Heuer", 971 | "email": "sebastian@phpeople.de", 972 | "role": "Developer" 973 | }, 974 | { 975 | "name": "Sebastian Bergmann", 976 | "email": "sebastian@phpunit.de", 977 | "role": "Developer" 978 | } 979 | ], 980 | "description": "Library for handling version information and constraints", 981 | "support": { 982 | "issues": "https://github.com/phar-io/version/issues", 983 | "source": "https://github.com/phar-io/version/tree/3.2.1" 984 | }, 985 | "time": "2022-02-21T01:04:05+00:00" 986 | }, 987 | { 988 | "name": "php-mock/php-mock", 989 | "version": "2.4.1", 990 | "source": { 991 | "type": "git", 992 | "url": "https://github.com/php-mock/php-mock.git", 993 | "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d" 994 | }, 995 | "dist": { 996 | "type": "zip", 997 | "url": "https://api.github.com/repos/php-mock/php-mock/zipball/6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", 998 | "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", 999 | "shasum": "" 1000 | }, 1001 | "require": { 1002 | "php": "^5.6 || ^7.0 || ^8.0", 1003 | "phpunit/php-text-template": "^1 || ^2 || ^3" 1004 | }, 1005 | "replace": { 1006 | "malkusch/php-mock": "*" 1007 | }, 1008 | "require-dev": { 1009 | "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0", 1010 | "squizlabs/php_codesniffer": "^3.5" 1011 | }, 1012 | "suggest": { 1013 | "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." 1014 | }, 1015 | "type": "library", 1016 | "autoload": { 1017 | "files": [ 1018 | "autoload.php" 1019 | ], 1020 | "psr-4": { 1021 | "phpmock\\": [ 1022 | "classes/", 1023 | "tests/" 1024 | ] 1025 | } 1026 | }, 1027 | "notification-url": "https://packagist.org/downloads/", 1028 | "license": [ 1029 | "WTFPL" 1030 | ], 1031 | "authors": [ 1032 | { 1033 | "name": "Markus Malkusch", 1034 | "email": "markus@malkusch.de", 1035 | "homepage": "http://markus.malkusch.de", 1036 | "role": "Developer" 1037 | } 1038 | ], 1039 | "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", 1040 | "homepage": "https://github.com/php-mock/php-mock", 1041 | "keywords": [ 1042 | "BDD", 1043 | "TDD", 1044 | "function", 1045 | "mock", 1046 | "stub", 1047 | "test", 1048 | "test double", 1049 | "testing" 1050 | ], 1051 | "support": { 1052 | "issues": "https://github.com/php-mock/php-mock/issues", 1053 | "source": "https://github.com/php-mock/php-mock/tree/2.4.1" 1054 | }, 1055 | "funding": [ 1056 | { 1057 | "url": "https://github.com/michalbundyra", 1058 | "type": "github" 1059 | } 1060 | ], 1061 | "time": "2023-06-12T20:48:52+00:00" 1062 | }, 1063 | { 1064 | "name": "php-mock/php-mock-integration", 1065 | "version": "2.2.1", 1066 | "source": { 1067 | "type": "git", 1068 | "url": "https://github.com/php-mock/php-mock-integration.git", 1069 | "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5" 1070 | }, 1071 | "dist": { 1072 | "type": "zip", 1073 | "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/04f4a8d5442ca457b102b5204673f77323e3edb5", 1074 | "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5", 1075 | "shasum": "" 1076 | }, 1077 | "require": { 1078 | "php": ">=5.6", 1079 | "php-mock/php-mock": "^2.4", 1080 | "phpunit/php-text-template": "^1 || ^2 || ^3" 1081 | }, 1082 | "require-dev": { 1083 | "phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9 || ^10" 1084 | }, 1085 | "type": "library", 1086 | "autoload": { 1087 | "psr-4": { 1088 | "phpmock\\integration\\": "classes/" 1089 | } 1090 | }, 1091 | "notification-url": "https://packagist.org/downloads/", 1092 | "license": [ 1093 | "WTFPL" 1094 | ], 1095 | "authors": [ 1096 | { 1097 | "name": "Markus Malkusch", 1098 | "email": "markus@malkusch.de", 1099 | "homepage": "http://markus.malkusch.de", 1100 | "role": "Developer" 1101 | } 1102 | ], 1103 | "description": "Integration package for PHP-Mock", 1104 | "homepage": "https://github.com/php-mock/php-mock-integration", 1105 | "keywords": [ 1106 | "BDD", 1107 | "TDD", 1108 | "function", 1109 | "mock", 1110 | "stub", 1111 | "test", 1112 | "test double" 1113 | ], 1114 | "support": { 1115 | "issues": "https://github.com/php-mock/php-mock-integration/issues", 1116 | "source": "https://github.com/php-mock/php-mock-integration/tree/2.2.1" 1117 | }, 1118 | "funding": [ 1119 | { 1120 | "url": "https://github.com/michalbundyra", 1121 | "type": "github" 1122 | } 1123 | ], 1124 | "time": "2023-02-13T09:51:29+00:00" 1125 | }, 1126 | { 1127 | "name": "php-mock/php-mock-phpunit", 1128 | "version": "2.7.2", 1129 | "source": { 1130 | "type": "git", 1131 | "url": "https://github.com/php-mock/php-mock-phpunit.git", 1132 | "reference": "33a99c190d078e77864b8d74cdc91cc4e5342598" 1133 | }, 1134 | "dist": { 1135 | "type": "zip", 1136 | "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/33a99c190d078e77864b8d74cdc91cc4e5342598", 1137 | "reference": "33a99c190d078e77864b8d74cdc91cc4e5342598", 1138 | "shasum": "" 1139 | }, 1140 | "require": { 1141 | "php": ">=7", 1142 | "php-mock/php-mock-integration": "^2.2.1", 1143 | "phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10.0.17" 1144 | }, 1145 | "require-dev": { 1146 | "mockery/mockery": "^1.3.6" 1147 | }, 1148 | "type": "library", 1149 | "autoload": { 1150 | "files": [ 1151 | "autoload.php" 1152 | ], 1153 | "psr-4": { 1154 | "phpmock\\phpunit\\": "classes/" 1155 | } 1156 | }, 1157 | "notification-url": "https://packagist.org/downloads/", 1158 | "license": [ 1159 | "WTFPL" 1160 | ], 1161 | "authors": [ 1162 | { 1163 | "name": "Markus Malkusch", 1164 | "email": "markus@malkusch.de", 1165 | "homepage": "http://markus.malkusch.de", 1166 | "role": "Developer" 1167 | } 1168 | ], 1169 | "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.", 1170 | "homepage": "https://github.com/php-mock/php-mock-phpunit", 1171 | "keywords": [ 1172 | "BDD", 1173 | "TDD", 1174 | "function", 1175 | "mock", 1176 | "phpunit", 1177 | "stub", 1178 | "test", 1179 | "test double", 1180 | "testing" 1181 | ], 1182 | "support": { 1183 | "issues": "https://github.com/php-mock/php-mock-phpunit/issues", 1184 | "source": "https://github.com/php-mock/php-mock-phpunit/tree/2.7.2" 1185 | }, 1186 | "funding": [ 1187 | { 1188 | "url": "https://github.com/michalbundyra", 1189 | "type": "github" 1190 | } 1191 | ], 1192 | "time": "2023-06-13T07:46:04+00:00" 1193 | }, 1194 | { 1195 | "name": "phpdocumentor/reflection-common", 1196 | "version": "2.2.0", 1197 | "source": { 1198 | "type": "git", 1199 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 1200 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" 1201 | }, 1202 | "dist": { 1203 | "type": "zip", 1204 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", 1205 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", 1206 | "shasum": "" 1207 | }, 1208 | "require": { 1209 | "php": "^7.2 || ^8.0" 1210 | }, 1211 | "type": "library", 1212 | "extra": { 1213 | "branch-alias": { 1214 | "dev-2.x": "2.x-dev" 1215 | } 1216 | }, 1217 | "autoload": { 1218 | "psr-4": { 1219 | "phpDocumentor\\Reflection\\": "src/" 1220 | } 1221 | }, 1222 | "notification-url": "https://packagist.org/downloads/", 1223 | "license": [ 1224 | "MIT" 1225 | ], 1226 | "authors": [ 1227 | { 1228 | "name": "Jaap van Otterdijk", 1229 | "email": "opensource@ijaap.nl" 1230 | } 1231 | ], 1232 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 1233 | "homepage": "http://www.phpdoc.org", 1234 | "keywords": [ 1235 | "FQSEN", 1236 | "phpDocumentor", 1237 | "phpdoc", 1238 | "reflection", 1239 | "static analysis" 1240 | ], 1241 | "support": { 1242 | "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", 1243 | "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" 1244 | }, 1245 | "time": "2020-06-27T09:03:43+00:00" 1246 | }, 1247 | { 1248 | "name": "phpdocumentor/reflection-docblock", 1249 | "version": "5.3.0", 1250 | "source": { 1251 | "type": "git", 1252 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 1253 | "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" 1254 | }, 1255 | "dist": { 1256 | "type": "zip", 1257 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", 1258 | "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", 1259 | "shasum": "" 1260 | }, 1261 | "require": { 1262 | "ext-filter": "*", 1263 | "php": "^7.2 || ^8.0", 1264 | "phpdocumentor/reflection-common": "^2.2", 1265 | "phpdocumentor/type-resolver": "^1.3", 1266 | "webmozart/assert": "^1.9.1" 1267 | }, 1268 | "require-dev": { 1269 | "mockery/mockery": "~1.3.2", 1270 | "psalm/phar": "^4.8" 1271 | }, 1272 | "type": "library", 1273 | "extra": { 1274 | "branch-alias": { 1275 | "dev-master": "5.x-dev" 1276 | } 1277 | }, 1278 | "autoload": { 1279 | "psr-4": { 1280 | "phpDocumentor\\Reflection\\": "src" 1281 | } 1282 | }, 1283 | "notification-url": "https://packagist.org/downloads/", 1284 | "license": [ 1285 | "MIT" 1286 | ], 1287 | "authors": [ 1288 | { 1289 | "name": "Mike van Riel", 1290 | "email": "me@mikevanriel.com" 1291 | }, 1292 | { 1293 | "name": "Jaap van Otterdijk", 1294 | "email": "account@ijaap.nl" 1295 | } 1296 | ], 1297 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 1298 | "support": { 1299 | "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", 1300 | "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" 1301 | }, 1302 | "time": "2021-10-19T17:43:47+00:00" 1303 | }, 1304 | { 1305 | "name": "phpdocumentor/type-resolver", 1306 | "version": "1.7.3", 1307 | "source": { 1308 | "type": "git", 1309 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 1310 | "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419" 1311 | }, 1312 | "dist": { 1313 | "type": "zip", 1314 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", 1315 | "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", 1316 | "shasum": "" 1317 | }, 1318 | "require": { 1319 | "doctrine/deprecations": "^1.0", 1320 | "php": "^7.4 || ^8.0", 1321 | "phpdocumentor/reflection-common": "^2.0", 1322 | "phpstan/phpdoc-parser": "^1.13" 1323 | }, 1324 | "require-dev": { 1325 | "ext-tokenizer": "*", 1326 | "phpbench/phpbench": "^1.2", 1327 | "phpstan/extension-installer": "^1.1", 1328 | "phpstan/phpstan": "^1.8", 1329 | "phpstan/phpstan-phpunit": "^1.1", 1330 | "phpunit/phpunit": "^9.5", 1331 | "rector/rector": "^0.13.9", 1332 | "vimeo/psalm": "^4.25" 1333 | }, 1334 | "type": "library", 1335 | "extra": { 1336 | "branch-alias": { 1337 | "dev-1.x": "1.x-dev" 1338 | } 1339 | }, 1340 | "autoload": { 1341 | "psr-4": { 1342 | "phpDocumentor\\Reflection\\": "src" 1343 | } 1344 | }, 1345 | "notification-url": "https://packagist.org/downloads/", 1346 | "license": [ 1347 | "MIT" 1348 | ], 1349 | "authors": [ 1350 | { 1351 | "name": "Mike van Riel", 1352 | "email": "me@mikevanriel.com" 1353 | } 1354 | ], 1355 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", 1356 | "support": { 1357 | "issues": "https://github.com/phpDocumentor/TypeResolver/issues", 1358 | "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3" 1359 | }, 1360 | "time": "2023-08-12T11:01:26+00:00" 1361 | }, 1362 | { 1363 | "name": "phpstan/phpdoc-parser", 1364 | "version": "1.24.0", 1365 | "source": { 1366 | "type": "git", 1367 | "url": "https://github.com/phpstan/phpdoc-parser.git", 1368 | "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" 1369 | }, 1370 | "dist": { 1371 | "type": "zip", 1372 | "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", 1373 | "reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", 1374 | "shasum": "" 1375 | }, 1376 | "require": { 1377 | "php": "^7.2 || ^8.0" 1378 | }, 1379 | "require-dev": { 1380 | "doctrine/annotations": "^2.0", 1381 | "nikic/php-parser": "^4.15", 1382 | "php-parallel-lint/php-parallel-lint": "^1.2", 1383 | "phpstan/extension-installer": "^1.0", 1384 | "phpstan/phpstan": "^1.5", 1385 | "phpstan/phpstan-phpunit": "^1.1", 1386 | "phpstan/phpstan-strict-rules": "^1.0", 1387 | "phpunit/phpunit": "^9.5", 1388 | "symfony/process": "^5.2" 1389 | }, 1390 | "type": "library", 1391 | "autoload": { 1392 | "psr-4": { 1393 | "PHPStan\\PhpDocParser\\": [ 1394 | "src/" 1395 | ] 1396 | } 1397 | }, 1398 | "notification-url": "https://packagist.org/downloads/", 1399 | "license": [ 1400 | "MIT" 1401 | ], 1402 | "description": "PHPDoc parser with support for nullable, intersection and generic types", 1403 | "support": { 1404 | "issues": "https://github.com/phpstan/phpdoc-parser/issues", 1405 | "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0" 1406 | }, 1407 | "time": "2023-09-07T20:46:32+00:00" 1408 | }, 1409 | { 1410 | "name": "phpunit/php-code-coverage", 1411 | "version": "9.2.27", 1412 | "source": { 1413 | "type": "git", 1414 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 1415 | "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" 1416 | }, 1417 | "dist": { 1418 | "type": "zip", 1419 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", 1420 | "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", 1421 | "shasum": "" 1422 | }, 1423 | "require": { 1424 | "ext-dom": "*", 1425 | "ext-libxml": "*", 1426 | "ext-xmlwriter": "*", 1427 | "nikic/php-parser": "^4.15", 1428 | "php": ">=7.3", 1429 | "phpunit/php-file-iterator": "^3.0.3", 1430 | "phpunit/php-text-template": "^2.0.2", 1431 | "sebastian/code-unit-reverse-lookup": "^2.0.2", 1432 | "sebastian/complexity": "^2.0", 1433 | "sebastian/environment": "^5.1.2", 1434 | "sebastian/lines-of-code": "^1.0.3", 1435 | "sebastian/version": "^3.0.1", 1436 | "theseer/tokenizer": "^1.2.0" 1437 | }, 1438 | "require-dev": { 1439 | "phpunit/phpunit": "^9.3" 1440 | }, 1441 | "suggest": { 1442 | "ext-pcov": "PHP extension that provides line coverage", 1443 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 1444 | }, 1445 | "type": "library", 1446 | "extra": { 1447 | "branch-alias": { 1448 | "dev-master": "9.2-dev" 1449 | } 1450 | }, 1451 | "autoload": { 1452 | "classmap": [ 1453 | "src/" 1454 | ] 1455 | }, 1456 | "notification-url": "https://packagist.org/downloads/", 1457 | "license": [ 1458 | "BSD-3-Clause" 1459 | ], 1460 | "authors": [ 1461 | { 1462 | "name": "Sebastian Bergmann", 1463 | "email": "sebastian@phpunit.de", 1464 | "role": "lead" 1465 | } 1466 | ], 1467 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 1468 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 1469 | "keywords": [ 1470 | "coverage", 1471 | "testing", 1472 | "xunit" 1473 | ], 1474 | "support": { 1475 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 1476 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 1477 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" 1478 | }, 1479 | "funding": [ 1480 | { 1481 | "url": "https://github.com/sebastianbergmann", 1482 | "type": "github" 1483 | } 1484 | ], 1485 | "time": "2023-07-26T13:44:30+00:00" 1486 | }, 1487 | { 1488 | "name": "phpunit/php-file-iterator", 1489 | "version": "3.0.6", 1490 | "source": { 1491 | "type": "git", 1492 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 1493 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 1494 | }, 1495 | "dist": { 1496 | "type": "zip", 1497 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 1498 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 1499 | "shasum": "" 1500 | }, 1501 | "require": { 1502 | "php": ">=7.3" 1503 | }, 1504 | "require-dev": { 1505 | "phpunit/phpunit": "^9.3" 1506 | }, 1507 | "type": "library", 1508 | "extra": { 1509 | "branch-alias": { 1510 | "dev-master": "3.0-dev" 1511 | } 1512 | }, 1513 | "autoload": { 1514 | "classmap": [ 1515 | "src/" 1516 | ] 1517 | }, 1518 | "notification-url": "https://packagist.org/downloads/", 1519 | "license": [ 1520 | "BSD-3-Clause" 1521 | ], 1522 | "authors": [ 1523 | { 1524 | "name": "Sebastian Bergmann", 1525 | "email": "sebastian@phpunit.de", 1526 | "role": "lead" 1527 | } 1528 | ], 1529 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 1530 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 1531 | "keywords": [ 1532 | "filesystem", 1533 | "iterator" 1534 | ], 1535 | "support": { 1536 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 1537 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 1538 | }, 1539 | "funding": [ 1540 | { 1541 | "url": "https://github.com/sebastianbergmann", 1542 | "type": "github" 1543 | } 1544 | ], 1545 | "time": "2021-12-02T12:48:52+00:00" 1546 | }, 1547 | { 1548 | "name": "phpunit/php-invoker", 1549 | "version": "3.1.1", 1550 | "source": { 1551 | "type": "git", 1552 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 1553 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 1554 | }, 1555 | "dist": { 1556 | "type": "zip", 1557 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 1558 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 1559 | "shasum": "" 1560 | }, 1561 | "require": { 1562 | "php": ">=7.3" 1563 | }, 1564 | "require-dev": { 1565 | "ext-pcntl": "*", 1566 | "phpunit/phpunit": "^9.3" 1567 | }, 1568 | "suggest": { 1569 | "ext-pcntl": "*" 1570 | }, 1571 | "type": "library", 1572 | "extra": { 1573 | "branch-alias": { 1574 | "dev-master": "3.1-dev" 1575 | } 1576 | }, 1577 | "autoload": { 1578 | "classmap": [ 1579 | "src/" 1580 | ] 1581 | }, 1582 | "notification-url": "https://packagist.org/downloads/", 1583 | "license": [ 1584 | "BSD-3-Clause" 1585 | ], 1586 | "authors": [ 1587 | { 1588 | "name": "Sebastian Bergmann", 1589 | "email": "sebastian@phpunit.de", 1590 | "role": "lead" 1591 | } 1592 | ], 1593 | "description": "Invoke callables with a timeout", 1594 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 1595 | "keywords": [ 1596 | "process" 1597 | ], 1598 | "support": { 1599 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 1600 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 1601 | }, 1602 | "funding": [ 1603 | { 1604 | "url": "https://github.com/sebastianbergmann", 1605 | "type": "github" 1606 | } 1607 | ], 1608 | "time": "2020-09-28T05:58:55+00:00" 1609 | }, 1610 | { 1611 | "name": "phpunit/php-text-template", 1612 | "version": "2.0.4", 1613 | "source": { 1614 | "type": "git", 1615 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 1616 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 1617 | }, 1618 | "dist": { 1619 | "type": "zip", 1620 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 1621 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 1622 | "shasum": "" 1623 | }, 1624 | "require": { 1625 | "php": ">=7.3" 1626 | }, 1627 | "require-dev": { 1628 | "phpunit/phpunit": "^9.3" 1629 | }, 1630 | "type": "library", 1631 | "extra": { 1632 | "branch-alias": { 1633 | "dev-master": "2.0-dev" 1634 | } 1635 | }, 1636 | "autoload": { 1637 | "classmap": [ 1638 | "src/" 1639 | ] 1640 | }, 1641 | "notification-url": "https://packagist.org/downloads/", 1642 | "license": [ 1643 | "BSD-3-Clause" 1644 | ], 1645 | "authors": [ 1646 | { 1647 | "name": "Sebastian Bergmann", 1648 | "email": "sebastian@phpunit.de", 1649 | "role": "lead" 1650 | } 1651 | ], 1652 | "description": "Simple template engine.", 1653 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 1654 | "keywords": [ 1655 | "template" 1656 | ], 1657 | "support": { 1658 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 1659 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 1660 | }, 1661 | "funding": [ 1662 | { 1663 | "url": "https://github.com/sebastianbergmann", 1664 | "type": "github" 1665 | } 1666 | ], 1667 | "time": "2020-10-26T05:33:50+00:00" 1668 | }, 1669 | { 1670 | "name": "phpunit/php-timer", 1671 | "version": "5.0.3", 1672 | "source": { 1673 | "type": "git", 1674 | "url": "https://github.com/sebastianbergmann/php-timer.git", 1675 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 1676 | }, 1677 | "dist": { 1678 | "type": "zip", 1679 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 1680 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 1681 | "shasum": "" 1682 | }, 1683 | "require": { 1684 | "php": ">=7.3" 1685 | }, 1686 | "require-dev": { 1687 | "phpunit/phpunit": "^9.3" 1688 | }, 1689 | "type": "library", 1690 | "extra": { 1691 | "branch-alias": { 1692 | "dev-master": "5.0-dev" 1693 | } 1694 | }, 1695 | "autoload": { 1696 | "classmap": [ 1697 | "src/" 1698 | ] 1699 | }, 1700 | "notification-url": "https://packagist.org/downloads/", 1701 | "license": [ 1702 | "BSD-3-Clause" 1703 | ], 1704 | "authors": [ 1705 | { 1706 | "name": "Sebastian Bergmann", 1707 | "email": "sebastian@phpunit.de", 1708 | "role": "lead" 1709 | } 1710 | ], 1711 | "description": "Utility class for timing", 1712 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1713 | "keywords": [ 1714 | "timer" 1715 | ], 1716 | "support": { 1717 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 1718 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 1719 | }, 1720 | "funding": [ 1721 | { 1722 | "url": "https://github.com/sebastianbergmann", 1723 | "type": "github" 1724 | } 1725 | ], 1726 | "time": "2020-10-26T13:16:10+00:00" 1727 | }, 1728 | { 1729 | "name": "phpunit/phpunit", 1730 | "version": "9.6.11", 1731 | "source": { 1732 | "type": "git", 1733 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1734 | "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" 1735 | }, 1736 | "dist": { 1737 | "type": "zip", 1738 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", 1739 | "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", 1740 | "shasum": "" 1741 | }, 1742 | "require": { 1743 | "doctrine/instantiator": "^1.3.1 || ^2", 1744 | "ext-dom": "*", 1745 | "ext-json": "*", 1746 | "ext-libxml": "*", 1747 | "ext-mbstring": "*", 1748 | "ext-xml": "*", 1749 | "ext-xmlwriter": "*", 1750 | "myclabs/deep-copy": "^1.10.1", 1751 | "phar-io/manifest": "^2.0.3", 1752 | "phar-io/version": "^3.0.2", 1753 | "php": ">=7.3", 1754 | "phpunit/php-code-coverage": "^9.2.13", 1755 | "phpunit/php-file-iterator": "^3.0.5", 1756 | "phpunit/php-invoker": "^3.1.1", 1757 | "phpunit/php-text-template": "^2.0.3", 1758 | "phpunit/php-timer": "^5.0.2", 1759 | "sebastian/cli-parser": "^1.0.1", 1760 | "sebastian/code-unit": "^1.0.6", 1761 | "sebastian/comparator": "^4.0.8", 1762 | "sebastian/diff": "^4.0.3", 1763 | "sebastian/environment": "^5.1.3", 1764 | "sebastian/exporter": "^4.0.5", 1765 | "sebastian/global-state": "^5.0.1", 1766 | "sebastian/object-enumerator": "^4.0.3", 1767 | "sebastian/resource-operations": "^3.0.3", 1768 | "sebastian/type": "^3.2", 1769 | "sebastian/version": "^3.0.2" 1770 | }, 1771 | "suggest": { 1772 | "ext-soap": "To be able to generate mocks based on WSDL files", 1773 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 1774 | }, 1775 | "bin": [ 1776 | "phpunit" 1777 | ], 1778 | "type": "library", 1779 | "extra": { 1780 | "branch-alias": { 1781 | "dev-master": "9.6-dev" 1782 | } 1783 | }, 1784 | "autoload": { 1785 | "files": [ 1786 | "src/Framework/Assert/Functions.php" 1787 | ], 1788 | "classmap": [ 1789 | "src/" 1790 | ] 1791 | }, 1792 | "notification-url": "https://packagist.org/downloads/", 1793 | "license": [ 1794 | "BSD-3-Clause" 1795 | ], 1796 | "authors": [ 1797 | { 1798 | "name": "Sebastian Bergmann", 1799 | "email": "sebastian@phpunit.de", 1800 | "role": "lead" 1801 | } 1802 | ], 1803 | "description": "The PHP Unit Testing framework.", 1804 | "homepage": "https://phpunit.de/", 1805 | "keywords": [ 1806 | "phpunit", 1807 | "testing", 1808 | "xunit" 1809 | ], 1810 | "support": { 1811 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 1812 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 1813 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" 1814 | }, 1815 | "funding": [ 1816 | { 1817 | "url": "https://phpunit.de/sponsors.html", 1818 | "type": "custom" 1819 | }, 1820 | { 1821 | "url": "https://github.com/sebastianbergmann", 1822 | "type": "github" 1823 | }, 1824 | { 1825 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 1826 | "type": "tidelift" 1827 | } 1828 | ], 1829 | "time": "2023-08-19T07:10:56+00:00" 1830 | }, 1831 | { 1832 | "name": "psr/container", 1833 | "version": "2.0.2", 1834 | "source": { 1835 | "type": "git", 1836 | "url": "https://github.com/php-fig/container.git", 1837 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 1838 | }, 1839 | "dist": { 1840 | "type": "zip", 1841 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 1842 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 1843 | "shasum": "" 1844 | }, 1845 | "require": { 1846 | "php": ">=7.4.0" 1847 | }, 1848 | "type": "library", 1849 | "extra": { 1850 | "branch-alias": { 1851 | "dev-master": "2.0.x-dev" 1852 | } 1853 | }, 1854 | "autoload": { 1855 | "psr-4": { 1856 | "Psr\\Container\\": "src/" 1857 | } 1858 | }, 1859 | "notification-url": "https://packagist.org/downloads/", 1860 | "license": [ 1861 | "MIT" 1862 | ], 1863 | "authors": [ 1864 | { 1865 | "name": "PHP-FIG", 1866 | "homepage": "https://www.php-fig.org/" 1867 | } 1868 | ], 1869 | "description": "Common Container Interface (PHP FIG PSR-11)", 1870 | "homepage": "https://github.com/php-fig/container", 1871 | "keywords": [ 1872 | "PSR-11", 1873 | "container", 1874 | "container-interface", 1875 | "container-interop", 1876 | "psr" 1877 | ], 1878 | "support": { 1879 | "issues": "https://github.com/php-fig/container/issues", 1880 | "source": "https://github.com/php-fig/container/tree/2.0.2" 1881 | }, 1882 | "time": "2021-11-05T16:47:00+00:00" 1883 | }, 1884 | { 1885 | "name": "psr/log", 1886 | "version": "3.0.0", 1887 | "source": { 1888 | "type": "git", 1889 | "url": "https://github.com/php-fig/log.git", 1890 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" 1891 | }, 1892 | "dist": { 1893 | "type": "zip", 1894 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", 1895 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", 1896 | "shasum": "" 1897 | }, 1898 | "require": { 1899 | "php": ">=8.0.0" 1900 | }, 1901 | "type": "library", 1902 | "extra": { 1903 | "branch-alias": { 1904 | "dev-master": "3.x-dev" 1905 | } 1906 | }, 1907 | "autoload": { 1908 | "psr-4": { 1909 | "Psr\\Log\\": "src" 1910 | } 1911 | }, 1912 | "notification-url": "https://packagist.org/downloads/", 1913 | "license": [ 1914 | "MIT" 1915 | ], 1916 | "authors": [ 1917 | { 1918 | "name": "PHP-FIG", 1919 | "homepage": "https://www.php-fig.org/" 1920 | } 1921 | ], 1922 | "description": "Common interface for logging libraries", 1923 | "homepage": "https://github.com/php-fig/log", 1924 | "keywords": [ 1925 | "log", 1926 | "psr", 1927 | "psr-3" 1928 | ], 1929 | "support": { 1930 | "source": "https://github.com/php-fig/log/tree/3.0.0" 1931 | }, 1932 | "time": "2021-07-14T16:46:02+00:00" 1933 | }, 1934 | { 1935 | "name": "sebastian/cli-parser", 1936 | "version": "1.0.1", 1937 | "source": { 1938 | "type": "git", 1939 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 1940 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" 1941 | }, 1942 | "dist": { 1943 | "type": "zip", 1944 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", 1945 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", 1946 | "shasum": "" 1947 | }, 1948 | "require": { 1949 | "php": ">=7.3" 1950 | }, 1951 | "require-dev": { 1952 | "phpunit/phpunit": "^9.3" 1953 | }, 1954 | "type": "library", 1955 | "extra": { 1956 | "branch-alias": { 1957 | "dev-master": "1.0-dev" 1958 | } 1959 | }, 1960 | "autoload": { 1961 | "classmap": [ 1962 | "src/" 1963 | ] 1964 | }, 1965 | "notification-url": "https://packagist.org/downloads/", 1966 | "license": [ 1967 | "BSD-3-Clause" 1968 | ], 1969 | "authors": [ 1970 | { 1971 | "name": "Sebastian Bergmann", 1972 | "email": "sebastian@phpunit.de", 1973 | "role": "lead" 1974 | } 1975 | ], 1976 | "description": "Library for parsing CLI options", 1977 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 1978 | "support": { 1979 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 1980 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" 1981 | }, 1982 | "funding": [ 1983 | { 1984 | "url": "https://github.com/sebastianbergmann", 1985 | "type": "github" 1986 | } 1987 | ], 1988 | "time": "2020-09-28T06:08:49+00:00" 1989 | }, 1990 | { 1991 | "name": "sebastian/code-unit", 1992 | "version": "1.0.8", 1993 | "source": { 1994 | "type": "git", 1995 | "url": "https://github.com/sebastianbergmann/code-unit.git", 1996 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 1997 | }, 1998 | "dist": { 1999 | "type": "zip", 2000 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 2001 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 2002 | "shasum": "" 2003 | }, 2004 | "require": { 2005 | "php": ">=7.3" 2006 | }, 2007 | "require-dev": { 2008 | "phpunit/phpunit": "^9.3" 2009 | }, 2010 | "type": "library", 2011 | "extra": { 2012 | "branch-alias": { 2013 | "dev-master": "1.0-dev" 2014 | } 2015 | }, 2016 | "autoload": { 2017 | "classmap": [ 2018 | "src/" 2019 | ] 2020 | }, 2021 | "notification-url": "https://packagist.org/downloads/", 2022 | "license": [ 2023 | "BSD-3-Clause" 2024 | ], 2025 | "authors": [ 2026 | { 2027 | "name": "Sebastian Bergmann", 2028 | "email": "sebastian@phpunit.de", 2029 | "role": "lead" 2030 | } 2031 | ], 2032 | "description": "Collection of value objects that represent the PHP code units", 2033 | "homepage": "https://github.com/sebastianbergmann/code-unit", 2034 | "support": { 2035 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 2036 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 2037 | }, 2038 | "funding": [ 2039 | { 2040 | "url": "https://github.com/sebastianbergmann", 2041 | "type": "github" 2042 | } 2043 | ], 2044 | "time": "2020-10-26T13:08:54+00:00" 2045 | }, 2046 | { 2047 | "name": "sebastian/code-unit-reverse-lookup", 2048 | "version": "2.0.3", 2049 | "source": { 2050 | "type": "git", 2051 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 2052 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 2053 | }, 2054 | "dist": { 2055 | "type": "zip", 2056 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 2057 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 2058 | "shasum": "" 2059 | }, 2060 | "require": { 2061 | "php": ">=7.3" 2062 | }, 2063 | "require-dev": { 2064 | "phpunit/phpunit": "^9.3" 2065 | }, 2066 | "type": "library", 2067 | "extra": { 2068 | "branch-alias": { 2069 | "dev-master": "2.0-dev" 2070 | } 2071 | }, 2072 | "autoload": { 2073 | "classmap": [ 2074 | "src/" 2075 | ] 2076 | }, 2077 | "notification-url": "https://packagist.org/downloads/", 2078 | "license": [ 2079 | "BSD-3-Clause" 2080 | ], 2081 | "authors": [ 2082 | { 2083 | "name": "Sebastian Bergmann", 2084 | "email": "sebastian@phpunit.de" 2085 | } 2086 | ], 2087 | "description": "Looks up which function or method a line of code belongs to", 2088 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 2089 | "support": { 2090 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 2091 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 2092 | }, 2093 | "funding": [ 2094 | { 2095 | "url": "https://github.com/sebastianbergmann", 2096 | "type": "github" 2097 | } 2098 | ], 2099 | "time": "2020-09-28T05:30:19+00:00" 2100 | }, 2101 | { 2102 | "name": "sebastian/comparator", 2103 | "version": "4.0.8", 2104 | "source": { 2105 | "type": "git", 2106 | "url": "https://github.com/sebastianbergmann/comparator.git", 2107 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a" 2108 | }, 2109 | "dist": { 2110 | "type": "zip", 2111 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", 2112 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a", 2113 | "shasum": "" 2114 | }, 2115 | "require": { 2116 | "php": ">=7.3", 2117 | "sebastian/diff": "^4.0", 2118 | "sebastian/exporter": "^4.0" 2119 | }, 2120 | "require-dev": { 2121 | "phpunit/phpunit": "^9.3" 2122 | }, 2123 | "type": "library", 2124 | "extra": { 2125 | "branch-alias": { 2126 | "dev-master": "4.0-dev" 2127 | } 2128 | }, 2129 | "autoload": { 2130 | "classmap": [ 2131 | "src/" 2132 | ] 2133 | }, 2134 | "notification-url": "https://packagist.org/downloads/", 2135 | "license": [ 2136 | "BSD-3-Clause" 2137 | ], 2138 | "authors": [ 2139 | { 2140 | "name": "Sebastian Bergmann", 2141 | "email": "sebastian@phpunit.de" 2142 | }, 2143 | { 2144 | "name": "Jeff Welch", 2145 | "email": "whatthejeff@gmail.com" 2146 | }, 2147 | { 2148 | "name": "Volker Dusch", 2149 | "email": "github@wallbash.com" 2150 | }, 2151 | { 2152 | "name": "Bernhard Schussek", 2153 | "email": "bschussek@2bepublished.at" 2154 | } 2155 | ], 2156 | "description": "Provides the functionality to compare PHP values for equality", 2157 | "homepage": "https://github.com/sebastianbergmann/comparator", 2158 | "keywords": [ 2159 | "comparator", 2160 | "compare", 2161 | "equality" 2162 | ], 2163 | "support": { 2164 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 2165 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" 2166 | }, 2167 | "funding": [ 2168 | { 2169 | "url": "https://github.com/sebastianbergmann", 2170 | "type": "github" 2171 | } 2172 | ], 2173 | "time": "2022-09-14T12:41:17+00:00" 2174 | }, 2175 | { 2176 | "name": "sebastian/complexity", 2177 | "version": "2.0.2", 2178 | "source": { 2179 | "type": "git", 2180 | "url": "https://github.com/sebastianbergmann/complexity.git", 2181 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" 2182 | }, 2183 | "dist": { 2184 | "type": "zip", 2185 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", 2186 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", 2187 | "shasum": "" 2188 | }, 2189 | "require": { 2190 | "nikic/php-parser": "^4.7", 2191 | "php": ">=7.3" 2192 | }, 2193 | "require-dev": { 2194 | "phpunit/phpunit": "^9.3" 2195 | }, 2196 | "type": "library", 2197 | "extra": { 2198 | "branch-alias": { 2199 | "dev-master": "2.0-dev" 2200 | } 2201 | }, 2202 | "autoload": { 2203 | "classmap": [ 2204 | "src/" 2205 | ] 2206 | }, 2207 | "notification-url": "https://packagist.org/downloads/", 2208 | "license": [ 2209 | "BSD-3-Clause" 2210 | ], 2211 | "authors": [ 2212 | { 2213 | "name": "Sebastian Bergmann", 2214 | "email": "sebastian@phpunit.de", 2215 | "role": "lead" 2216 | } 2217 | ], 2218 | "description": "Library for calculating the complexity of PHP code units", 2219 | "homepage": "https://github.com/sebastianbergmann/complexity", 2220 | "support": { 2221 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 2222 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" 2223 | }, 2224 | "funding": [ 2225 | { 2226 | "url": "https://github.com/sebastianbergmann", 2227 | "type": "github" 2228 | } 2229 | ], 2230 | "time": "2020-10-26T15:52:27+00:00" 2231 | }, 2232 | { 2233 | "name": "sebastian/diff", 2234 | "version": "4.0.5", 2235 | "source": { 2236 | "type": "git", 2237 | "url": "https://github.com/sebastianbergmann/diff.git", 2238 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" 2239 | }, 2240 | "dist": { 2241 | "type": "zip", 2242 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", 2243 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", 2244 | "shasum": "" 2245 | }, 2246 | "require": { 2247 | "php": ">=7.3" 2248 | }, 2249 | "require-dev": { 2250 | "phpunit/phpunit": "^9.3", 2251 | "symfony/process": "^4.2 || ^5" 2252 | }, 2253 | "type": "library", 2254 | "extra": { 2255 | "branch-alias": { 2256 | "dev-master": "4.0-dev" 2257 | } 2258 | }, 2259 | "autoload": { 2260 | "classmap": [ 2261 | "src/" 2262 | ] 2263 | }, 2264 | "notification-url": "https://packagist.org/downloads/", 2265 | "license": [ 2266 | "BSD-3-Clause" 2267 | ], 2268 | "authors": [ 2269 | { 2270 | "name": "Sebastian Bergmann", 2271 | "email": "sebastian@phpunit.de" 2272 | }, 2273 | { 2274 | "name": "Kore Nordmann", 2275 | "email": "mail@kore-nordmann.de" 2276 | } 2277 | ], 2278 | "description": "Diff implementation", 2279 | "homepage": "https://github.com/sebastianbergmann/diff", 2280 | "keywords": [ 2281 | "diff", 2282 | "udiff", 2283 | "unidiff", 2284 | "unified diff" 2285 | ], 2286 | "support": { 2287 | "issues": "https://github.com/sebastianbergmann/diff/issues", 2288 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" 2289 | }, 2290 | "funding": [ 2291 | { 2292 | "url": "https://github.com/sebastianbergmann", 2293 | "type": "github" 2294 | } 2295 | ], 2296 | "time": "2023-05-07T05:35:17+00:00" 2297 | }, 2298 | { 2299 | "name": "sebastian/environment", 2300 | "version": "5.1.5", 2301 | "source": { 2302 | "type": "git", 2303 | "url": "https://github.com/sebastianbergmann/environment.git", 2304 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" 2305 | }, 2306 | "dist": { 2307 | "type": "zip", 2308 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 2309 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 2310 | "shasum": "" 2311 | }, 2312 | "require": { 2313 | "php": ">=7.3" 2314 | }, 2315 | "require-dev": { 2316 | "phpunit/phpunit": "^9.3" 2317 | }, 2318 | "suggest": { 2319 | "ext-posix": "*" 2320 | }, 2321 | "type": "library", 2322 | "extra": { 2323 | "branch-alias": { 2324 | "dev-master": "5.1-dev" 2325 | } 2326 | }, 2327 | "autoload": { 2328 | "classmap": [ 2329 | "src/" 2330 | ] 2331 | }, 2332 | "notification-url": "https://packagist.org/downloads/", 2333 | "license": [ 2334 | "BSD-3-Clause" 2335 | ], 2336 | "authors": [ 2337 | { 2338 | "name": "Sebastian Bergmann", 2339 | "email": "sebastian@phpunit.de" 2340 | } 2341 | ], 2342 | "description": "Provides functionality to handle HHVM/PHP environments", 2343 | "homepage": "http://www.github.com/sebastianbergmann/environment", 2344 | "keywords": [ 2345 | "Xdebug", 2346 | "environment", 2347 | "hhvm" 2348 | ], 2349 | "support": { 2350 | "issues": "https://github.com/sebastianbergmann/environment/issues", 2351 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" 2352 | }, 2353 | "funding": [ 2354 | { 2355 | "url": "https://github.com/sebastianbergmann", 2356 | "type": "github" 2357 | } 2358 | ], 2359 | "time": "2023-02-03T06:03:51+00:00" 2360 | }, 2361 | { 2362 | "name": "sebastian/exporter", 2363 | "version": "4.0.5", 2364 | "source": { 2365 | "type": "git", 2366 | "url": "https://github.com/sebastianbergmann/exporter.git", 2367 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" 2368 | }, 2369 | "dist": { 2370 | "type": "zip", 2371 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 2372 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 2373 | "shasum": "" 2374 | }, 2375 | "require": { 2376 | "php": ">=7.3", 2377 | "sebastian/recursion-context": "^4.0" 2378 | }, 2379 | "require-dev": { 2380 | "ext-mbstring": "*", 2381 | "phpunit/phpunit": "^9.3" 2382 | }, 2383 | "type": "library", 2384 | "extra": { 2385 | "branch-alias": { 2386 | "dev-master": "4.0-dev" 2387 | } 2388 | }, 2389 | "autoload": { 2390 | "classmap": [ 2391 | "src/" 2392 | ] 2393 | }, 2394 | "notification-url": "https://packagist.org/downloads/", 2395 | "license": [ 2396 | "BSD-3-Clause" 2397 | ], 2398 | "authors": [ 2399 | { 2400 | "name": "Sebastian Bergmann", 2401 | "email": "sebastian@phpunit.de" 2402 | }, 2403 | { 2404 | "name": "Jeff Welch", 2405 | "email": "whatthejeff@gmail.com" 2406 | }, 2407 | { 2408 | "name": "Volker Dusch", 2409 | "email": "github@wallbash.com" 2410 | }, 2411 | { 2412 | "name": "Adam Harvey", 2413 | "email": "aharvey@php.net" 2414 | }, 2415 | { 2416 | "name": "Bernhard Schussek", 2417 | "email": "bschussek@gmail.com" 2418 | } 2419 | ], 2420 | "description": "Provides the functionality to export PHP variables for visualization", 2421 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 2422 | "keywords": [ 2423 | "export", 2424 | "exporter" 2425 | ], 2426 | "support": { 2427 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 2428 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" 2429 | }, 2430 | "funding": [ 2431 | { 2432 | "url": "https://github.com/sebastianbergmann", 2433 | "type": "github" 2434 | } 2435 | ], 2436 | "time": "2022-09-14T06:03:37+00:00" 2437 | }, 2438 | { 2439 | "name": "sebastian/global-state", 2440 | "version": "5.0.6", 2441 | "source": { 2442 | "type": "git", 2443 | "url": "https://github.com/sebastianbergmann/global-state.git", 2444 | "reference": "bde739e7565280bda77be70044ac1047bc007e34" 2445 | }, 2446 | "dist": { 2447 | "type": "zip", 2448 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", 2449 | "reference": "bde739e7565280bda77be70044ac1047bc007e34", 2450 | "shasum": "" 2451 | }, 2452 | "require": { 2453 | "php": ">=7.3", 2454 | "sebastian/object-reflector": "^2.0", 2455 | "sebastian/recursion-context": "^4.0" 2456 | }, 2457 | "require-dev": { 2458 | "ext-dom": "*", 2459 | "phpunit/phpunit": "^9.3" 2460 | }, 2461 | "suggest": { 2462 | "ext-uopz": "*" 2463 | }, 2464 | "type": "library", 2465 | "extra": { 2466 | "branch-alias": { 2467 | "dev-master": "5.0-dev" 2468 | } 2469 | }, 2470 | "autoload": { 2471 | "classmap": [ 2472 | "src/" 2473 | ] 2474 | }, 2475 | "notification-url": "https://packagist.org/downloads/", 2476 | "license": [ 2477 | "BSD-3-Clause" 2478 | ], 2479 | "authors": [ 2480 | { 2481 | "name": "Sebastian Bergmann", 2482 | "email": "sebastian@phpunit.de" 2483 | } 2484 | ], 2485 | "description": "Snapshotting of global state", 2486 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 2487 | "keywords": [ 2488 | "global state" 2489 | ], 2490 | "support": { 2491 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 2492 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" 2493 | }, 2494 | "funding": [ 2495 | { 2496 | "url": "https://github.com/sebastianbergmann", 2497 | "type": "github" 2498 | } 2499 | ], 2500 | "time": "2023-08-02T09:26:13+00:00" 2501 | }, 2502 | { 2503 | "name": "sebastian/lines-of-code", 2504 | "version": "1.0.3", 2505 | "source": { 2506 | "type": "git", 2507 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 2508 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" 2509 | }, 2510 | "dist": { 2511 | "type": "zip", 2512 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", 2513 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", 2514 | "shasum": "" 2515 | }, 2516 | "require": { 2517 | "nikic/php-parser": "^4.6", 2518 | "php": ">=7.3" 2519 | }, 2520 | "require-dev": { 2521 | "phpunit/phpunit": "^9.3" 2522 | }, 2523 | "type": "library", 2524 | "extra": { 2525 | "branch-alias": { 2526 | "dev-master": "1.0-dev" 2527 | } 2528 | }, 2529 | "autoload": { 2530 | "classmap": [ 2531 | "src/" 2532 | ] 2533 | }, 2534 | "notification-url": "https://packagist.org/downloads/", 2535 | "license": [ 2536 | "BSD-3-Clause" 2537 | ], 2538 | "authors": [ 2539 | { 2540 | "name": "Sebastian Bergmann", 2541 | "email": "sebastian@phpunit.de", 2542 | "role": "lead" 2543 | } 2544 | ], 2545 | "description": "Library for counting the lines of code in PHP source code", 2546 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 2547 | "support": { 2548 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 2549 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" 2550 | }, 2551 | "funding": [ 2552 | { 2553 | "url": "https://github.com/sebastianbergmann", 2554 | "type": "github" 2555 | } 2556 | ], 2557 | "time": "2020-11-28T06:42:11+00:00" 2558 | }, 2559 | { 2560 | "name": "sebastian/object-enumerator", 2561 | "version": "4.0.4", 2562 | "source": { 2563 | "type": "git", 2564 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 2565 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 2566 | }, 2567 | "dist": { 2568 | "type": "zip", 2569 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 2570 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 2571 | "shasum": "" 2572 | }, 2573 | "require": { 2574 | "php": ">=7.3", 2575 | "sebastian/object-reflector": "^2.0", 2576 | "sebastian/recursion-context": "^4.0" 2577 | }, 2578 | "require-dev": { 2579 | "phpunit/phpunit": "^9.3" 2580 | }, 2581 | "type": "library", 2582 | "extra": { 2583 | "branch-alias": { 2584 | "dev-master": "4.0-dev" 2585 | } 2586 | }, 2587 | "autoload": { 2588 | "classmap": [ 2589 | "src/" 2590 | ] 2591 | }, 2592 | "notification-url": "https://packagist.org/downloads/", 2593 | "license": [ 2594 | "BSD-3-Clause" 2595 | ], 2596 | "authors": [ 2597 | { 2598 | "name": "Sebastian Bergmann", 2599 | "email": "sebastian@phpunit.de" 2600 | } 2601 | ], 2602 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 2603 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 2604 | "support": { 2605 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 2606 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 2607 | }, 2608 | "funding": [ 2609 | { 2610 | "url": "https://github.com/sebastianbergmann", 2611 | "type": "github" 2612 | } 2613 | ], 2614 | "time": "2020-10-26T13:12:34+00:00" 2615 | }, 2616 | { 2617 | "name": "sebastian/object-reflector", 2618 | "version": "2.0.4", 2619 | "source": { 2620 | "type": "git", 2621 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 2622 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 2623 | }, 2624 | "dist": { 2625 | "type": "zip", 2626 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 2627 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 2628 | "shasum": "" 2629 | }, 2630 | "require": { 2631 | "php": ">=7.3" 2632 | }, 2633 | "require-dev": { 2634 | "phpunit/phpunit": "^9.3" 2635 | }, 2636 | "type": "library", 2637 | "extra": { 2638 | "branch-alias": { 2639 | "dev-master": "2.0-dev" 2640 | } 2641 | }, 2642 | "autoload": { 2643 | "classmap": [ 2644 | "src/" 2645 | ] 2646 | }, 2647 | "notification-url": "https://packagist.org/downloads/", 2648 | "license": [ 2649 | "BSD-3-Clause" 2650 | ], 2651 | "authors": [ 2652 | { 2653 | "name": "Sebastian Bergmann", 2654 | "email": "sebastian@phpunit.de" 2655 | } 2656 | ], 2657 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 2658 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 2659 | "support": { 2660 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 2661 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 2662 | }, 2663 | "funding": [ 2664 | { 2665 | "url": "https://github.com/sebastianbergmann", 2666 | "type": "github" 2667 | } 2668 | ], 2669 | "time": "2020-10-26T13:14:26+00:00" 2670 | }, 2671 | { 2672 | "name": "sebastian/recursion-context", 2673 | "version": "4.0.5", 2674 | "source": { 2675 | "type": "git", 2676 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 2677 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" 2678 | }, 2679 | "dist": { 2680 | "type": "zip", 2681 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 2682 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 2683 | "shasum": "" 2684 | }, 2685 | "require": { 2686 | "php": ">=7.3" 2687 | }, 2688 | "require-dev": { 2689 | "phpunit/phpunit": "^9.3" 2690 | }, 2691 | "type": "library", 2692 | "extra": { 2693 | "branch-alias": { 2694 | "dev-master": "4.0-dev" 2695 | } 2696 | }, 2697 | "autoload": { 2698 | "classmap": [ 2699 | "src/" 2700 | ] 2701 | }, 2702 | "notification-url": "https://packagist.org/downloads/", 2703 | "license": [ 2704 | "BSD-3-Clause" 2705 | ], 2706 | "authors": [ 2707 | { 2708 | "name": "Sebastian Bergmann", 2709 | "email": "sebastian@phpunit.de" 2710 | }, 2711 | { 2712 | "name": "Jeff Welch", 2713 | "email": "whatthejeff@gmail.com" 2714 | }, 2715 | { 2716 | "name": "Adam Harvey", 2717 | "email": "aharvey@php.net" 2718 | } 2719 | ], 2720 | "description": "Provides functionality to recursively process PHP variables", 2721 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 2722 | "support": { 2723 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 2724 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" 2725 | }, 2726 | "funding": [ 2727 | { 2728 | "url": "https://github.com/sebastianbergmann", 2729 | "type": "github" 2730 | } 2731 | ], 2732 | "time": "2023-02-03T06:07:39+00:00" 2733 | }, 2734 | { 2735 | "name": "sebastian/resource-operations", 2736 | "version": "3.0.3", 2737 | "source": { 2738 | "type": "git", 2739 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 2740 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" 2741 | }, 2742 | "dist": { 2743 | "type": "zip", 2744 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 2745 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 2746 | "shasum": "" 2747 | }, 2748 | "require": { 2749 | "php": ">=7.3" 2750 | }, 2751 | "require-dev": { 2752 | "phpunit/phpunit": "^9.0" 2753 | }, 2754 | "type": "library", 2755 | "extra": { 2756 | "branch-alias": { 2757 | "dev-master": "3.0-dev" 2758 | } 2759 | }, 2760 | "autoload": { 2761 | "classmap": [ 2762 | "src/" 2763 | ] 2764 | }, 2765 | "notification-url": "https://packagist.org/downloads/", 2766 | "license": [ 2767 | "BSD-3-Clause" 2768 | ], 2769 | "authors": [ 2770 | { 2771 | "name": "Sebastian Bergmann", 2772 | "email": "sebastian@phpunit.de" 2773 | } 2774 | ], 2775 | "description": "Provides a list of PHP built-in functions that operate on resources", 2776 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 2777 | "support": { 2778 | "issues": "https://github.com/sebastianbergmann/resource-operations/issues", 2779 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" 2780 | }, 2781 | "funding": [ 2782 | { 2783 | "url": "https://github.com/sebastianbergmann", 2784 | "type": "github" 2785 | } 2786 | ], 2787 | "time": "2020-09-28T06:45:17+00:00" 2788 | }, 2789 | { 2790 | "name": "sebastian/type", 2791 | "version": "3.2.1", 2792 | "source": { 2793 | "type": "git", 2794 | "url": "https://github.com/sebastianbergmann/type.git", 2795 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" 2796 | }, 2797 | "dist": { 2798 | "type": "zip", 2799 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 2800 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 2801 | "shasum": "" 2802 | }, 2803 | "require": { 2804 | "php": ">=7.3" 2805 | }, 2806 | "require-dev": { 2807 | "phpunit/phpunit": "^9.5" 2808 | }, 2809 | "type": "library", 2810 | "extra": { 2811 | "branch-alias": { 2812 | "dev-master": "3.2-dev" 2813 | } 2814 | }, 2815 | "autoload": { 2816 | "classmap": [ 2817 | "src/" 2818 | ] 2819 | }, 2820 | "notification-url": "https://packagist.org/downloads/", 2821 | "license": [ 2822 | "BSD-3-Clause" 2823 | ], 2824 | "authors": [ 2825 | { 2826 | "name": "Sebastian Bergmann", 2827 | "email": "sebastian@phpunit.de", 2828 | "role": "lead" 2829 | } 2830 | ], 2831 | "description": "Collection of value objects that represent the types of the PHP type system", 2832 | "homepage": "https://github.com/sebastianbergmann/type", 2833 | "support": { 2834 | "issues": "https://github.com/sebastianbergmann/type/issues", 2835 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" 2836 | }, 2837 | "funding": [ 2838 | { 2839 | "url": "https://github.com/sebastianbergmann", 2840 | "type": "github" 2841 | } 2842 | ], 2843 | "time": "2023-02-03T06:13:03+00:00" 2844 | }, 2845 | { 2846 | "name": "sebastian/version", 2847 | "version": "3.0.2", 2848 | "source": { 2849 | "type": "git", 2850 | "url": "https://github.com/sebastianbergmann/version.git", 2851 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 2852 | }, 2853 | "dist": { 2854 | "type": "zip", 2855 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 2856 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 2857 | "shasum": "" 2858 | }, 2859 | "require": { 2860 | "php": ">=7.3" 2861 | }, 2862 | "type": "library", 2863 | "extra": { 2864 | "branch-alias": { 2865 | "dev-master": "3.0-dev" 2866 | } 2867 | }, 2868 | "autoload": { 2869 | "classmap": [ 2870 | "src/" 2871 | ] 2872 | }, 2873 | "notification-url": "https://packagist.org/downloads/", 2874 | "license": [ 2875 | "BSD-3-Clause" 2876 | ], 2877 | "authors": [ 2878 | { 2879 | "name": "Sebastian Bergmann", 2880 | "email": "sebastian@phpunit.de", 2881 | "role": "lead" 2882 | } 2883 | ], 2884 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2885 | "homepage": "https://github.com/sebastianbergmann/version", 2886 | "support": { 2887 | "issues": "https://github.com/sebastianbergmann/version/issues", 2888 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 2889 | }, 2890 | "funding": [ 2891 | { 2892 | "url": "https://github.com/sebastianbergmann", 2893 | "type": "github" 2894 | } 2895 | ], 2896 | "time": "2020-09-28T06:39:44+00:00" 2897 | }, 2898 | { 2899 | "name": "spatie/array-to-xml", 2900 | "version": "3.2.0", 2901 | "source": { 2902 | "type": "git", 2903 | "url": "https://github.com/spatie/array-to-xml.git", 2904 | "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7" 2905 | }, 2906 | "dist": { 2907 | "type": "zip", 2908 | "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f9ab39c808500c347d5a8b6b13310bd5221e39e7", 2909 | "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7", 2910 | "shasum": "" 2911 | }, 2912 | "require": { 2913 | "ext-dom": "*", 2914 | "php": "^8.0" 2915 | }, 2916 | "require-dev": { 2917 | "mockery/mockery": "^1.2", 2918 | "pestphp/pest": "^1.21", 2919 | "spatie/pest-plugin-snapshots": "^1.1" 2920 | }, 2921 | "type": "library", 2922 | "autoload": { 2923 | "psr-4": { 2924 | "Spatie\\ArrayToXml\\": "src" 2925 | } 2926 | }, 2927 | "notification-url": "https://packagist.org/downloads/", 2928 | "license": [ 2929 | "MIT" 2930 | ], 2931 | "authors": [ 2932 | { 2933 | "name": "Freek Van der Herten", 2934 | "email": "freek@spatie.be", 2935 | "homepage": "https://freek.dev", 2936 | "role": "Developer" 2937 | } 2938 | ], 2939 | "description": "Convert an array to xml", 2940 | "homepage": "https://github.com/spatie/array-to-xml", 2941 | "keywords": [ 2942 | "array", 2943 | "convert", 2944 | "xml" 2945 | ], 2946 | "support": { 2947 | "source": "https://github.com/spatie/array-to-xml/tree/3.2.0" 2948 | }, 2949 | "funding": [ 2950 | { 2951 | "url": "https://spatie.be/open-source/support-us", 2952 | "type": "custom" 2953 | }, 2954 | { 2955 | "url": "https://github.com/spatie", 2956 | "type": "github" 2957 | } 2958 | ], 2959 | "time": "2023-07-19T18:30:26+00:00" 2960 | }, 2961 | { 2962 | "name": "symfony/console", 2963 | "version": "v6.0.19", 2964 | "source": { 2965 | "type": "git", 2966 | "url": "https://github.com/symfony/console.git", 2967 | "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed" 2968 | }, 2969 | "dist": { 2970 | "type": "zip", 2971 | "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed", 2972 | "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed", 2973 | "shasum": "" 2974 | }, 2975 | "require": { 2976 | "php": ">=8.0.2", 2977 | "symfony/polyfill-mbstring": "~1.0", 2978 | "symfony/service-contracts": "^1.1|^2|^3", 2979 | "symfony/string": "^5.4|^6.0" 2980 | }, 2981 | "conflict": { 2982 | "symfony/dependency-injection": "<5.4", 2983 | "symfony/dotenv": "<5.4", 2984 | "symfony/event-dispatcher": "<5.4", 2985 | "symfony/lock": "<5.4", 2986 | "symfony/process": "<5.4" 2987 | }, 2988 | "provide": { 2989 | "psr/log-implementation": "1.0|2.0|3.0" 2990 | }, 2991 | "require-dev": { 2992 | "psr/log": "^1|^2|^3", 2993 | "symfony/config": "^5.4|^6.0", 2994 | "symfony/dependency-injection": "^5.4|^6.0", 2995 | "symfony/event-dispatcher": "^5.4|^6.0", 2996 | "symfony/lock": "^5.4|^6.0", 2997 | "symfony/process": "^5.4|^6.0", 2998 | "symfony/var-dumper": "^5.4|^6.0" 2999 | }, 3000 | "suggest": { 3001 | "psr/log": "For using the console logger", 3002 | "symfony/event-dispatcher": "", 3003 | "symfony/lock": "", 3004 | "symfony/process": "" 3005 | }, 3006 | "type": "library", 3007 | "autoload": { 3008 | "psr-4": { 3009 | "Symfony\\Component\\Console\\": "" 3010 | }, 3011 | "exclude-from-classmap": [ 3012 | "/Tests/" 3013 | ] 3014 | }, 3015 | "notification-url": "https://packagist.org/downloads/", 3016 | "license": [ 3017 | "MIT" 3018 | ], 3019 | "authors": [ 3020 | { 3021 | "name": "Fabien Potencier", 3022 | "email": "fabien@symfony.com" 3023 | }, 3024 | { 3025 | "name": "Symfony Community", 3026 | "homepage": "https://symfony.com/contributors" 3027 | } 3028 | ], 3029 | "description": "Eases the creation of beautiful and testable command line interfaces", 3030 | "homepage": "https://symfony.com", 3031 | "keywords": [ 3032 | "cli", 3033 | "command line", 3034 | "console", 3035 | "terminal" 3036 | ], 3037 | "support": { 3038 | "source": "https://github.com/symfony/console/tree/v6.0.19" 3039 | }, 3040 | "funding": [ 3041 | { 3042 | "url": "https://symfony.com/sponsor", 3043 | "type": "custom" 3044 | }, 3045 | { 3046 | "url": "https://github.com/fabpot", 3047 | "type": "github" 3048 | }, 3049 | { 3050 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3051 | "type": "tidelift" 3052 | } 3053 | ], 3054 | "time": "2023-01-01T08:36:10+00:00" 3055 | }, 3056 | { 3057 | "name": "symfony/filesystem", 3058 | "version": "v6.0.19", 3059 | "source": { 3060 | "type": "git", 3061 | "url": "https://github.com/symfony/filesystem.git", 3062 | "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214" 3063 | }, 3064 | "dist": { 3065 | "type": "zip", 3066 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/3d49eec03fda1f0fc19b7349fbbe55ebc1004214", 3067 | "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214", 3068 | "shasum": "" 3069 | }, 3070 | "require": { 3071 | "php": ">=8.0.2", 3072 | "symfony/polyfill-ctype": "~1.8", 3073 | "symfony/polyfill-mbstring": "~1.8" 3074 | }, 3075 | "type": "library", 3076 | "autoload": { 3077 | "psr-4": { 3078 | "Symfony\\Component\\Filesystem\\": "" 3079 | }, 3080 | "exclude-from-classmap": [ 3081 | "/Tests/" 3082 | ] 3083 | }, 3084 | "notification-url": "https://packagist.org/downloads/", 3085 | "license": [ 3086 | "MIT" 3087 | ], 3088 | "authors": [ 3089 | { 3090 | "name": "Fabien Potencier", 3091 | "email": "fabien@symfony.com" 3092 | }, 3093 | { 3094 | "name": "Symfony Community", 3095 | "homepage": "https://symfony.com/contributors" 3096 | } 3097 | ], 3098 | "description": "Provides basic utilities for the filesystem", 3099 | "homepage": "https://symfony.com", 3100 | "support": { 3101 | "source": "https://github.com/symfony/filesystem/tree/v6.0.19" 3102 | }, 3103 | "funding": [ 3104 | { 3105 | "url": "https://symfony.com/sponsor", 3106 | "type": "custom" 3107 | }, 3108 | { 3109 | "url": "https://github.com/fabpot", 3110 | "type": "github" 3111 | }, 3112 | { 3113 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3114 | "type": "tidelift" 3115 | } 3116 | ], 3117 | "time": "2023-01-20T17:44:14+00:00" 3118 | }, 3119 | { 3120 | "name": "symfony/polyfill-ctype", 3121 | "version": "v1.28.0", 3122 | "source": { 3123 | "type": "git", 3124 | "url": "https://github.com/symfony/polyfill-ctype.git", 3125 | "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" 3126 | }, 3127 | "dist": { 3128 | "type": "zip", 3129 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", 3130 | "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", 3131 | "shasum": "" 3132 | }, 3133 | "require": { 3134 | "php": ">=7.1" 3135 | }, 3136 | "provide": { 3137 | "ext-ctype": "*" 3138 | }, 3139 | "suggest": { 3140 | "ext-ctype": "For best performance" 3141 | }, 3142 | "type": "library", 3143 | "extra": { 3144 | "branch-alias": { 3145 | "dev-main": "1.28-dev" 3146 | }, 3147 | "thanks": { 3148 | "name": "symfony/polyfill", 3149 | "url": "https://github.com/symfony/polyfill" 3150 | } 3151 | }, 3152 | "autoload": { 3153 | "files": [ 3154 | "bootstrap.php" 3155 | ], 3156 | "psr-4": { 3157 | "Symfony\\Polyfill\\Ctype\\": "" 3158 | } 3159 | }, 3160 | "notification-url": "https://packagist.org/downloads/", 3161 | "license": [ 3162 | "MIT" 3163 | ], 3164 | "authors": [ 3165 | { 3166 | "name": "Gert de Pagter", 3167 | "email": "BackEndTea@gmail.com" 3168 | }, 3169 | { 3170 | "name": "Symfony Community", 3171 | "homepage": "https://symfony.com/contributors" 3172 | } 3173 | ], 3174 | "description": "Symfony polyfill for ctype functions", 3175 | "homepage": "https://symfony.com", 3176 | "keywords": [ 3177 | "compatibility", 3178 | "ctype", 3179 | "polyfill", 3180 | "portable" 3181 | ], 3182 | "support": { 3183 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" 3184 | }, 3185 | "funding": [ 3186 | { 3187 | "url": "https://symfony.com/sponsor", 3188 | "type": "custom" 3189 | }, 3190 | { 3191 | "url": "https://github.com/fabpot", 3192 | "type": "github" 3193 | }, 3194 | { 3195 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3196 | "type": "tidelift" 3197 | } 3198 | ], 3199 | "time": "2023-01-26T09:26:14+00:00" 3200 | }, 3201 | { 3202 | "name": "symfony/polyfill-intl-grapheme", 3203 | "version": "v1.28.0", 3204 | "source": { 3205 | "type": "git", 3206 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 3207 | "reference": "875e90aeea2777b6f135677f618529449334a612" 3208 | }, 3209 | "dist": { 3210 | "type": "zip", 3211 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", 3212 | "reference": "875e90aeea2777b6f135677f618529449334a612", 3213 | "shasum": "" 3214 | }, 3215 | "require": { 3216 | "php": ">=7.1" 3217 | }, 3218 | "suggest": { 3219 | "ext-intl": "For best performance" 3220 | }, 3221 | "type": "library", 3222 | "extra": { 3223 | "branch-alias": { 3224 | "dev-main": "1.28-dev" 3225 | }, 3226 | "thanks": { 3227 | "name": "symfony/polyfill", 3228 | "url": "https://github.com/symfony/polyfill" 3229 | } 3230 | }, 3231 | "autoload": { 3232 | "files": [ 3233 | "bootstrap.php" 3234 | ], 3235 | "psr-4": { 3236 | "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 3237 | } 3238 | }, 3239 | "notification-url": "https://packagist.org/downloads/", 3240 | "license": [ 3241 | "MIT" 3242 | ], 3243 | "authors": [ 3244 | { 3245 | "name": "Nicolas Grekas", 3246 | "email": "p@tchwork.com" 3247 | }, 3248 | { 3249 | "name": "Symfony Community", 3250 | "homepage": "https://symfony.com/contributors" 3251 | } 3252 | ], 3253 | "description": "Symfony polyfill for intl's grapheme_* functions", 3254 | "homepage": "https://symfony.com", 3255 | "keywords": [ 3256 | "compatibility", 3257 | "grapheme", 3258 | "intl", 3259 | "polyfill", 3260 | "portable", 3261 | "shim" 3262 | ], 3263 | "support": { 3264 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" 3265 | }, 3266 | "funding": [ 3267 | { 3268 | "url": "https://symfony.com/sponsor", 3269 | "type": "custom" 3270 | }, 3271 | { 3272 | "url": "https://github.com/fabpot", 3273 | "type": "github" 3274 | }, 3275 | { 3276 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3277 | "type": "tidelift" 3278 | } 3279 | ], 3280 | "time": "2023-01-26T09:26:14+00:00" 3281 | }, 3282 | { 3283 | "name": "symfony/polyfill-intl-normalizer", 3284 | "version": "v1.28.0", 3285 | "source": { 3286 | "type": "git", 3287 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 3288 | "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" 3289 | }, 3290 | "dist": { 3291 | "type": "zip", 3292 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", 3293 | "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", 3294 | "shasum": "" 3295 | }, 3296 | "require": { 3297 | "php": ">=7.1" 3298 | }, 3299 | "suggest": { 3300 | "ext-intl": "For best performance" 3301 | }, 3302 | "type": "library", 3303 | "extra": { 3304 | "branch-alias": { 3305 | "dev-main": "1.28-dev" 3306 | }, 3307 | "thanks": { 3308 | "name": "symfony/polyfill", 3309 | "url": "https://github.com/symfony/polyfill" 3310 | } 3311 | }, 3312 | "autoload": { 3313 | "files": [ 3314 | "bootstrap.php" 3315 | ], 3316 | "psr-4": { 3317 | "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 3318 | }, 3319 | "classmap": [ 3320 | "Resources/stubs" 3321 | ] 3322 | }, 3323 | "notification-url": "https://packagist.org/downloads/", 3324 | "license": [ 3325 | "MIT" 3326 | ], 3327 | "authors": [ 3328 | { 3329 | "name": "Nicolas Grekas", 3330 | "email": "p@tchwork.com" 3331 | }, 3332 | { 3333 | "name": "Symfony Community", 3334 | "homepage": "https://symfony.com/contributors" 3335 | } 3336 | ], 3337 | "description": "Symfony polyfill for intl's Normalizer class and related functions", 3338 | "homepage": "https://symfony.com", 3339 | "keywords": [ 3340 | "compatibility", 3341 | "intl", 3342 | "normalizer", 3343 | "polyfill", 3344 | "portable", 3345 | "shim" 3346 | ], 3347 | "support": { 3348 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" 3349 | }, 3350 | "funding": [ 3351 | { 3352 | "url": "https://symfony.com/sponsor", 3353 | "type": "custom" 3354 | }, 3355 | { 3356 | "url": "https://github.com/fabpot", 3357 | "type": "github" 3358 | }, 3359 | { 3360 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3361 | "type": "tidelift" 3362 | } 3363 | ], 3364 | "time": "2023-01-26T09:26:14+00:00" 3365 | }, 3366 | { 3367 | "name": "symfony/polyfill-mbstring", 3368 | "version": "v1.28.0", 3369 | "source": { 3370 | "type": "git", 3371 | "url": "https://github.com/symfony/polyfill-mbstring.git", 3372 | "reference": "42292d99c55abe617799667f454222c54c60e229" 3373 | }, 3374 | "dist": { 3375 | "type": "zip", 3376 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", 3377 | "reference": "42292d99c55abe617799667f454222c54c60e229", 3378 | "shasum": "" 3379 | }, 3380 | "require": { 3381 | "php": ">=7.1" 3382 | }, 3383 | "provide": { 3384 | "ext-mbstring": "*" 3385 | }, 3386 | "suggest": { 3387 | "ext-mbstring": "For best performance" 3388 | }, 3389 | "type": "library", 3390 | "extra": { 3391 | "branch-alias": { 3392 | "dev-main": "1.28-dev" 3393 | }, 3394 | "thanks": { 3395 | "name": "symfony/polyfill", 3396 | "url": "https://github.com/symfony/polyfill" 3397 | } 3398 | }, 3399 | "autoload": { 3400 | "files": [ 3401 | "bootstrap.php" 3402 | ], 3403 | "psr-4": { 3404 | "Symfony\\Polyfill\\Mbstring\\": "" 3405 | } 3406 | }, 3407 | "notification-url": "https://packagist.org/downloads/", 3408 | "license": [ 3409 | "MIT" 3410 | ], 3411 | "authors": [ 3412 | { 3413 | "name": "Nicolas Grekas", 3414 | "email": "p@tchwork.com" 3415 | }, 3416 | { 3417 | "name": "Symfony Community", 3418 | "homepage": "https://symfony.com/contributors" 3419 | } 3420 | ], 3421 | "description": "Symfony polyfill for the Mbstring extension", 3422 | "homepage": "https://symfony.com", 3423 | "keywords": [ 3424 | "compatibility", 3425 | "mbstring", 3426 | "polyfill", 3427 | "portable", 3428 | "shim" 3429 | ], 3430 | "support": { 3431 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" 3432 | }, 3433 | "funding": [ 3434 | { 3435 | "url": "https://symfony.com/sponsor", 3436 | "type": "custom" 3437 | }, 3438 | { 3439 | "url": "https://github.com/fabpot", 3440 | "type": "github" 3441 | }, 3442 | { 3443 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3444 | "type": "tidelift" 3445 | } 3446 | ], 3447 | "time": "2023-07-28T09:04:16+00:00" 3448 | }, 3449 | { 3450 | "name": "symfony/service-contracts", 3451 | "version": "v3.0.2", 3452 | "source": { 3453 | "type": "git", 3454 | "url": "https://github.com/symfony/service-contracts.git", 3455 | "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66" 3456 | }, 3457 | "dist": { 3458 | "type": "zip", 3459 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66", 3460 | "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66", 3461 | "shasum": "" 3462 | }, 3463 | "require": { 3464 | "php": ">=8.0.2", 3465 | "psr/container": "^2.0" 3466 | }, 3467 | "conflict": { 3468 | "ext-psr": "<1.1|>=2" 3469 | }, 3470 | "suggest": { 3471 | "symfony/service-implementation": "" 3472 | }, 3473 | "type": "library", 3474 | "extra": { 3475 | "branch-alias": { 3476 | "dev-main": "3.0-dev" 3477 | }, 3478 | "thanks": { 3479 | "name": "symfony/contracts", 3480 | "url": "https://github.com/symfony/contracts" 3481 | } 3482 | }, 3483 | "autoload": { 3484 | "psr-4": { 3485 | "Symfony\\Contracts\\Service\\": "" 3486 | } 3487 | }, 3488 | "notification-url": "https://packagist.org/downloads/", 3489 | "license": [ 3490 | "MIT" 3491 | ], 3492 | "authors": [ 3493 | { 3494 | "name": "Nicolas Grekas", 3495 | "email": "p@tchwork.com" 3496 | }, 3497 | { 3498 | "name": "Symfony Community", 3499 | "homepage": "https://symfony.com/contributors" 3500 | } 3501 | ], 3502 | "description": "Generic abstractions related to writing services", 3503 | "homepage": "https://symfony.com", 3504 | "keywords": [ 3505 | "abstractions", 3506 | "contracts", 3507 | "decoupling", 3508 | "interfaces", 3509 | "interoperability", 3510 | "standards" 3511 | ], 3512 | "support": { 3513 | "source": "https://github.com/symfony/service-contracts/tree/v3.0.2" 3514 | }, 3515 | "funding": [ 3516 | { 3517 | "url": "https://symfony.com/sponsor", 3518 | "type": "custom" 3519 | }, 3520 | { 3521 | "url": "https://github.com/fabpot", 3522 | "type": "github" 3523 | }, 3524 | { 3525 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3526 | "type": "tidelift" 3527 | } 3528 | ], 3529 | "time": "2022-05-30T19:17:58+00:00" 3530 | }, 3531 | { 3532 | "name": "symfony/string", 3533 | "version": "v6.0.19", 3534 | "source": { 3535 | "type": "git", 3536 | "url": "https://github.com/symfony/string.git", 3537 | "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a" 3538 | }, 3539 | "dist": { 3540 | "type": "zip", 3541 | "url": "https://api.github.com/repos/symfony/string/zipball/d9e72497367c23e08bf94176d2be45b00a9d232a", 3542 | "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a", 3543 | "shasum": "" 3544 | }, 3545 | "require": { 3546 | "php": ">=8.0.2", 3547 | "symfony/polyfill-ctype": "~1.8", 3548 | "symfony/polyfill-intl-grapheme": "~1.0", 3549 | "symfony/polyfill-intl-normalizer": "~1.0", 3550 | "symfony/polyfill-mbstring": "~1.0" 3551 | }, 3552 | "conflict": { 3553 | "symfony/translation-contracts": "<2.0" 3554 | }, 3555 | "require-dev": { 3556 | "symfony/error-handler": "^5.4|^6.0", 3557 | "symfony/http-client": "^5.4|^6.0", 3558 | "symfony/translation-contracts": "^2.0|^3.0", 3559 | "symfony/var-exporter": "^5.4|^6.0" 3560 | }, 3561 | "type": "library", 3562 | "autoload": { 3563 | "files": [ 3564 | "Resources/functions.php" 3565 | ], 3566 | "psr-4": { 3567 | "Symfony\\Component\\String\\": "" 3568 | }, 3569 | "exclude-from-classmap": [ 3570 | "/Tests/" 3571 | ] 3572 | }, 3573 | "notification-url": "https://packagist.org/downloads/", 3574 | "license": [ 3575 | "MIT" 3576 | ], 3577 | "authors": [ 3578 | { 3579 | "name": "Nicolas Grekas", 3580 | "email": "p@tchwork.com" 3581 | }, 3582 | { 3583 | "name": "Symfony Community", 3584 | "homepage": "https://symfony.com/contributors" 3585 | } 3586 | ], 3587 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", 3588 | "homepage": "https://symfony.com", 3589 | "keywords": [ 3590 | "grapheme", 3591 | "i18n", 3592 | "string", 3593 | "unicode", 3594 | "utf-8", 3595 | "utf8" 3596 | ], 3597 | "support": { 3598 | "source": "https://github.com/symfony/string/tree/v6.0.19" 3599 | }, 3600 | "funding": [ 3601 | { 3602 | "url": "https://symfony.com/sponsor", 3603 | "type": "custom" 3604 | }, 3605 | { 3606 | "url": "https://github.com/fabpot", 3607 | "type": "github" 3608 | }, 3609 | { 3610 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3611 | "type": "tidelift" 3612 | } 3613 | ], 3614 | "time": "2023-01-01T08:36:10+00:00" 3615 | }, 3616 | { 3617 | "name": "theseer/tokenizer", 3618 | "version": "1.2.1", 3619 | "source": { 3620 | "type": "git", 3621 | "url": "https://github.com/theseer/tokenizer.git", 3622 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" 3623 | }, 3624 | "dist": { 3625 | "type": "zip", 3626 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", 3627 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", 3628 | "shasum": "" 3629 | }, 3630 | "require": { 3631 | "ext-dom": "*", 3632 | "ext-tokenizer": "*", 3633 | "ext-xmlwriter": "*", 3634 | "php": "^7.2 || ^8.0" 3635 | }, 3636 | "type": "library", 3637 | "autoload": { 3638 | "classmap": [ 3639 | "src/" 3640 | ] 3641 | }, 3642 | "notification-url": "https://packagist.org/downloads/", 3643 | "license": [ 3644 | "BSD-3-Clause" 3645 | ], 3646 | "authors": [ 3647 | { 3648 | "name": "Arne Blankerts", 3649 | "email": "arne@blankerts.de", 3650 | "role": "Developer" 3651 | } 3652 | ], 3653 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 3654 | "support": { 3655 | "issues": "https://github.com/theseer/tokenizer/issues", 3656 | "source": "https://github.com/theseer/tokenizer/tree/1.2.1" 3657 | }, 3658 | "funding": [ 3659 | { 3660 | "url": "https://github.com/theseer", 3661 | "type": "github" 3662 | } 3663 | ], 3664 | "time": "2021-07-28T10:34:58+00:00" 3665 | }, 3666 | { 3667 | "name": "vimeo/psalm", 3668 | "version": "5.15.0", 3669 | "source": { 3670 | "type": "git", 3671 | "url": "https://github.com/vimeo/psalm.git", 3672 | "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352" 3673 | }, 3674 | "dist": { 3675 | "type": "zip", 3676 | "url": "https://api.github.com/repos/vimeo/psalm/zipball/5c774aca4746caf3d239d9c8cadb9f882ca29352", 3677 | "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352", 3678 | "shasum": "" 3679 | }, 3680 | "require": { 3681 | "amphp/amp": "^2.4.2", 3682 | "amphp/byte-stream": "^1.5", 3683 | "composer-runtime-api": "^2", 3684 | "composer/semver": "^1.4 || ^2.0 || ^3.0", 3685 | "composer/xdebug-handler": "^2.0 || ^3.0", 3686 | "dnoegel/php-xdg-base-dir": "^0.1.1", 3687 | "ext-ctype": "*", 3688 | "ext-dom": "*", 3689 | "ext-json": "*", 3690 | "ext-libxml": "*", 3691 | "ext-mbstring": "*", 3692 | "ext-simplexml": "*", 3693 | "ext-tokenizer": "*", 3694 | "felixfbecker/advanced-json-rpc": "^3.1", 3695 | "felixfbecker/language-server-protocol": "^1.5.2", 3696 | "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", 3697 | "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", 3698 | "nikic/php-parser": "^4.16", 3699 | "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", 3700 | "sebastian/diff": "^4.0 || ^5.0", 3701 | "spatie/array-to-xml": "^2.17.0 || ^3.0", 3702 | "symfony/console": "^4.1.6 || ^5.0 || ^6.0", 3703 | "symfony/filesystem": "^5.4 || ^6.0" 3704 | }, 3705 | "conflict": { 3706 | "nikic/php-parser": "4.17.0" 3707 | }, 3708 | "provide": { 3709 | "psalm/psalm": "self.version" 3710 | }, 3711 | "require-dev": { 3712 | "amphp/phpunit-util": "^2.0", 3713 | "bamarni/composer-bin-plugin": "^1.4", 3714 | "brianium/paratest": "^6.9", 3715 | "ext-curl": "*", 3716 | "mockery/mockery": "^1.5", 3717 | "nunomaduro/mock-final-classes": "^1.1", 3718 | "php-parallel-lint/php-parallel-lint": "^1.2", 3719 | "phpstan/phpdoc-parser": "^1.6", 3720 | "phpunit/phpunit": "^9.6", 3721 | "psalm/plugin-mockery": "^1.1", 3722 | "psalm/plugin-phpunit": "^0.18", 3723 | "slevomat/coding-standard": "^8.4", 3724 | "squizlabs/php_codesniffer": "^3.6", 3725 | "symfony/process": "^4.4 || ^5.0 || ^6.0" 3726 | }, 3727 | "suggest": { 3728 | "ext-curl": "In order to send data to shepherd", 3729 | "ext-igbinary": "^2.0.5 is required, used to serialize caching data" 3730 | }, 3731 | "bin": [ 3732 | "psalm", 3733 | "psalm-language-server", 3734 | "psalm-plugin", 3735 | "psalm-refactor", 3736 | "psalter" 3737 | ], 3738 | "type": "library", 3739 | "extra": { 3740 | "branch-alias": { 3741 | "dev-master": "5.x-dev", 3742 | "dev-4.x": "4.x-dev", 3743 | "dev-3.x": "3.x-dev", 3744 | "dev-2.x": "2.x-dev", 3745 | "dev-1.x": "1.x-dev" 3746 | } 3747 | }, 3748 | "autoload": { 3749 | "psr-4": { 3750 | "Psalm\\": "src/Psalm/" 3751 | } 3752 | }, 3753 | "notification-url": "https://packagist.org/downloads/", 3754 | "license": [ 3755 | "MIT" 3756 | ], 3757 | "authors": [ 3758 | { 3759 | "name": "Matthew Brown" 3760 | } 3761 | ], 3762 | "description": "A static analysis tool for finding errors in PHP applications", 3763 | "keywords": [ 3764 | "code", 3765 | "inspection", 3766 | "php", 3767 | "static analysis" 3768 | ], 3769 | "support": { 3770 | "issues": "https://github.com/vimeo/psalm/issues", 3771 | "source": "https://github.com/vimeo/psalm/tree/5.15.0" 3772 | }, 3773 | "time": "2023-08-20T23:07:30+00:00" 3774 | }, 3775 | { 3776 | "name": "webmozart/assert", 3777 | "version": "1.11.0", 3778 | "source": { 3779 | "type": "git", 3780 | "url": "https://github.com/webmozarts/assert.git", 3781 | "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" 3782 | }, 3783 | "dist": { 3784 | "type": "zip", 3785 | "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", 3786 | "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", 3787 | "shasum": "" 3788 | }, 3789 | "require": { 3790 | "ext-ctype": "*", 3791 | "php": "^7.2 || ^8.0" 3792 | }, 3793 | "conflict": { 3794 | "phpstan/phpstan": "<0.12.20", 3795 | "vimeo/psalm": "<4.6.1 || 4.6.2" 3796 | }, 3797 | "require-dev": { 3798 | "phpunit/phpunit": "^8.5.13" 3799 | }, 3800 | "type": "library", 3801 | "extra": { 3802 | "branch-alias": { 3803 | "dev-master": "1.10-dev" 3804 | } 3805 | }, 3806 | "autoload": { 3807 | "psr-4": { 3808 | "Webmozart\\Assert\\": "src/" 3809 | } 3810 | }, 3811 | "notification-url": "https://packagist.org/downloads/", 3812 | "license": [ 3813 | "MIT" 3814 | ], 3815 | "authors": [ 3816 | { 3817 | "name": "Bernhard Schussek", 3818 | "email": "bschussek@gmail.com" 3819 | } 3820 | ], 3821 | "description": "Assertions to validate method input/output with nice error messages.", 3822 | "keywords": [ 3823 | "assert", 3824 | "check", 3825 | "validate" 3826 | ], 3827 | "support": { 3828 | "issues": "https://github.com/webmozarts/assert/issues", 3829 | "source": "https://github.com/webmozarts/assert/tree/1.11.0" 3830 | }, 3831 | "time": "2022-06-03T18:03:27+00:00" 3832 | } 3833 | ], 3834 | "aliases": [], 3835 | "minimum-stability": "stable", 3836 | "stability-flags": [], 3837 | "prefer-stable": false, 3838 | "prefer-lowest": false, 3839 | "platform": { 3840 | "php": "^8.0", 3841 | "ext-curl": "*", 3842 | "ext-dom": "*", 3843 | "ext-mbstring": "*", 3844 | "ext-simplexml": "*", 3845 | "ext-spl": "*", 3846 | "ext-xml": "*", 3847 | "ext-xmlwriter": "*", 3848 | "ext-zlib": "*" 3849 | }, 3850 | "platform-dev": [], 3851 | "plugin-api-version": "2.6.0" 3852 | } 3853 | -------------------------------------------------------------------------------- /src/Config.php: -------------------------------------------------------------------------------- 1 | fs = null; 30 | $this->runtime = null; 31 | } 32 | 33 | /** 34 | * @return string 35 | */ 36 | public function getBaseURL(): string 37 | { 38 | return $this->baseURL; 39 | } 40 | 41 | /** 42 | * @param string $baseURL 43 | * @return Config 44 | */ 45 | public function setBaseURL(string $baseURL): Config 46 | { 47 | $this->baseURL = $baseURL; 48 | return $this; 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getSaveDirectory(): string 55 | { 56 | return $this->saveDirectory; 57 | } 58 | 59 | /** 60 | * @param string $saveDirectory 61 | * @return Config 62 | */ 63 | public function setSaveDirectory(string $saveDirectory): Config 64 | { 65 | $this->saveDirectory = $saveDirectory; 66 | return $this; 67 | } 68 | 69 | /** 70 | * @return IFileSystem|null 71 | */ 72 | public function getFS(): IFileSystem|null 73 | { 74 | return $this->fs; 75 | } 76 | 77 | /** 78 | * @param IFileSystem|null $fs 79 | * @return Config 80 | */ 81 | public function setFS(IFileSystem|null $fs): Config 82 | { 83 | $this->fs = $fs; 84 | return $this; 85 | } 86 | 87 | /** 88 | * @return IRuntime|null 89 | */ 90 | public function getRuntime(): IRuntime|null 91 | { 92 | return $this->runtime; 93 | } 94 | 95 | /** 96 | * @param IRuntime|null $runtime 97 | * @return Config 98 | */ 99 | public function setRuntime(IRuntime|null $runtime): Config 100 | { 101 | $this->runtime = $runtime; 102 | return $this; 103 | } 104 | 105 | public function getSitemapIndexURL(): string 106 | { 107 | return $this->sitemapIndexURL; 108 | } 109 | 110 | public function setSitemapIndexURL(string $sitemapIndexURL): Config 111 | { 112 | $this->sitemapIndexURL = $sitemapIndexURL; 113 | return $this; 114 | } 115 | } -------------------------------------------------------------------------------- /src/Extensions/GoogleImageExtension.php: -------------------------------------------------------------------------------- 1 | self::maxImageCount) { 36 | throw new InvalidArgumentException( 37 | sprintf("Too many images for a single URL. Maximum number of images allowed per page is %d, got %d. For more information, see %s", 38 | self::maxImageCount, 39 | count($extFields), 40 | self::maxImageCountRefLink 41 | ) 42 | ); 43 | } 44 | 45 | foreach ($extFields as $extFieldSingle) { 46 | self::writeImageTagSingle($xmlWriter, $extFieldSingle); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * @param XMLWriter $xmlWriter 53 | * @param array $extFields 54 | * @return void 55 | * @throws InvalidArgumentException 56 | */ 57 | private static function writeImageTagSingle(XMLWriter $xmlWriter, array $extFields): void 58 | { 59 | self::validateEntryFields($extFields); 60 | 61 | $xmlWriter->startElement('image:image'); 62 | $xmlWriter->writeElement('image:loc', $extFields['loc']); 63 | 64 | if (isset($extFields['title'])) { 65 | $xmlWriter->writeElement('image:title', htmlentities($extFields['title'], ENT_QUOTES)); 66 | } 67 | 68 | if (isset($extFields['caption'])) { 69 | $xmlWriter->writeElement('image:caption', $extFields['caption']); 70 | } 71 | 72 | if (isset($extFields['geo_location'])) { 73 | $xmlWriter->writeElement('image:geo_location', $extFields['geo_location']); 74 | } 75 | 76 | if (isset($extFields['license'])) { 77 | $xmlWriter->writeElement('image:license', $extFields['license']); 78 | } 79 | 80 | $xmlWriter->endElement(); 81 | } 82 | 83 | /** 84 | * @throws InvalidArgumentException 85 | */ 86 | public static function validateEntryFields($fields): void 87 | { 88 | if (has_string_keys($fields)) { 89 | self::validateSingleEntryFields($fields); 90 | } else { 91 | foreach ($fields as $extFieldSingle) { 92 | self::validateSingleEntryFields($extFieldSingle); 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * @throws InvalidArgumentException 99 | */ 100 | private static function validateSingleEntryFields($fields): void 101 | { 102 | $extFieldNames = array_keys($fields); 103 | 104 | if (count(array_intersect(self::$requiredFields, $extFieldNames)) !== count(self::$requiredFields)) { 105 | throw new InvalidArgumentException( 106 | sprintf("Missing required fields: %s", implode(', ', array_diff(self::$requiredFields, $extFieldNames))) 107 | ); 108 | } 109 | } 110 | } 111 | 112 | /** 113 | * @param array $array 114 | * @return bool 115 | */ 116 | function has_string_keys(array $array): bool 117 | { 118 | return count(array_filter(array_keys($array), 'is_string')) > 0; 119 | } 120 | -------------------------------------------------------------------------------- /src/Extensions/GoogleVideoExtension.php: -------------------------------------------------------------------------------- 1 | startElement('video:video'); 43 | $xmlWriter->writeElement('video:thumbnail_loc', $extFields['thumbnail_loc']); 44 | $xmlWriter->writeElement('video:title', htmlentities($extFields['title'], ENT_QUOTES)); 45 | $xmlWriter->writeElement('video:description', htmlentities($extFields['description'], ENT_QUOTES)); 46 | 47 | if (isset($extFields['content_loc'])) { 48 | $xmlWriter->writeElement('video:content_loc', $extFields['content_loc']); 49 | } 50 | if (isset($extFields['player_loc'])) { 51 | $xmlWriter->writeElement('video:content_loc', $extFields['player_loc']); 52 | } 53 | if (isset($extFields['duration'])) { 54 | $xmlWriter->writeElement('video:duration', $extFields['duration']); 55 | } 56 | if (isset($extFields['expiration_date'])) { 57 | $xmlWriter->writeElement('video:expiration_date', $extFields['expiration_date']); 58 | } 59 | if (isset($extFields['rating'])) { 60 | $xmlWriter->writeElement('video:rating', $extFields['rating']); 61 | } 62 | if (isset($extFields['view_count'])) { 63 | $xmlWriter->writeElement('video:view_count', $extFields['view_count']); 64 | } 65 | if (isset($extFields['publication_date'])) { 66 | $xmlWriter->writeElement('video:publication_date', $extFields['publication_date']); 67 | } 68 | if (isset($extFields['family_friendly'])) { 69 | $xmlWriter->writeElement('video:family_friendly', $extFields['family_friendly']); 70 | } 71 | if (isset($extFields['restriction'])) { 72 | $xmlWriter->startElement('video:restriction'); 73 | if (isset($extFields['restriction']['relationship'])) { 74 | $xmlWriter->writeAttribute('relationship', $extFields['restriction']['relationship']); 75 | } 76 | $xmlWriter->writeRaw($extFields['restriction']['value']); 77 | $xmlWriter->endElement(); 78 | } 79 | if (isset($extFields['platform'])) { 80 | $xmlWriter->startElement('video:platform'); 81 | if (isset($extFields['platform']['relationship'])) { 82 | $xmlWriter->writeAttribute('relationship', $extFields['platform']['relationship']); 83 | } 84 | $xmlWriter->writeRaw($extFields['platform']['value']); 85 | $xmlWriter->endElement(); 86 | } 87 | if (isset($extFields['price'])) { 88 | foreach ($extFields['price'] as $price) { 89 | $xmlWriter->startElement('video:price'); 90 | $xmlWriter->writeAttribute('currency', $price['currency']); 91 | if (isset($price['type'])) { 92 | $xmlWriter->writeAttribute('type', $price['type']); 93 | } 94 | if (isset($price['resolution'])) { 95 | $xmlWriter->writeAttribute('resolution', $price['resolution']); 96 | } 97 | $xmlWriter->writeRaw($price['value']); 98 | $xmlWriter->endElement(); 99 | } 100 | } 101 | if (isset($extFields['requires_subscription'])) { 102 | $xmlWriter->writeElement('video:requires_subscription', $extFields['requires_subscription']); 103 | } 104 | if (isset($extFields['uploader'])) { 105 | $xmlWriter->startElement('video:uploader'); 106 | if (isset($extFields['uploader']['info'])) { 107 | $xmlWriter->writeAttribute('info', $extFields['uploader']['info']); 108 | } 109 | $xmlWriter->writeRaw($extFields['uploader']['value']); 110 | $xmlWriter->endElement(); 111 | } 112 | if (isset($extFields['live'])) { 113 | $xmlWriter->writeElement('video:live', $extFields['live']); 114 | } 115 | if (isset($extFields['tag'])) { 116 | foreach ($extFields['tag'] as $tag) { 117 | $xmlWriter->writeElement('video:tag', $tag); 118 | } 119 | } 120 | if (isset($extFields['category'])) { 121 | $xmlWriter->writeElement('video:category', $extFields['category']); 122 | } 123 | 124 | $xmlWriter->endElement(); 125 | } 126 | 127 | /** 128 | * @throws InvalidArgumentException 129 | */ 130 | public static function validate($loc, $extFields) 131 | { 132 | $extFieldNames = array_keys($extFields); 133 | 134 | if (count(array_intersect(self::$requiredFields, $extFieldNames)) !== count(self::$requiredFields)) { 135 | throw new InvalidArgumentException( 136 | sprintf("Missing required fields: %s", implode(', ', array_diff(self::$requiredFields, $extFieldNames))) 137 | ); 138 | } 139 | if (count(array_intersect(self::$requiredEitherFields, $extFieldNames)) < 1) { 140 | throw new InvalidArgumentException( 141 | sprintf("At least one of the following values are required but missing: %s", 142 | implode(', ', self::$requiredEitherFields) 143 | ) 144 | ); 145 | } 146 | if (mb_strlen($extFields['description']) > 2048) { 147 | throw new InvalidArgumentException('The field description must be less than or equal to a 2048'); 148 | } 149 | if (isset($extFields['content_loc']) && $extFields['content_loc'] === $loc) { 150 | throw new InvalidArgumentException('The field content_loc must not be the same as the URL.'); 151 | } 152 | if (isset($extFields['player_loc']) && $extFields['player_loc'] === $loc) { 153 | throw new InvalidArgumentException('The field player_loc must not be the same as the URL.'); 154 | } 155 | if (isset($extFields['duration']) && !(1 <= $extFields['duration'] && $extFields['duration'] <= 28800)) { 156 | throw new InvalidArgumentException('The duration value should be between 1 and 28800'); 157 | } 158 | if (isset($extFields['expiration_date']) 159 | && DateTime::createFromFormat(DateTime::ATOM, $extFields['expiration_date']) === false 160 | && DateTime::createFromFormat('Y-m-d', $extFields['expiration_date']) === false 161 | ) { 162 | throw new InvalidArgumentException('Invalid expiration_date value. ' . 163 | 'Supported values are complete date (YYYY-MM-DD) or complete date plus hours, ' . 164 | 'minutes and seconds, and timezone (YYYY-MM-DDThh:mm:ss+TZD)'); 165 | } 166 | if (isset($extFields['rating']) && !in_array($extFields['rating'], range(0.0, 5.0, 0.1))) { 167 | throw new InvalidArgumentException( 168 | 'Invalid rating value. ' . 169 | 'Supported values are float numbers in the range 0.0 (low) to 5.0 (high), inclusive.' 170 | ); 171 | } 172 | if (isset($extFields['publication_date']) 173 | && DateTime::createFromFormat(DateTime::ATOM, $extFields['publication_date']) === false 174 | && DateTime::createFromFormat('Y-m-d', $extFields['publication_date']) === false 175 | ) { 176 | throw new InvalidArgumentException('Invalid publication_date value. ' . 177 | 'Supported values are complete date (YYYY-MM-DD) or complete date plus hours, ' . 178 | 'minutes and seconds, and timezone (YYYY-MM-DDThh:mm:ss+TZD)'); 179 | } 180 | if (isset($extFields['family_friendly']) && !in_array($extFields['family_friendly'], ['yes', 'no'])) { 181 | throw new InvalidArgumentException('Invalid family_friendly value. ' . 182 | 'yes (or omitted) if the video can be available with SafeSearch on. ' . 183 | 'no if the video should be available only with SafeSearch off.'); 184 | } 185 | if (isset($extFields['restriction'])) { 186 | if (isset($extFields['restriction']['relationship']) 187 | && !in_array($extFields['restriction']['relationship'], ['allow', 'deny'])) { 188 | throw new InvalidArgumentException('Invalid restriction.relationship value. Allowed values are allow or deny.'); 189 | } 190 | if (!isset($extFields['restriction']['value'])) { // todo: country codes in ISO 3166 format 191 | throw new InvalidArgumentException('Value restriction.value is required'); 192 | } 193 | } 194 | if (isset($extFields['platform'])) { 195 | if (isset($extFields['platform']['relationship']) 196 | && !in_array($extFields['platform']['relationship'], ['allow', 'deny'])) { 197 | throw new InvalidArgumentException('Invalid platform.relationship value. Allowed values are allow or deny.'); 198 | } 199 | if (!isset($extFields['platform']['value'])) { 200 | throw new InvalidArgumentException('Value platform.value is required.'); 201 | } 202 | 203 | $platformValues = explode(' ', $extFields['platform']['value']); 204 | 205 | if (count(array_diff($platformValues, static::$platforms)) > 0) { 206 | throw new InvalidArgumentException( 207 | 'Invalid platform.relationship value. ' . 208 | 'Expecting a list of space-delimited platform types: ' . 209 | implode(', ', self::$platforms) . '.' 210 | ); 211 | } 212 | } 213 | if (isset($extFields['price'])) { 214 | foreach ($extFields['price'] as $price) { 215 | if (!isset($price['currency'])) { 216 | throw new InvalidArgumentException('Value price.currency is required'); 217 | } 218 | if (!isset($price['value'])) { 219 | throw new InvalidArgumentException('Value price.value is required'); 220 | } 221 | if ($price['value'] <= 0 || is_float($price['value']) === false) { 222 | throw new InvalidArgumentException('Value price.value should be a float value more than 0'); 223 | } 224 | if (isset($price['type']) && !in_array($price['type'], ['rent', 'own'])) { 225 | throw new InvalidArgumentException( 226 | 'Invalid price.type value. Allowed values are rent or own.' 227 | ); 228 | } 229 | if (isset($price['resolution']) && !in_array($price['resolution'], ['hd', 'sd'])) { 230 | throw new InvalidArgumentException( 231 | 'Invalid price.resolution value. Allowed values are hd or sd.' 232 | ); 233 | } 234 | } 235 | } 236 | if (isset($extFields['requires_subscription']) && !in_array($extFields['requires_subscription'], ['yes', 'no'])) { 237 | throw new InvalidArgumentException( 238 | 'Invalid requires_subscription value. Allowed values are yes or no.' 239 | ); 240 | } 241 | if (isset($extFields['uploader'])) { 242 | if (mb_strlen($extFields['uploader']['value']) > 255) { 243 | throw new InvalidArgumentException( 244 | 'Value uploader.value is too large, max 255 characters.' 245 | ); 246 | } 247 | if (isset($extFields['uploader']['info'])) { 248 | $locDomain = parse_url($loc, PHP_URL_HOST); 249 | $infoDomain = parse_url($extFields['uploader']['info'], PHP_URL_HOST); 250 | if ($locDomain !== $infoDomain) { 251 | throw new InvalidArgumentException( 252 | 'The uploader.info must be in the same domain as the tag.' 253 | ); 254 | } 255 | } 256 | } 257 | if (isset($extFields['live']) && !in_array($extFields['live'], ['yes', 'no'])) { 258 | throw new InvalidArgumentException( 259 | 'Invalid live value. Allowed values are yes or no.' 260 | ); 261 | } 262 | if (isset($extFields['tag'])) { 263 | if (count($extFields['tag']) > 32) { 264 | throw new InvalidArgumentException( 265 | 'The array tag is too large, max 32 tags.' 266 | ); 267 | } 268 | } 269 | if (isset($extFields['category']) && mb_strlen($extFields['category']) > 256) { 270 | throw new InvalidArgumentException( 271 | 'Value category is too large, max 256 characters.' 272 | ); 273 | } 274 | } 275 | } -------------------------------------------------------------------------------- /src/FileSystem.php: -------------------------------------------------------------------------------- 1 | \n") 210 | private int $sitemapURLCount = 0; 211 | private array $generatedFiles = []; 212 | 213 | /** 214 | * @param IConfig $config Configuration object. 215 | * @throws InvalidArgumentException 216 | */ 217 | public function __construct(IConfig $config) 218 | { 219 | if ($config->getBaseURL() === '') { 220 | throw new InvalidArgumentException('baseURL config parameter is required'); 221 | } 222 | 223 | $this->baseURL = rtrim($config->getBaseURL(), '/'); 224 | $this->sitemapIndexURL = rtrim($config->getBaseURL(), '/'); 225 | 226 | if ($config->getSitemapIndexURL()) { 227 | $this->sitemapIndexURL = rtrim($config->getSitemapIndexURL(), '/'); 228 | } 229 | 230 | $configFS = $config->getFS(); 231 | if ($configFS === null) { 232 | $this->fs = new FileSystem(); 233 | } else { 234 | $this->fs = $configFS; 235 | } 236 | 237 | $configRuntime = $config->getRuntime(); 238 | if ($configRuntime === null) { 239 | $this->runtime = new Runtime(); 240 | } else { 241 | $this->runtime = $configRuntime; 242 | } 243 | 244 | if ($this->runtime->is_writable($config->getSaveDirectory()) === false) { 245 | throw new InvalidArgumentException( 246 | sprintf('the provided basePath (%s) should be a writable directory,', $config->getSaveDirectory()) . 247 | ' please check its existence and permissions' 248 | ); 249 | } 250 | 251 | $this->saveDirectory = $config->getSaveDirectory(); 252 | if (strlen($this->saveDirectory) > 0 && substr($this->saveDirectory, -1) != DIRECTORY_SEPARATOR) { 253 | $this->saveDirectory = $this->saveDirectory . DIRECTORY_SEPARATOR; 254 | } 255 | 256 | $this->xmlWriter = $this->createXmlWriter(); 257 | $this->flushedSitemapFilenameFormat = sprintf("sm-%%d-%d.xml", time()); 258 | } 259 | 260 | private function createXmlWriter(): XMLWriter 261 | { 262 | $w = new XMLWriter(); 263 | $w->openMemory(); 264 | $w->setIndent(true); 265 | return $w; 266 | } 267 | 268 | /** 269 | * @param string $filename 270 | * 271 | * @return SitemapGenerator 272 | * 273 | * @throws InvalidArgumentException 274 | */ 275 | public function setSitemapFilename(string $filename = ''): SitemapGenerator 276 | { 277 | if (strlen($filename) === 0) { 278 | throw new InvalidArgumentException('sitemap filename should not be empty'); 279 | } 280 | if (pathinfo($filename, PATHINFO_EXTENSION) !== 'xml') { 281 | throw new InvalidArgumentException('sitemap filename should have *.xml extension'); 282 | } 283 | $this->sitemapFileName = $filename; 284 | return $this; 285 | } 286 | 287 | /** 288 | * @param string $path 289 | * @return SitemapGenerator 290 | * @throws InvalidArgumentException 291 | */ 292 | public function setSitemapStylesheet(string $path): SitemapGenerator 293 | { 294 | if (strlen($path) === 0) { 295 | throw new InvalidArgumentException('sitemap stylesheet path should not be empty'); 296 | } 297 | $this->sitemapStylesheetLink = $path; 298 | return $this; 299 | } 300 | 301 | /** 302 | * @param string $filename 303 | * 304 | * @return $this 305 | * 306 | * @throws InvalidArgumentException 307 | */ 308 | public function setSitemapIndexFilename(string $filename = ''): SitemapGenerator 309 | { 310 | if (strlen($filename) === 0) { 311 | throw new InvalidArgumentException('filename should not be empty'); 312 | } 313 | $this->sitemapIndexFileName = $filename; 314 | return $this; 315 | } 316 | 317 | /** 318 | * @param string $filename 319 | * @return $this 320 | * @throws InvalidArgumentException 321 | */ 322 | public function setRobotsFileName(string $filename): SitemapGenerator 323 | { 324 | if (strlen($filename) === 0) { 325 | throw new InvalidArgumentException('filename should not be empty'); 326 | } 327 | $this->robotsFileName = $filename; 328 | return $this; 329 | } 330 | 331 | /** 332 | * @param int $value 333 | * @return $this 334 | * @throws OutOfRangeException 335 | */ 336 | public function setMaxURLsPerSitemap(int $value): SitemapGenerator 337 | { 338 | if ($value < 1 || self::MAX_URLS_PER_SITEMAP < $value) { 339 | throw new OutOfRangeException( 340 | sprintf('value %d is out of range 1-%d', $value, self::MAX_URLS_PER_SITEMAP) 341 | ); 342 | } 343 | $this->maxURLsPerSitemap = $value; 344 | return $this; 345 | } 346 | 347 | public function enableCompression(): SitemapGenerator 348 | { 349 | $this->isCompressionEnabled = true; 350 | return $this; 351 | } 352 | 353 | public function disableCompression(): SitemapGenerator 354 | { 355 | $this->isCompressionEnabled = false; 356 | return $this; 357 | } 358 | 359 | public function isCompressionEnabled(): bool 360 | { 361 | return $this->isCompressionEnabled; 362 | } 363 | 364 | /** 365 | * @param string $path 366 | * @param string|null $changeFrequency 367 | * @param float|null $priority 368 | * @param array $extensions 369 | * @return void 370 | * @throws InvalidArgumentException 371 | */ 372 | public function validate( 373 | string $path, 374 | string $changeFrequency = null, 375 | float $priority = null, 376 | array $extensions = []): void 377 | { 378 | if (!(1 <= mb_strlen($path) && mb_strlen($path) <= self::MAX_URL_LEN)) { 379 | throw new InvalidArgumentException( 380 | sprintf("The urlPath argument length must be between 1 and %d.", self::MAX_URL_LEN) 381 | ); 382 | } 383 | if ($changeFrequency !== null && !in_array($changeFrequency, $this->validChangefreqValues)) { 384 | throw new InvalidArgumentException( 385 | 'The change frequency argument should be one of: %s' . implode(',', $this->validChangefreqValues) 386 | ); 387 | } 388 | if ($priority !== null && !in_array($priority, $this->validPriorities)) { 389 | throw new InvalidArgumentException("Priority argument should be a float number in the range [0.0..1.0]"); 390 | } 391 | if (count($extensions) > 0) { 392 | if (isset($extensions['google_video'])) { 393 | GoogleVideoExtension::validate($this->baseURL . $path, $extensions['google_video']); 394 | } 395 | 396 | if (isset($extensions['google_image'])) { 397 | GoogleImageExtension::validateEntryFields($extensions['google_image']); 398 | } 399 | } 400 | } 401 | 402 | /** 403 | * Add url components. 404 | * Instead of storing all urls in the memory, the generator will flush sets of added urls 405 | * to the temporary files created on your disk. 406 | * The file format is 'sm-{index}-{timestamp}.xml' 407 | * @param string $path 408 | * @param DateTime|null $lastModified 409 | * @param string|null $changeFrequency 410 | * @param float|null $priority 411 | * @param array|null $alternates 412 | * @param array $extensions 413 | * @return $this 414 | * @throws OutOfRangeException 415 | * @throws UnexpectedValueException 416 | * @throws InvalidArgumentException 417 | */ 418 | public function addURL( 419 | string $path, 420 | DateTime $lastModified = null, 421 | string $changeFrequency = null, 422 | float $priority = null, 423 | array $alternates = null, 424 | array $extensions = [] 425 | ): SitemapGenerator 426 | { 427 | $this->validate($path, $changeFrequency, $priority, $extensions); 428 | 429 | if ($this->totalURLCount >= self::TOTAL_MAX_URLS) { 430 | throw new OutOfRangeException( 431 | sprintf("Max url limit reached (%d)", self::TOTAL_MAX_URLS) 432 | ); 433 | } 434 | if ($this->isSitemapStarted === false) { 435 | $this->writeSitemapStart(); 436 | } 437 | 438 | $this->writeSitemapUrl($this->baseURL . $path, $lastModified, $changeFrequency, $priority, $alternates, $extensions); 439 | 440 | if ($this->totalURLCount % 1000 === 0 || $this->sitemapURLCount >= $this->maxURLsPerSitemap) { 441 | $this->flushWriter(); 442 | } 443 | 444 | if ($this->sitemapURLCount === $this->maxURLsPerSitemap) { 445 | $this->writeSitemapEnd(); 446 | } 447 | 448 | return $this; 449 | } 450 | 451 | protected function writeSitemapStart(): void 452 | { 453 | $this->xmlWriter->startDocument("1.0", "UTF-8"); 454 | if ($this->sitemapStylesheetLink != "") { 455 | $this->xmlWriter->writePi('xml-stylesheet', 456 | sprintf('type="text/xsl" href="%s"', $this->sitemapStylesheetLink)); 457 | } 458 | $this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this))); 459 | $this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion)); 460 | $this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c'))); 461 | $this->xmlWriter->startElement('urlset'); 462 | $this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); 463 | $this->xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); 464 | $this->xmlWriter->writeAttribute('xmlns:video', 'http://www.google.com/schemas/sitemap-video/1.1'); 465 | $this->xmlWriter->writeAttribute('xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1'); 466 | $this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); 467 | $this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); 468 | $this->isSitemapStarted = true; 469 | } 470 | 471 | /** 472 | * @param string $url 473 | * @return string 474 | * @throws UnexpectedValueException 475 | */ 476 | private function encodeEscapeURL(string $url): string 477 | { 478 | // In-place encoding only on non-ASCII characters, like browsers do. 479 | $encoded = preg_replace_callback('/[^\x20-\x7f]/', function ($match) { 480 | return urlencode($match[0]); 481 | }, $url); 482 | if (!is_string($encoded)) { 483 | throw new UnexpectedValueException('Failed to encode URL'); 484 | } 485 | return htmlspecialchars($encoded, ENT_QUOTES, 'UTF-8'); 486 | } 487 | 488 | /** 489 | * @param string $loc 490 | * @param DateTime|null $lastModified 491 | * @param string|null $changeFrequency 492 | * @param float|null $priority 493 | * @param array|null $alternates 494 | * @param array $extensions 495 | * @throws UnexpectedValueException 496 | */ 497 | private function writeSitemapUrl( 498 | string $loc, 499 | DateTime $lastModified = null, 500 | string $changeFrequency = null, 501 | float $priority = null, 502 | array $alternates = null, 503 | array $extensions = [] 504 | ): void { 505 | $this->xmlWriter->startElement('url'); 506 | $this->xmlWriter->writeElement('loc', $this->encodeEscapeURL($loc)); 507 | 508 | if ($lastModified !== null) { 509 | $this->xmlWriter->writeElement('lastmod', $lastModified->format(DateTime::ATOM)); 510 | } 511 | 512 | if ($changeFrequency !== null) { 513 | $this->xmlWriter->writeElement('changefreq', $changeFrequency); 514 | } 515 | 516 | if ($priority !== null) { 517 | $this->xmlWriter->writeElement('priority', number_format($priority, 1, ".", "")); 518 | } 519 | 520 | if (is_array($alternates) && count($alternates) > 0) { 521 | foreach ($alternates as $alternate) { 522 | if (is_array($alternate) && isset($alternate['hreflang']) && isset($alternate['href'])) { 523 | $this->xmlWriter->startElement('xhtml:link'); 524 | $this->xmlWriter->writeAttribute('rel', 'alternate'); 525 | $this->xmlWriter->writeAttribute('hreflang', $alternate['hreflang']); 526 | $this->xmlWriter->writeAttribute('href', $alternate['href']); 527 | $this->xmlWriter->endElement(); 528 | } 529 | } 530 | } 531 | 532 | foreach ($extensions as $extName => $extFields) { 533 | if ($extName === 'google_video') { 534 | GoogleVideoExtension::writeVideoTag($this->xmlWriter, $loc, $extFields); 535 | } 536 | if ($extName === 'google_image') { 537 | GoogleImageExtension::writeImageTag($this->xmlWriter, $extFields); 538 | } 539 | } 540 | 541 | $this->xmlWriter->endElement(); // url 542 | $this->sitemapURLCount++; 543 | $this->totalURLCount++; 544 | } 545 | 546 | private function flushWriter(): void 547 | { 548 | $targetSitemapFilepath = $this->saveDirectory . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter); 549 | $flushedString = $this->xmlWriter->outputMemory(); 550 | $flushedStringLen = mb_strlen($flushedString); 551 | 552 | if ($flushedStringLen === 0) { 553 | return; 554 | } 555 | 556 | $this->flushedSitemapSize += $flushedStringLen; 557 | 558 | if ($this->flushedSitemapSize > self::MAX_FILE_SIZE - $this->urlsetClosingTagLen) { 559 | $this->writeSitemapEnd(); 560 | $this->writeSitemapStart(); 561 | } 562 | $this->fs->file_put_contents($targetSitemapFilepath, $flushedString, FILE_APPEND); 563 | } 564 | 565 | private function writeSitemapEnd(): void 566 | { 567 | $targetSitemapFilepath = $this->saveDirectory . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter); 568 | $this->xmlWriter->endElement(); // urlset 569 | $this->xmlWriter->endDocument(); 570 | $this->fs->file_put_contents($targetSitemapFilepath, $this->xmlWriter->flush(), FILE_APPEND); 571 | $this->isSitemapStarted = false; 572 | $this->flushedSitemaps[] = $targetSitemapFilepath; 573 | $this->flushedSitemapCounter++; 574 | $this->sitemapURLCount = 0; 575 | $this->flushedSitemapSize = 0; 576 | } 577 | 578 | /** 579 | * Flush all stored urls from memory to the disk and close all necessary tags. 580 | */ 581 | public function flush(): void 582 | { 583 | $this->flushWriter(); 584 | if ($this->isSitemapStarted) { 585 | $this->writeSitemapEnd(); 586 | } 587 | } 588 | 589 | /** 590 | * Move flushed files to their final location. Compress if necessary. 591 | * @throws RuntimeException 592 | */ 593 | public function finalize(): void 594 | { 595 | $this->generatedFiles = []; 596 | 597 | if (count($this->flushedSitemaps) === 1) { 598 | $targetSitemapFilename = $this->sitemapFileName; 599 | if ($this->isCompressionEnabled) { 600 | $targetSitemapFilename .= '.gz'; 601 | } 602 | 603 | $targetSitemapFilepath = $this->saveDirectory . $targetSitemapFilename; 604 | 605 | if ($this->isCompressionEnabled) { 606 | $this->fs->copy($this->flushedSitemaps[0], 'compress.zlib://' . $targetSitemapFilepath); 607 | $this->fs->unlink($this->flushedSitemaps[0]); 608 | } else { 609 | $this->fs->rename($this->flushedSitemaps[0], $targetSitemapFilepath); 610 | } 611 | $this->generatedFiles['sitemaps_location'] = [$targetSitemapFilepath]; 612 | $this->generatedFiles['sitemaps_index_url'] = $this->sitemapIndexURL . '/' . $targetSitemapFilename; 613 | } else if (count($this->flushedSitemaps) > 1) { 614 | $ext = '.' . pathinfo($this->sitemapFileName, PATHINFO_EXTENSION); 615 | $targetExt = $ext; 616 | if ($this->isCompressionEnabled) { 617 | $targetExt .= '.gz'; 618 | } 619 | 620 | $sitemapsUrls = []; 621 | $targetSitemapFilepaths = []; 622 | foreach ($this->flushedSitemaps as $i => $flushedSitemap) { 623 | $targetSitemapFilename = str_replace($ext, ((int)$i + 1) . $targetExt, $this->sitemapFileName); 624 | $targetSitemapFilepath = $this->saveDirectory . $targetSitemapFilename; 625 | 626 | if ($this->isCompressionEnabled) { 627 | $this->fs->copy($flushedSitemap, 'compress.zlib://' . $targetSitemapFilepath); 628 | $this->fs->unlink($flushedSitemap); 629 | } else { 630 | $this->fs->rename($flushedSitemap, $targetSitemapFilepath); 631 | } 632 | $sitemapsUrls[] = htmlspecialchars( 633 | $this->sitemapIndexURL . '/' . $targetSitemapFilename, ENT_QUOTES); 634 | $targetSitemapFilepaths[] = $targetSitemapFilepath; 635 | } 636 | 637 | $targetSitemapIndexFilepath = $this->saveDirectory . $this->sitemapIndexFileName; 638 | $this->createSitemapIndex($sitemapsUrls, $targetSitemapIndexFilepath); 639 | $this->generatedFiles['sitemaps_location'] = $targetSitemapFilepaths; 640 | $this->generatedFiles['sitemaps_index_location'] = $targetSitemapIndexFilepath; 641 | $this->generatedFiles['sitemaps_index_url'] = $this->sitemapIndexURL . '/' . $this->sitemapIndexFileName; 642 | } else { 643 | throw new RuntimeException('failed to finalize, please add urls and flush first'); 644 | } 645 | } 646 | 647 | private function createSitemapIndex(array $sitemapsUrls, string $sitemapIndexFileName): void 648 | { 649 | $this->xmlWriter->flush(); 650 | $this->writeSitemapIndexStart(); 651 | foreach ($sitemapsUrls as $sitemapsUrl) { 652 | $this->writeSitemapIndexUrl($sitemapsUrl); 653 | } 654 | $this->writeSitemapIndexEnd(); 655 | $this->fs->file_put_contents( 656 | $sitemapIndexFileName, 657 | $this->xmlWriter->flush(), 658 | ); 659 | } 660 | 661 | protected function writeSitemapIndexStart(): void 662 | { 663 | $this->xmlWriter->startDocument("1.0", "UTF-8"); 664 | $this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this))); 665 | $this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion)); 666 | $this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c'))); 667 | $this->xmlWriter->startElement('sitemapindex'); 668 | $this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); 669 | $this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); 670 | $this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'); 671 | } 672 | 673 | /** 674 | * @param string $url 675 | * @throws UnexpectedValueException 676 | */ 677 | private function writeSitemapIndexUrl(string $url): void 678 | { 679 | $this->xmlWriter->startElement('sitemap'); 680 | $this->xmlWriter->writeElement('loc', $this->encodeEscapeURL($url)); 681 | $this->xmlWriter->writeElement('lastmod', date('c')); 682 | $this->xmlWriter->endElement(); // sitemap 683 | } 684 | 685 | private function writeSitemapIndexEnd(): void 686 | { 687 | $this->xmlWriter->endElement(); // sitemapindex 688 | $this->xmlWriter->endDocument(); 689 | } 690 | 691 | /** 692 | * @return array Array of previously generated files 693 | */ 694 | public function getGeneratedFiles(): array 695 | { 696 | return $this->generatedFiles; 697 | } 698 | 699 | /** 700 | * Will inform search engines about newly created sitemaps. 701 | * Google and Yandex will be notified. 702 | * @return array of messages and http codes from each search engine 703 | * @access public 704 | * @throws BadMethodCallException 705 | */ 706 | public function submitSitemap(): array 707 | { 708 | if (count($this->generatedFiles) === 0) { 709 | throw new BadMethodCallException("To update robots.txt, call finalize() first."); 710 | } 711 | if (!$this->runtime->extension_loaded('curl')) { 712 | throw new BadMethodCallException("curl extension is needed to do submission."); 713 | } 714 | $searchEngines = $this->searchEngines; 715 | $result = []; 716 | for ($i = 0; $i < count($searchEngines); $i++) { 717 | $submitUrl = $searchEngines[$i] . htmlspecialchars($this->generatedFiles['sitemaps_index_url'], ENT_QUOTES); 718 | $curlResource = $this->runtime->curl_init($submitUrl); 719 | if (is_bool($curlResource) && !$curlResource) { 720 | throw new RuntimeException("failed to execute curl_init for url " . $submitUrl); 721 | } 722 | if (!$this->runtime->curl_setopt($curlResource, CURLOPT_RETURNTRANSFER, true)) { 723 | throw new RuntimeException( 724 | "failed to set curl option CURLOPT_RETURNTRANSFER to true, error: " 725 | . $this->runtime->curl_error($curlResource) 726 | ); 727 | } 728 | $responseContent = $this->runtime->curl_exec($curlResource); 729 | if (is_bool($responseContent) && !$responseContent) { 730 | throw new RuntimeException( 731 | "failed to run curl_exec, error: " . $this->runtime->curl_error($curlResource) 732 | ); 733 | } 734 | $response = $this->runtime->curl_getinfo($curlResource); 735 | $submitSiteShort = array_reverse(explode(".", parse_url($searchEngines[$i], PHP_URL_HOST))); 736 | $result[] = [ 737 | "site" => $submitSiteShort[1] . "." . $submitSiteShort[0], 738 | "fullsite" => $submitUrl, 739 | "http_code" => $response['http_code'], 740 | "message" => str_replace("\n", " ", strip_tags($responseContent)), 741 | ]; 742 | } 743 | return $result; 744 | } 745 | 746 | /** 747 | * Adds sitemap url to robots.txt file located in basePath. 748 | * If robots.txt file exists, 749 | * the function will append sitemap url to file. 750 | * If robots.txt does not exist, 751 | * the function will create new robots.txt file with sample content and sitemap url. 752 | * @access public 753 | * @throws BadMethodCallException 754 | * @throws RuntimeException 755 | */ 756 | public function updateRobots(): SitemapGenerator 757 | { 758 | if (count($this->generatedFiles) === 0) { 759 | throw new BadMethodCallException("To update robots.txt, call finalize() first."); 760 | } 761 | 762 | $robotsFilePath = $this->saveDirectory . $this->robotsFileName; 763 | 764 | $robotsFileContent = $this->createNewRobotsContentFromFile($robotsFilePath); 765 | 766 | $this->fs->file_put_contents($robotsFilePath, $robotsFileContent); 767 | 768 | return $this; 769 | } 770 | 771 | /** 772 | * @param string $filepath 773 | * @return string 774 | * @throws RuntimeException 775 | */ 776 | private function createNewRobotsContentFromFile(string $filepath): string 777 | { 778 | if ($this->fs->file_exists($filepath)) { 779 | $existingContent = $this->fs->file_get_contents($filepath); 780 | // if $existingContent is bool and false, it means that file exists but is not readable 781 | if (is_bool($existingContent) && !$existingContent) { 782 | throw new RuntimeException("Failed to read existing robots.txt file: $filepath"); 783 | } 784 | if (is_string($existingContent)) { 785 | $contentLines = explode(PHP_EOL, $existingContent); 786 | } else { 787 | $contentLines = []; 788 | } 789 | $newContent = ""; 790 | foreach ($contentLines as $key => $line) { 791 | if (str_starts_with($line, 'Sitemap:')) { 792 | unset($contentLines[$key]); 793 | } else { 794 | $newContent .= $line . PHP_EOL; 795 | } 796 | } 797 | } else { 798 | $newContent = $this->getSampleRobotsContent(); 799 | } 800 | 801 | $newContent .= "Sitemap: {$this->generatedFiles['sitemaps_index_url']}"; 802 | 803 | return $newContent; 804 | } 805 | 806 | /** 807 | * @return string 808 | * @access private 809 | */ 810 | private function getSampleRobotsContent(): string 811 | { 812 | return implode(PHP_EOL, $this->sampleRobotsLines) . PHP_EOL; 813 | } 814 | } 815 | --------------------------------------------------------------------------------